From df7ca608ce62dba76ab7c766bede2a3f9b68755e Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 25 Apr 2014 00:56:15 +0400 Subject: [PATCH] Optimized constant lookup --- Zend/zend_ast.c | 2 +- Zend/zend_builtin_functions.c | 11 ++- Zend/zend_constants.c | 118 ++++++++++++++++++-------------- Zend/zend_constants.h | 5 +- Zend/zend_execute_API.c | 44 ++++++++---- Zend/zend_ini_parser.y | 21 ++++-- ext/opcache/Optimizer/pass1_5.c | 6 +- ext/opcache/zend_persist.c | 6 +- ext/standard/basic_functions.c | 17 +++-- 9 files changed, 136 insertions(+), 94 deletions(-) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index d0cd7da102..5babcffe48 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -223,7 +223,7 @@ ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *s break; case ZEND_CONST: ZVAL_DUP(result, &ast->u.val); - if (Z_CONSTANT_P(result)) { + if (Z_OPT_CONSTANT_P(result)) { zval_update_constant_ex(result, (void *) 1, scope TSRMLS_CC); } break; diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 1d066deb41..32bd68e58e 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -729,16 +729,13 @@ repeat: Check whether a constant exists */ ZEND_FUNCTION(defined) { - char *name; - int name_len; - zval c; + zend_string *name; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &name) == FAILURE) { return; } - if (zend_get_constant_ex(name, name_len, &c, NULL, ZEND_FETCH_CLASS_SILENT TSRMLS_CC)) { - zval_dtor(&c); + if (zend_get_constant_ex(name, NULL, ZEND_FETCH_CLASS_SILENT TSRMLS_CC)) { RETURN_TRUE; } else { RETURN_FALSE; @@ -927,7 +924,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value /* this is necessary to make it able to work with default array * properties, returned to user */ - if (Z_CONSTANT(prop_copy)) { + if (Z_OPT_CONSTANT(prop_copy)) { zval_update_constant(&prop_copy, 0 TSRMLS_CC); } diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 72fa9cb177..fd98a92c4e 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -278,12 +278,14 @@ static zend_constant *zend_get_special_constant(const char *name, uint name_len } -ZEND_API int zend_get_constant(const char *name, uint name_len, zval *result TSRMLS_DC) +ZEND_API zval *zend_get_constant_str(const char *name, uint name_len TSRMLS_DC) { zend_constant *c; + ALLOCA_FLAG(use_heap) if ((c = zend_hash_str_find_ptr(EG(zend_constants), name, name_len)) == NULL) { - char *lcname = zend_str_tolower_dup(name, name_len); + char *lcname = do_alloca(name_len + 1, use_heap); + zend_str_tolower_copy(lcname, name, name_len); if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, name_len)) != NULL) { if (c->flags & CONST_CS) { c = NULL; @@ -291,29 +293,47 @@ ZEND_API int zend_get_constant(const char *name, uint name_len, zval *result TSR } else { c = zend_get_special_constant(name, name_len TSRMLS_CC); } - efree(lcname); + free_alloca(lcname, use_heap); } - if (c) { - ZVAL_DUP(result, &c->value); - return 1; + return c ? &c->value : NULL; +} + +ZEND_API zval *zend_get_constant(zend_string *name TSRMLS_DC) +{ + zend_constant *c; + ALLOCA_FLAG(use_heap) + + if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) { + char *lcname = do_alloca(name->len + 1, use_heap); + zend_str_tolower_copy(lcname, name->val, name->len); + if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, name->len)) != NULL) { + if (c->flags & CONST_CS) { + c = NULL; + } + } else { + c = zend_get_special_constant(name->val, name->len TSRMLS_CC); + } + free_alloca(lcname, use_heap); } - return 0; + return c ? &c->value : NULL; } -ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, zend_class_entry *scope, ulong flags TSRMLS_DC) +ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, ulong flags TSRMLS_DC) { zend_constant *c; - int retval = 1; const char *colon; zend_class_entry *ce = NULL; zend_string *class_name; + const char *name = cname->val; + uint name_len = cname->len; /* Skip leading \\ */ if (name[0] == '\\') { name += 1; name_len -= 1; + cname = NULL; } if ((colon = zend_memrchr(name, ':', name_len)) && @@ -321,12 +341,13 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, int class_name_len = colon - name - 1; int const_name_len = name_len - class_name_len - 2; zend_string *constant_name = STR_INIT(colon + 1, const_name_len, 0); - zend_string *lcname; + char *lcname; zval *ret_constant = NULL; + ALLOCA_FLAG(use_heap) class_name = STR_INIT(name, class_name_len, 0); - lcname = STR_ALLOC(class_name_len, 0); - zend_str_tolower_copy(lcname->val, name, class_name_len); + lcname = do_alloca(class_name_len + 1, use_heap); + zend_str_tolower_copy(lcname, name, class_name_len); if (!scope) { if (EG(in_execution)) { scope = EG(scope); @@ -336,16 +357,14 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, } if (class_name_len == sizeof("self")-1 && - !memcmp(lcname->val, "self", sizeof("self")-1)) { + !memcmp(lcname, "self", sizeof("self")-1)) { if (scope) { ce = scope; } else { zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); - retval = 0; } - STR_FREE(lcname); } else if (class_name_len == sizeof("parent")-1 && - !memcmp(lcname->val, "parent", sizeof("parent")-1)) { + !memcmp(lcname, "parent", sizeof("parent")-1)) { if (!scope) { zend_error(E_ERROR, "Cannot access parent:: when no class scope is active"); } else if (!scope->parent) { @@ -353,38 +372,33 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, } else { ce = scope->parent; } - STR_FREE(lcname); } else if (class_name_len == sizeof("static")-1 && - !memcmp(lcname->val, "static", sizeof("static")-1)) { + !memcmp(lcname, "static", sizeof("static")-1)) { if (EG(called_scope)) { ce = EG(called_scope); } else { zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); } - STR_FREE(lcname); } else { - STR_FREE(lcname); ce = zend_fetch_class(class_name, flags TSRMLS_CC); } - if (retval && ce) { - if ((ret_constant = zend_hash_find(&ce->constants_table, constant_name)) == NULL) { - retval = 0; + free_alloca(lcname, use_heap); + if (ce) { + ret_constant = zend_hash_find(&ce->constants_table, constant_name); + if (ret_constant == NULL) { if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) { zend_error(E_ERROR, "Undefined class constant '%s::%s'", class_name->val, constant_name->val); } } else if (Z_ISREF_P(ret_constant)) { ret_constant = Z_REFVAL_P(ret_constant); } - } else if (!ce) { - retval = 0; } STR_FREE(class_name); STR_FREE(constant_name); - if (retval) { + if (ret_constant && Z_CONSTANT_P(ret_constant)) { zval_update_constant_ex(ret_constant, (void*)1, ce TSRMLS_CC); - ZVAL_DUP(result, ret_constant); } - return retval; + return ret_constant; } /* non-class constant */ @@ -393,45 +407,43 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, int prefix_len = colon - name; int const_name_len = name_len - prefix_len - 1; const char *constant_name = colon + 1; - zend_string *lcname; - int found_const = 0; + char *lcname; + int lcname_len; + ALLOCA_FLAG(use_heap) - lcname = STR_ALLOC(prefix_len + 1 + const_name_len, 0); - zend_str_tolower_copy(lcname->val, name, prefix_len); + lcname_len = prefix_len + 1 + const_name_len; + lcname = do_alloca(lcname_len + 1, use_heap); + zend_str_tolower_copy(lcname, name, prefix_len); /* Check for namespace constant */ - lcname->val[prefix_len] = '\\'; - memcpy(lcname->val + prefix_len + 1, constant_name, const_name_len + 1); + lcname[prefix_len] = '\\'; + memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1); - if ((c = zend_hash_find_ptr(EG(zend_constants), lcname)) != NULL) { - found_const = 1; - } else { + if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) == NULL) { /* try lowercase */ - zend_str_tolower(lcname->val + prefix_len + 1, const_name_len); - STR_FORGET_HASH_VAL(lcname); - if ((c = zend_hash_find_ptr(EG(zend_constants), lcname)) != NULL) { - if ((c->flags & CONST_CS) == 0) { - found_const = 1; + zend_str_tolower(lcname + prefix_len + 1, const_name_len); + if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) != NULL) { + if ((c->flags & CONST_CS) != 0) { + c = NULL; } } } - STR_FREE(lcname); - if (found_const) { - ZVAL_COPY_VALUE(result, &c->value); - zval_update_constant_ex(result, (void*)1, NULL TSRMLS_CC); - zval_copy_ctor(result); - return 1; + free_alloca(lcname, use_heap); + if (c) { + return &c->value; } /* name requires runtime resolution, need to check non-namespaced name */ if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) { - name = constant_name; - name_len = const_name_len; - return zend_get_constant(name, name_len, result TSRMLS_CC); + return zend_get_constant_str(constant_name, const_name_len TSRMLS_CC); } - return 0; + return NULL; } - return zend_get_constant(name, name_len, result TSRMLS_CC); + if (cname) { + return zend_get_constant(cname TSRMLS_CC); + } else { + return zend_get_constant_str(name, name_len TSRMLS_CC); + } } zend_constant *zend_quick_get_constant(const zval *key, ulong flags TSRMLS_DC) diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index df7f27cf8f..09a5dac63d 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -65,8 +65,9 @@ int zend_startup_constants(TSRMLS_D); int zend_shutdown_constants(TSRMLS_D); void zend_register_standard_constants(TSRMLS_D); void clean_non_persistent_constants(TSRMLS_D); -ZEND_API int zend_get_constant(const char *name, uint name_len, zval *result TSRMLS_DC); -ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, zend_class_entry *scope, ulong flags TSRMLS_DC); +ZEND_API zval *zend_get_constant(zend_string *name TSRMLS_DC); +ZEND_API zval *zend_get_constant_str(const char *name, uint name_len TSRMLS_DC); +ZEND_API zval *zend_get_constant_ex(zend_string *name, zend_class_entry *scope, ulong flags TSRMLS_DC); ZEND_API void zend_register_bool_constant(const char *name, uint name_len, zend_bool bval, int flags, int module_number TSRMLS_DC); ZEND_API void zend_register_null_constant(const char *name, uint name_len, int flags, int module_number TSRMLS_DC); ZEND_API void zend_register_long_constant(const char *name, uint name_len, long lval, int flags, int module_number TSRMLS_DC); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index d2fefa7f71..3ad4a8cac1 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -509,7 +509,7 @@ ZEND_API int zend_is_true(zval *op TSRMLS_DC) /* {{{ */ ZEND_API int zval_update_constant_ex(zval *p, void *arg, zend_class_entry *scope TSRMLS_DC) /* {{{ */ { zend_bool inline_change = (zend_bool) (zend_uintptr_t) arg; - zval const_value; + zval *const_value, tmp; char *colon; if (IS_CONSTANT_VISITED(p)) { @@ -520,7 +520,8 @@ ZEND_API int zval_update_constant_ex(zval *p, void *arg, zend_class_entry *scope SEPARATE_ZVAL_IF_NOT_REF(p); MARK_CONSTANT_VISITED(p); refcount = Z_REFCOUNTED_P(p) ? Z_REFCOUNT_P(p) : 1; - if (!zend_get_constant_ex(Z_STRVAL_P(p), Z_STRLEN_P(p), &const_value, scope, Z_CONST_FLAGS_P(p) TSRMLS_CC)) { + const_value = zend_get_constant_ex(Z_STR_P(p), scope, Z_CONST_FLAGS_P(p) TSRMLS_CC); + if (!const_value) { char *actual = Z_STRVAL_P(p); if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { @@ -584,7 +585,12 @@ ZEND_API int zval_update_constant_ex(zval *p, void *arg, zend_class_entry *scope if (inline_change) { STR_RELEASE(Z_STR_P(p)); } - ZVAL_COPY_VALUE(p, &const_value); +//???! + ZVAL_COPY_VALUE(p, const_value); + if (Z_OPT_CONSTANT_P(p)) { + zval_update_constant_ex(p, (void*)1, NULL TSRMLS_CC); + } + zval_opt_copy_ctor(p); } if (Z_REFCOUNTED_P(p)) Z_SET_REFCOUNT_P(p, refcount); @@ -619,10 +625,11 @@ ZEND_API int zval_update_constant_ex(zval *p, void *arg, zend_class_entry *scope if (GC_FLAGS(str_index) & IS_STR_AST) { zend_ast_ref *ast = *(zend_ast_ref **)str_index->val; - zend_ast_evaluate(&const_value, ast->ast, scope TSRMLS_CC); + zend_ast_evaluate(&tmp, ast->ast, scope TSRMLS_CC); zend_ast_destroy(ast->ast); efree(ast); - } else if (!zend_get_constant_ex(str_index->val, str_index->len, &const_value, scope, GC_FLAGS(str_index) & ~(IS_STR_PERSISTENT | IS_STR_INTERNED |IS_STR_PERMANENT) TSRMLS_CC)) { + const_value = &tmp; + } else if (!(const_value = zend_get_constant_ex(str_index, scope, GC_FLAGS(str_index) & ~(IS_STR_PERSISTENT | IS_STR_INTERNED |IS_STR_PERMANENT) TSRMLS_CC))) { char *actual, *str; const char *save = str_index->val; int len; @@ -654,10 +661,19 @@ ZEND_API int zval_update_constant_ex(zval *p, void *arg, zend_class_entry *scope zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str, str); } if (str == str_index->val && len == str_index->len) { - ZVAL_STR(&const_value, STR_COPY(str_index)); + ZVAL_STR(&tmp, STR_COPY(str_index)); } else { - ZVAL_STRINGL(&const_value, str, len); + ZVAL_STRINGL(&tmp, str, len); + } + const_value = &tmp; + } else { +//???! + ZVAL_COPY_VALUE(&tmp, const_value); + if (Z_OPT_CONSTANT(tmp)) { + zval_update_constant_ex(&tmp, (void*)1, NULL TSRMLS_CC); } + zval_opt_copy_ctor(&tmp); + const_value = &tmp; } if (Z_REFCOUNTED_P(element) && Z_REFCOUNT_P(element) > 1) { @@ -666,16 +682,16 @@ ZEND_API int zval_update_constant_ex(zval *p, void *arg, zend_class_entry *scope ZVAL_COPY_VALUE(element, &new_val); } - switch (Z_TYPE(const_value)) { + switch (Z_TYPE_P(const_value)) { case IS_STRING: - ret = zend_symtable_update_current_key_ex(Z_ARRVAL_P(p), Z_STR(const_value), HASH_UPDATE_KEY_IF_BEFORE); + ret = zend_symtable_update_current_key_ex(Z_ARRVAL_P(p), Z_STR_P(const_value), HASH_UPDATE_KEY_IF_BEFORE); break; case IS_BOOL: case IS_LONG: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE); + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, Z_LVAL_P(const_value), HASH_UPDATE_KEY_IF_BEFORE); break; case IS_DOUBLE: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE); + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, zend_dval_to_lval(Z_DVAL_P(const_value)), HASH_UPDATE_KEY_IF_BEFORE); break; case IS_NULL: ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, STR_EMPTY_ALLOC(), 0, HASH_UPDATE_KEY_IF_BEFORE); @@ -687,19 +703,19 @@ ZEND_API int zval_update_constant_ex(zval *p, void *arg, zend_class_entry *scope if (ret == SUCCESS) { zend_hash_move_forward(Z_ARRVAL_P(p)); } - zval_dtor(&const_value); + zval_dtor(const_value); } zend_hash_apply_with_argument(Z_ARRVAL_P(p), (apply_func_arg_t) zval_update_constant_inline_change, (void *) scope TSRMLS_CC); zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); } else if (Z_TYPE_P(p) == IS_CONSTANT_AST) { SEPARATE_ZVAL_IF_NOT_REF(p); - zend_ast_evaluate(&const_value, Z_ASTVAL_P(p), scope TSRMLS_CC); + zend_ast_evaluate(&tmp, Z_ASTVAL_P(p), scope TSRMLS_CC); if (inline_change) { zend_ast_destroy(Z_ASTVAL_P(p)); efree(Z_AST_P(p)); } - ZVAL_COPY_VALUE(p, &const_value); + ZVAL_COPY_VALUE(p, &tmp); } return 0; } diff --git a/Zend/zend_ini_parser.y b/Zend/zend_ini_parser.y index b65b16a93c..29a2cb0aff 100644 --- a/Zend/zend_ini_parser.y +++ b/Zend/zend_ini_parser.y @@ -112,15 +112,24 @@ static void zend_ini_add_string(zval *result, zval *op1, zval *op2) */ static void zend_ini_get_constant(zval *result, zval *name TSRMLS_DC) { - zval z_constant; + zval *c, tmp; /* If name contains ':' it is not a constant. Bug #26893. */ if (!memchr(Z_STRVAL_P(name), ':', Z_STRLEN_P(name)) - && zend_get_constant(Z_STRVAL_P(name), Z_STRLEN_P(name), &z_constant TSRMLS_CC)) { - /* z_constant is emalloc()'d */ - convert_to_string(&z_constant); - ZVAL_PSTRINGL(result, Z_STRVAL(z_constant), Z_STRLEN(z_constant)); - zval_dtor(&z_constant); + && (c = zend_get_constant(Z_STR_P(name) TSRMLS_CC)) != 0) { + if (Z_TYPE_P(c) != IS_STRING) { + ZVAL_COPY_VALUE(&tmp, c); + if (Z_OPT_CONSTANT(tmp)) { + zval_update_constant_ex(&tmp, (void*)1, NULL TSRMLS_CC); + } + zval_opt_copy_ctor(&tmp); + convert_to_string(&tmp); + c = &tmp; + } + ZVAL_PSTRINGL(result, Z_STRVAL_P(c), Z_STRLEN_P(c)); + if (c == &tmp) { + zval_dtor(&tmp); + } STR_FREE(Z_STR_P(name)); } else { *result = *name; diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index 4e1410a76e..cae7e80375 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -218,16 +218,16 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { /* substitute __COMPILER_HALT_OFFSET__ constant */ zend_bool orig_in_execution = EG(in_execution); zend_op_array *orig_op_array = EG(active_op_array); - zval offset; + zval *offset; EG(in_execution) = 1; EG(active_op_array) = op_array; - if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1, &offset TSRMLS_CC)) { + if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1 TSRMLS_CC)) != NULL) { zend_uint tv = ZEND_RESULT(opline).var; literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); - replace_tmp_by_const(op_array, opline, tv, &offset TSRMLS_CC); + replace_tmp_by_const(op_array, opline, tv, offset TSRMLS_CC); } EG(active_op_array) = orig_op_array; EG(in_execution) = orig_in_execution; diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 39a2aa4a7c..bc63705e5e 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -198,15 +198,15 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc if (main_persistent_script) { zend_bool orig_in_execution = EG(in_execution); zend_op_array *orig_op_array = EG(active_op_array); - zval offset; + zval *offset; #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO main_persistent_script->early_binding = -1; #endif EG(in_execution) = 1; EG(active_op_array) = op_array; - if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1, &offset TSRMLS_CC)) { - main_persistent_script->compiler_halt_offset = Z_LVAL(offset); + if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1 TSRMLS_CC)) != NULL) { + main_persistent_script->compiler_halt_offset = Z_LVAL_P(offset); } EG(active_op_array) = orig_op_array; EG(in_execution) = orig_in_execution; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 7647781e2b..0393917e23 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -3854,15 +3854,22 @@ PHP_MINFO_FUNCTION(basic) /* {{{ */ Given the name of a constant this function will return the constant's associated value */ PHP_FUNCTION(constant) { - char *const_name; - int const_name_len; + zend_string *const_name; + zval *c; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &const_name, &const_name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &const_name) == FAILURE) { return; } - if (!zend_get_constant_ex(const_name, const_name_len, return_value, NULL, ZEND_FETCH_CLASS_SILENT TSRMLS_CC)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't find constant %s", const_name); + c = zend_get_constant_ex(const_name, NULL, ZEND_FETCH_CLASS_SILENT TSRMLS_CC); + if (c) { + ZVAL_COPY_VALUE(return_value, c); + if (Z_CONSTANT_P(return_value)) { + zval_update_constant_ex(return_value, (void*)1, NULL TSRMLS_CC); + } + zval_copy_ctor(return_value); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't find constant %s", const_name->val); RETURN_NULL(); } } -- 2.40.0