Skip to content

Add zend_string_init_fast and related macros to speed up string creation #5684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 44 additions & 24 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,20 @@ END_EXTERN_C()
ZVAL_PSTRINGL(z, "", 0); \
} while (0)

#define ZVAL_ONE_CHAR_STRING(z, c) do { \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about using ZVAL_ONE_CHAR_INTERNED_STR? So that we wouldn't lose the information that it creates an interned string?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about using ZVAL_ONE_CHAR_INTERNED_STR? So that we wouldn't lose the information that it creates an interned string?

but API named *_STR usually takes zend_string * as a parameter and ZVAL_ONE_CHAR_INTERNED_STRING is too long...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Length of a macro name is not a valid argument IMHO, readability is more important than just how many characters less you will type once.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Length of a macro name is not a valid argument IMHO, readability is more important than just how many characters less you will type once.

You're right, I prefer ZVAL_ONE_CHAR_INTERNED_STRING

Copy link
Member

@kocsismate kocsismate Jun 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@twose Using str vs string has a semantic difference. Please see this here: #5647 (comment) Initially, I also argued against using abbreviations, but "unfortunately" they make sense in this case. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kocsismate I'm a little confused now, this macro accepts a parameter of type char, not zend_string *, so we named it *_ONE_CHAR_INTERNED_STRING instead of ONE_CHAR_INTERNED_STR, is that right?

Copy link
Member

@nikic nikic Jun 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using just ZVAL_CHAR(zv, c), RETVAL_CHAR(c), RETURN_CHAR(c) ... :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using just ZVAL_CHAR(zv, c) ... :)

I'm in favor of your proposal, the reason I didn’t do this at first was that there is no char type in PHP

char _c = (c); \
ZVAL_INTERNED_STR(z, ZSTR_CHAR((zend_uchar) _c)); \
} while (0)

#define ZVAL_STRINGL_FAST(z, s, l) do { \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a comment to clarify when the fast implementation should be used? I believe there are some people (including me) who would appreciate a little bit more information about its applicability/use-cases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kocsismate
sorry for my poor English...😢
you can add comments if possible...

ZVAL_STR(z, zend_string_init_fast(s, l)); \
} while (0)

#define ZVAL_STRING_FAST(z, s) do { \
const char *_s = (s); \
ZVAL_STRINGL_FAST(z, _s, strlen(_s)); \
} while (0)

#define ZVAL_ZVAL(z, zv, copy, dtor) do { \
zval *__z = (z); \
zval *__zv = (zv); \
Expand All @@ -654,46 +668,52 @@ END_EXTERN_C()
} while (0)

#define RETVAL_BOOL(b) ZVAL_BOOL(return_value, b)
#define RETVAL_NULL() ZVAL_NULL(return_value)
#define RETVAL_LONG(l) ZVAL_LONG(return_value, l)
#define RETVAL_DOUBLE(d) ZVAL_DOUBLE(return_value, d)
#define RETVAL_STR(s) ZVAL_STR(return_value, s)
#define RETVAL_INTERNED_STR(s) ZVAL_INTERNED_STR(return_value, s)
#define RETVAL_NEW_STR(s) ZVAL_NEW_STR(return_value, s)
#define RETVAL_STR_COPY(s) ZVAL_STR_COPY(return_value, s)
#define RETVAL_STRING(s) ZVAL_STRING(return_value, s)
#define RETVAL_STRINGL(s, l) ZVAL_STRINGL(return_value, s, l)
#define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value)
#define RETVAL_RES(r) ZVAL_RES(return_value, r)
#define RETVAL_ARR(r) ZVAL_ARR(return_value, r)
#define RETVAL_NULL() ZVAL_NULL(return_value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously I also tried to do something similar, but it turned out that tabs should only be used for indentation at the beginning of the line. Otherwise, spaces are preferred.

