mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Add support for deprecating constants
Internal constants can be marked as CONST_DEPRECATED, in which case accessing them will throw a deprecation warning. For now this is only supported on global constants, not class constants. Complain to me if you need to deprecate a class constant... Closes GH-5072.
This commit is contained in:
parent
ae706e51e1
commit
9ec1ee5976
25
Zend/tests/const_deprecation.phpt
Normal file
25
Zend/tests/const_deprecation.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Internal constant deprecation
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('zend-test')) die('skip requires zend-test');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(ZEND_TEST_DEPRECATED);
|
||||
var_dump(constant('ZEND_TEST_DEPRECATED'));
|
||||
|
||||
const X = ZEND_TEST_DEPRECATED;
|
||||
var_dump(X);
|
||||
|
||||
?>
|
||||
--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)
|
@ -1401,15 +1401,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;
|
||||
}
|
||||
@ -1418,14 +1430,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;
|
||||
}
|
||||
|
||||
|
@ -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_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->value;
|
||||
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 @@ failure:
|
||||
}
|
||||
|
||||
/* 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 @@ failure:
|
||||
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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user