diff --git a/Zend/tests/const_deprecation.phpt b/Zend/tests/const_deprecation.phpt new file mode 100644 index 0000000000000..b7cf99d52e974 --- /dev/null +++ b/Zend/tests/const_deprecation.phpt @@ -0,0 +1,25 @@ +--TEST-- +Internal constant deprecation +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Deprecated: Constant ZEND_TEST_DEPRECATED is deprecated in %s on line %d +int(42) + +Deprecated: Constant ZEND_TEST_DEPRECATED is deprecated in %s on line %d +int(42) + +Deprecated: Constant ZEND_TEST_DEPRECATED is deprecated in %s on line %d +int(42) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7cd71426f5d8f..75d1bd3718bc0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1409,15 +1409,27 @@ ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char } /* }}} */ +static zend_bool can_ct_eval_const(zend_constant *c) { + if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { + return 0; + } + if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) + && !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION) + && !((ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE) + && (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) { + return 1; + } + if (Z_TYPE(c->value) < IS_OBJECT + && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { + return 1; + } + return 0; +} + static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool is_fully_qualified) /* {{{ */ { zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name); - if (c && ( - ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) - && !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION) - && !((ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE) && (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) - || (Z_TYPE(c->value) < IS_OBJECT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) - )) { + if (c && can_ct_eval_const(c)) { ZVAL_COPY_OR_DUP(zv, &c->value); return 1; } @@ -1426,14 +1438,13 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i /* Substitute true, false and null (including unqualified usage in namespaces) */ const char *lookup_name = ZSTR_VAL(name); size_t lookup_len = ZSTR_LEN(name); - zval *val; if (!is_fully_qualified) { zend_get_unqualified_name(name, &lookup_name, &lookup_len); } - if ((val = zend_get_special_const(lookup_name, lookup_len))) { - ZVAL_COPY_VALUE(zv, val); + if ((c = zend_get_special_const(lookup_name, lookup_len))) { + ZVAL_COPY_VALUE(zv, &c->value); return 1; } diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 84e7891aba250..0885525676bff 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -34,7 +34,7 @@ #define RESET_CONSTANT_VISITED(zv) Z_ACCESS_FLAGS_P(zv) &= ~IS_CONSTANT_VISITED_MARK /* Use for special null/true/false constants. */ -static zval null_value, true_value, false_value; +static zend_constant *null_const, *true_const, *false_const; void free_zend_constant(zval *zv) { @@ -138,9 +138,9 @@ void zend_register_standard_constants(void) REGISTER_MAIN_BOOL_CONSTANT("FALSE", 0, CONST_PERSISTENT); REGISTER_MAIN_NULL_CONSTANT("NULL", CONST_PERSISTENT); - ZVAL_NULL(&null_value); - ZVAL_TRUE(&true_value); - ZVAL_FALSE(&false_value); + true_const = zend_hash_str_find_ptr(EG(zend_constants), "TRUE", sizeof("TRUE")-1); + false_const = zend_hash_str_find_ptr(EG(zend_constants), "FALSE", sizeof("FALSE")-1); + null_const = zend_hash_str_find_ptr(EG(zend_constants), "NULL", sizeof("NULL")-1); } @@ -235,7 +235,7 @@ static zend_constant *zend_get_halt_offset_constant(const char *name, size_t nam } } -ZEND_API zval *_zend_get_special_const(const char *name, size_t len) /* {{{ */ +ZEND_API zend_constant *_zend_get_special_const(const char *name, size_t len) /* {{{ */ { if (len == 4) { if ((name[0] == 'n' || name[0] == 'N') && @@ -243,14 +243,14 @@ ZEND_API zval *_zend_get_special_const(const char *name, size_t len) /* {{{ */ (name[2] == 'l' || name[2] == 'L') && (name[3] == 'l' || name[3] == 'L') ) { - return &null_value; + return null_const; } if ((name[0] == 't' || name[0] == 'T') && (name[1] == 'r' || name[1] == 'R') && (name[2] == 'u' || name[2] == 'U') && (name[3] == 'e' || name[3] == 'E') ) { - return &true_value; + return true_const; } } else { if ((name[0] == 'f' || name[0] == 'F') && @@ -259,10 +259,10 @@ ZEND_API zval *_zend_get_special_const(const char *name, size_t len) /* {{{ */ (name[3] == 's' || name[3] == 'S') && (name[4] == 'e' || name[4] == 'E') ) { - return &false_value; + return false_const; } } - return 0; + return NULL; } /* }}} */ @@ -279,36 +279,54 @@ ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry * } /* }}} */ -ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len) +static zend_constant *zend_get_constant_str_impl(const char *name, size_t name_len) { zend_constant *c = zend_hash_str_find_ptr(EG(zend_constants), name, name_len); if (c) { - return &c->value; + return c; } c = zend_get_halt_offset_constant(name, name_len); if (c) { - return &c->value; + return c; } return zend_get_special_const(name, name_len); } -ZEND_API zval *zend_get_constant(zend_string *name) +ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len) { - zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name); + zend_constant *c = zend_get_constant_str_impl(name, name_len); if (c) { return &c->value; } + return NULL; +} + +static zend_constant *zend_get_constant_impl(zend_string *name) +{ + zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name); + if (c) { + return c; + } c = zend_get_halt_offset_constant(ZSTR_VAL(name), ZSTR_LEN(name)); if (c) { - return &c->value; + return c; } return zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name)); } +ZEND_API zval *zend_get_constant(zend_string *name) +{ + zend_constant *c = zend_get_constant_impl(name); + if (c) { + return &c->value; + } + return NULL; +} + ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, uint32_t flags) { zend_constant *c; @@ -402,7 +420,6 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, } /* non-class constant */ - zval *value; if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) { /* compound constant name */ int prefix_len = colon - name; @@ -423,28 +440,28 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len); free_alloca(lcname, use_heap); - if (c) { - return &c->value; - } - - if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) { - /* name requires runtime resolution, need to check non-namespaced name */ - value = zend_get_constant_str(constant_name, const_name_len); - } else { - value = NULL; + if (!c) { + if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) { + /* name requires runtime resolution, need to check non-namespaced name */ + c = zend_get_constant_str_impl(constant_name, const_name_len); + } } } else { if (cname) { - value = zend_get_constant(cname); + c = zend_get_constant_impl(cname); } else { - value = zend_get_constant_str(name, name_len); + c = zend_get_constant_str_impl(name, name_len); } } - if (!value && !(flags & ZEND_FETCH_CLASS_SILENT)) { - zend_throw_error(NULL, "Undefined constant '%s'", name); + if (!(flags & ZEND_FETCH_CLASS_SILENT)) { + if (!c) { + zend_throw_error(NULL, "Undefined constant '%s'", name); + } else if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { + zend_error(E_DEPRECATED, "Constant %s is deprecated", name); + } } - return value; + return &c->value; } static void* zend_hash_add_constant(HashTable *ht, zend_string *key, zend_constant *c) diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index 75be4c32b268c..9b5a63a0260d9 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -25,6 +25,7 @@ #define CONST_CS 0 /* No longer used -- always case sensitive */ #define CONST_PERSISTENT (1<<0) /* Persistent */ #define CONST_NO_FILE_CACHE (1<<1) /* Can't be saved in file cache */ +#define CONST_DEPRECATED (1<<2) /* Deprecated */ #define PHP_USER_CONSTANT 0x7fffff /* a constant defined in user space */ @@ -86,9 +87,10 @@ ZEND_API int zend_register_constant(zend_constant *c); void zend_copy_constants(HashTable *target, HashTable *sourc); #endif -ZEND_API zval *_zend_get_special_const(const char *name, size_t name_len); +ZEND_API zend_constant *_zend_get_special_const(const char *name, size_t name_len); -static zend_always_inline zval *zend_get_special_const(const char *name, size_t name_len) { +static zend_always_inline zend_constant *zend_get_special_const( + const char *name, size_t name_len) { if (name_len == 4 || name_len == 5) { return _zend_get_special_const(name, name_len); } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 17de515410b1d..f5ad54939af83 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -4301,6 +4301,10 @@ static zend_always_inline int _zend_quick_get_constant( if (!check_defined_only) { ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); + if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { + zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(c->name)); + return SUCCESS; + } } CACHE_PTR(opline->extended_value, c); diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index b6af541eac6e9..79028982451c7 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -33,10 +33,10 @@ /* Checks if a constant (like "true") may be replaced by its value */ int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy) { - zval *zv; zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name); if (c) { if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) + && !(ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) && (!(ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE) || !(CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) { ZVAL_COPY_VALUE(result, &c->value); @@ -50,9 +50,9 @@ int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int } /* Special constants null/true/false can always be substituted. */ - zv = zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name)); - if (zv) { - ZVAL_COPY_VALUE(result, zv); + c = zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name)); + if (c) { + ZVAL_COPY_VALUE(result, &c->value); return 1; } return 0; diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 2f21bd8158e31..0deb39910e93d 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -301,6 +301,8 @@ PHP_MINIT_FUNCTION(zend_test) zend_declare_property_null(zend_test_trait, "testProp", sizeof("testProp")-1, ZEND_ACC_PUBLIC); zend_register_class_alias("_ZendTestClassAlias", zend_test_class); + + REGISTER_LONG_CONSTANT("ZEND_TEST_DEPRECATED", 42, CONST_PERSISTENT | CONST_DEPRECATED); return SUCCESS; }