#define RETVAL_LONG(l) ZVAL_LONG(return_value, l)
#define RETVAL_DOUBLE(d) ZVAL_DOUBLE(return_value, d)
#define RETVAL_STR(s) ZVAL_STR(return_value, s)
#define RETVAL_INTERNED_STR(s) ZVAL_INTERNED_STR(return_value, s)
#define RETVAL_NEW_STR(s) ZVAL_NEW_STR(return_value, s)
#define RETVAL_STR_COPY(s) ZVAL_STR_COPY(return_value, s)
#define RETVAL_STRING(s) ZVAL_STRING(return_value, s)
#define RETVAL_STRINGL(s, l) ZVAL_STRINGL(return_value, s, l)
#define RETVAL_STRING_FAST(s) ZVAL_STRING_FAST(return_value, s)
#define RETVAL_STRINGL_FAST(s, l) ZVAL_STRINGL_FAST(return_value, s, l)
#define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value)
#define RETVAL_ONE_CHAR_STRING(c) ZVAL_ONE_CHAR_STRING(return_value, c)
#define RETVAL_RES(r) ZVAL_RES(return_value, r)
#define RETVAL_ARR(r) ZVAL_ARR(return_value, r)
#define RETVAL_EMPTY_ARRAY() ZVAL_EMPTY_ARRAY(return_value)
#define RETVAL_OBJ(r) ZVAL_OBJ(return_value, r)
#define RETVAL_OBJ(r) ZVAL_OBJ(return_value, r)
#define RETVAL_COPY(zv) ZVAL_COPY(return_value, zv)
#define RETVAL_COPY_VALUE(zv) ZVAL_COPY_VALUE(return_value, zv)
#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor)
#define RETVAL_FALSE ZVAL_FALSE(return_value)
#define RETVAL_TRUE ZVAL_TRUE(return_value)
#define RETVAL_FALSE ZVAL_FALSE(return_value)
#define RETVAL_TRUE ZVAL_TRUE(return_value)

#define RETURN_BOOL(b) do { RETVAL_BOOL(b); return; } while (0)
#define RETURN_NULL() do { RETVAL_NULL(); return;} while (0)
#define RETURN_LONG(l) do { RETVAL_LONG(l); return; } while (0)
#define RETURN_DOUBLE(d) do { RETVAL_DOUBLE(d); return; } while (0)
#define RETURN_BOOL(b) do { RETVAL_BOOL(b); return; } while (0)
#define RETURN_NULL() do { RETVAL_NULL(); return;} while (0)
#define RETURN_LONG(l) do { RETVAL_LONG(l); return; } while (0)
#define RETURN_DOUBLE(d) do { RETVAL_DOUBLE(d); return; } while (0)
#define RETURN_STR(s) do { RETVAL_STR(s); return; } while (0)
#define RETURN_INTERNED_STR(s) do { RETVAL_INTERNED_STR(s); return; } while (0)
#define RETURN_NEW_STR(s) do { RETVAL_NEW_STR(s); return; } while (0)
#define RETURN_STR_COPY(s) do { RETVAL_STR_COPY(s); return; } while (0)
#define RETURN_STRING(s) do { RETVAL_STRING(s); return; } while (0)
#define RETURN_STRINGL(s, l) do { RETVAL_STRINGL(s, l); return; } while (0)
#define RETURN_STRING_FAST(s) do { RETVAL_STRING_FAST(s); return; } while (0)
#define RETURN_STRINGL_FAST(s, l) do { RETVAL_STRINGL_FAST(s, l); return; } while (0)
#define RETURN_EMPTY_STRING() do { RETVAL_EMPTY_STRING(); return; } while (0)
#define RETURN_RES(r) do { RETVAL_RES(r); return; } while (0)
#define RETURN_ARR(r) do { RETVAL_ARR(r); return; } while (0)
#define RETURN_ONE_CHAR_STRING(c) do { RETVAL_ONE_CHAR_STRING(c); return; } while (0)
#define RETURN_RES(r) do { RETVAL_RES(r); return; } while (0)
#define RETURN_ARR(r) do { RETVAL_ARR(r); return; } while (0)
#define RETURN_EMPTY_ARRAY() do { RETVAL_EMPTY_ARRAY(); return; } while (0)
#define RETURN_OBJ(r) do { RETVAL_OBJ(r); return; } while (0)
#define RETURN_OBJ(r) do { RETVAL_OBJ(r); return; } while (0)
#define RETURN_COPY(zv) do { RETVAL_COPY(zv); return; } while (0)
#define RETURN_COPY_VALUE(zv) do { RETVAL_COPY_VALUE(zv); return; } while (0)
#define RETURN_ZVAL(zv, copy, dtor) do { RETVAL_ZVAL(zv, copy, dtor); return; } while (0)
#define RETURN_FALSE do { RETVAL_FALSE; return; } while (0)
#define RETURN_TRUE do { RETVAL_TRUE; return; } while (0)
#define RETURN_FALSE do { RETVAL_FALSE; return; } while (0)
#define RETURN_TRUE do { RETVAL_TRUE; return; } while (0)
#define RETURN_THROWS() do { ZEND_ASSERT(EG(exception)); (void) return_value; return; } while (0)

#define HASH_OF(p) (Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties(Z_OBJ_P(p)) : NULL)))
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3525,7 +3525,7 @@ int zend_compile_func_chr(znode *result, zend_ast_list *args) /* {{{ */
zend_long c = Z_LVAL_P(zend_ast_get_zval(args->child[0])) & 0xff;

result->op_type = IS_CONST;
ZVAL_INTERNED_STR(&result->u.constant, ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(&result->u.constant, c);
return SUCCESS;
} else {
return FAILURE;
Expand Down Expand Up @@ -9383,7 +9383,7 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
return;
}
c = (zend_uchar) Z_STRVAL_P(container)[offset];
ZVAL_INTERNED_STR(&result, ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(&result, c);
} else if (Z_TYPE_P(container) <= IS_FALSE) {
ZVAL_NULL(&result);
} else {
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,

if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
/* Return the new character */
ZVAL_INTERNED_STR(EX_VAR(opline->result.var), ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(EX_VAR(opline->result.var), c);
}
}

Expand Down Expand Up @@ -2332,7 +2332,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
? (zend_long)Z_STRLEN_P(container) + offset : offset;
c = (zend_uchar)Z_STRVAL_P(container)[real_offset];

ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(result, c);
}
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
if (ZEND_CONST_COND(dim_type == IS_CV, 1) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
Expand Down
12 changes: 6 additions & 6 deletions Zend/zend_operators.c
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op) /* {{{ */
break;
}
case IS_TRUE:
ZVAL_INTERNED_STR(op, ZSTR_CHAR('1'));
ZVAL_ONE_CHAR_STRING(op, '1');
break;
case IS_STRING:
break;
Expand Down Expand Up @@ -1449,7 +1449,7 @@ ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{

if (Z_STRLEN_P(op1) == 1) {
zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1);
ZVAL_INTERNED_STR(result, ZSTR_CHAR(not));
ZVAL_ONE_CHAR_STRING(result, not);
} else {
ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
for (i = 0; i < Z_STRLEN_P(op1); i++) {
Expand Down Expand Up @@ -1497,7 +1497,7 @@ ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op
if (result==op1) {
zval_ptr_dtor_str(result);
}
ZVAL_INTERNED_STR(result, ZSTR_CHAR(or));
ZVAL_ONE_CHAR_STRING(result, or);
return SUCCESS;
}
longer = op1;
Expand Down Expand Up @@ -1579,7 +1579,7 @@ ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *o
if (result==op1) {
zval_ptr_dtor_str(result);
}
ZVAL_INTERNED_STR(result, ZSTR_CHAR(and));
ZVAL_ONE_CHAR_STRING(result, and);
return SUCCESS;
}
longer = op1;
Expand Down Expand Up @@ -1661,7 +1661,7 @@ ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *o
if (result==op1) {
zval_ptr_dtor_str(result);
}
ZVAL_INTERNED_STR(result, ZSTR_CHAR(xor));
ZVAL_ONE_CHAR_STRING(result, xor);
return SUCCESS;
}
longer = op1;
Expand Down Expand Up @@ -2244,7 +2244,7 @@ static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */

if (Z_STRLEN_P(str) == 0) {
zval_ptr_dtor_str(str);
ZVAL_INTERNED_STR(str, ZSTR_CHAR('1'));
ZVAL_ONE_CHAR_STRING(str, '1');
return;
}

Expand Down
11 changes: 11 additions & 0 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ static zend_always_inline zend_string *zend_string_init(const char *str, size_t
return ret;
}

static zend_always_inline zend_string *zend_string_init_fast(const char *str, size_t len)
{
if (len > 1) {
return zend_string_init(str, len, 0);
} else if (len == 0) {
return zend_empty_string;
} else /* if (len == 1) */ {
return ZSTR_CHAR((zend_uchar) *str);
}
}

static zend_always_inline zend_string *zend_string_copy(zend_string *s)
{
if (!ZSTR_IS_INTERNED(s)) {
Expand Down
4 changes: 2 additions & 2 deletions ext/ffi/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, voi
ZVAL_BOOL(rv, *(uint8_t*)ptr);
return;
case ZEND_FFI_TYPE_CHAR:
ZVAL_INTERNED_STR(rv, ZSTR_CHAR(*(unsigned char*)ptr));
ZVAL_ONE_CHAR_STRING(rv, *(char*)ptr);
return;
case ZEND_FFI_TYPE_ENUM:
kind = type->enumeration.kind;
Expand Down Expand Up @@ -1077,7 +1077,7 @@ static int zend_ffi_cdata_cast_object(zend_object *readobj, zval *writeobj, int
ZVAL_BOOL(writeobj, *(uint8_t*)ptr);
break;
case ZEND_FFI_TYPE_CHAR:
ZVAL_INTERNED_STR(writeobj, ZSTR_CHAR(*(unsigned char*)ptr));
ZVAL_ONE_CHAR_STRING(writeobj, *(char*)ptr);
return SUCCESS;
case ZEND_FFI_TYPE_ENUM:
kind = ctype->enumeration.kind;
Expand Down
6 changes: 1 addition & 5 deletions ext/mysqlnd/mysqlnd_wireprotocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1666,12 +1666,8 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
} else if (Z_TYPE_P(current_field) == IS_STRING) {
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
}
} else if (len == 0) {
ZVAL_EMPTY_STRING(current_field);
} else if (len == 1) {
ZVAL_INTERNED_STR(current_field, ZSTR_CHAR((zend_uchar)*(char *)p));
} else {
ZVAL_STRINGL(current_field, (char *)p, len);
ZVAL_STRINGL_FAST(current_field, (char *)p, len);
}
p += len;
}
Expand Down
2 changes: 1 addition & 1 deletion ext/opcache/Optimizer/sccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ static inline int ct_eval_func_call(
}

c = Z_LVAL_P(args[0]) & 0xff;
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(result, c);
return SUCCESS;
} else if (zend_string_equals_literal(name, "count")) {
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
Expand Down
6 changes: 3 additions & 3 deletions ext/opcache/jit/zend_jit_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_str_r_helper(zval *container, zval
real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
? (zend_long)Z_STRLEN_P(container) + offset : offset;
c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(result, c);
}
}

Expand Down Expand Up @@ -685,7 +685,7 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zval *container, zval
real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
? (zend_long)Z_STRLEN_P(container) + offset : offset;
c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(result, c);
}
}

Expand Down Expand Up @@ -952,7 +952,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,

if (result) {
/* Return the new character */
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
ZVAL_ONE_CHAR_STRING(result, c);
}
}

Expand Down
8 changes: 1 addition & 7 deletions ext/pcre/php_pcre.c
Original file line number Diff line number Diff line change
Expand Up @@ -966,13 +966,7 @@ static void init_unmatched_empty_pair() {

static zend_always_inline void populate_match_value_str(
zval *val, const char *subject, PCRE2_SIZE start_offset, PCRE2_SIZE end_offset) {
if (start_offset == end_offset) {
ZVAL_EMPTY_STRING(val);
} else if (start_offset + 1 == end_offset) {
ZVAL_INTERNED_STR(val, ZSTR_CHAR((unsigned char) subject[start_offset]));
} else {
ZVAL_STRINGL(val, subject + start_offset, end_offset - start_offset);
}
ZVAL_STRINGL_FAST(val, subject + start_offset, end_offset - start_offset);
}

static inline void populate_match_value(
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -2739,7 +2739,7 @@ PHP_FUNCTION(range)
} ZEND_HASH_FILL_END();
} else {
array_init(return_value);
ZVAL_INTERNED_STR(&tmp, ZSTR_CHAR(low));
ZVAL_ONE_CHAR_STRING(&tmp, low);
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
} else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
Expand Down
42 changes: 19 additions & 23 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -2041,6 +2041,21 @@ PHP_FUNCTION(highlight_string)
}
/* }}} */

#define INI_RETVAL_STR(val) do { \
/* copy to return value here, because alter might free it! */ \
if (ZSTR_IS_INTERNED(val)) { \
RETVAL_INTERNED_STR(val); \
} else if (ZSTR_LEN(val) == 0) { \
RETVAL_EMPTY_STRING(); \
} else if (ZSTR_LEN(val) == 1) { \
RETVAL_INTERNED_STR(ZSTR_CHAR((zend_uchar)ZSTR_VAL(val)[0])); \
} else if (!(GC_FLAGS(val) & GC_PERSISTENT)) { \
ZVAL_NEW_STR(return_value, zend_string_copy(val)); \
} else { \
ZVAL_NEW_STR(return_value, zend_string_init(ZSTR_VAL(val), ZSTR_LEN(val), 0)); \
} \
} while (0)

/* {{{ proto string|false ini_get(string varname)
Get a configuration option */
PHP_FUNCTION(ini_get)
Expand All @@ -2057,17 +2072,7 @@ PHP_FUNCTION(ini_get)
RETURN_FALSE;
}

if (ZSTR_IS_INTERNED(val)) {
RETVAL_INTERNED_STR(val);
} else if (ZSTR_LEN(val) == 0) {
RETVAL_EMPTY_STRING();
} else if (ZSTR_LEN(val) == 1) {
RETVAL_INTERNED_STR(ZSTR_CHAR((zend_uchar)ZSTR_VAL(val)[0]));
} else if (!(GC_FLAGS(val) & GC_PERSISTENT)) {
ZVAL_NEW_STR(return_value, zend_string_copy(val));
} else {
ZVAL_NEW_STR(return_value, zend_string_init(ZSTR_VAL(val), ZSTR_LEN(val), 0));
}
INI_RETVAL_STR(val);
}
/* }}} */

Expand Down Expand Up @@ -2168,19 +2173,8 @@ PHP_FUNCTION(ini_set)

val = zend_ini_get_value(varname);

/* copy to return here, because alter might free it! */
if (val) {
if (ZSTR_IS_INTERNED(val)) {
RETVAL_INTERNED_STR(val);
} else if (ZSTR_LEN(val) == 0) {
RETVAL_EMPTY_STRING();
} else if (ZSTR_LEN(val) == 1) {
RETVAL_INTERNED_STR(ZSTR_CHAR((zend_uchar)ZSTR_VAL(val)[0]));
} else if (!(GC_FLAGS(val) & GC_PERSISTENT)) {
ZVAL_NEW_STR(return_value, zend_string_copy(val));
} else {
ZVAL_NEW_STR(return_value, zend_string_init(ZSTR_VAL(val), ZSTR_LEN(val), 0));
}
INI_RETVAL_STR(val);
} else {
RETVAL_FALSE;
}
Expand Down Expand Up @@ -2209,6 +2203,8 @@ PHP_FUNCTION(ini_set)
}
/* }}} */

#undef INI_RETVAL_STR

/* {{{ proto void ini_restore(string varname)
Restore the value of a configuration option specified by varname */
PHP_FUNCTION(ini_restore)
Expand Down
Loading