Skip to content

Commit 0df51e9

Browse files
committed
Add support for class constants and enum cases for #[\Deprecated]
1 parent 7ccef0f commit 0df51e9

File tree

10 files changed

+149
-40
lines changed

10 files changed

+149
-40
lines changed

Zend/tests/attributes/deprecated/001.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
#[\Deprecated]
2+
#[\Deprecated]: Functions and Methods
33
--FILE--
44
<?php
55

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
#[\Deprecated]: Class Constants
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
7+
echo "$errstr", PHP_EOL;
8+
9+
if ($errno !== E_USER_DEPRECATED) {
10+
echo "Wrong errno: $errno", PHP_EOL;
11+
}
12+
});
13+
14+
class Foo {
15+
#[\Deprecated]
16+
public const TEST = 1;
17+
18+
#[\Deprecated()]
19+
public const TEST2 = 1;
20+
21+
#[\Deprecated("use Clazz::TEST instead")]
22+
public const TEST3 = 1;
23+
}
24+
25+
Foo::TEST;
26+
Foo::TEST2;
27+
Foo::TEST3;
28+
29+
?>
30+
--EXPECT--
31+
Constant Foo::TEST is deprecated
32+
Constant Foo::TEST2 is deprecated
33+
Constant Foo::TEST3 is deprecated, use Clazz::TEST instead
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
#[\Deprecated]: Enum cases
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
7+
echo "$errstr", PHP_EOL;
8+
9+
if ($errno !== E_USER_DEPRECATED) {
10+
echo "Wrong errno: $errno", PHP_EOL;
11+
}
12+
});
13+
14+
enum E {
15+
#[\Deprecated]
16+
case Test;
17+
18+
#[\Deprecated("use E::Test instead")]
19+
case Test2;
20+
}
21+
22+
E::Test;
23+
E::Test2;
24+
25+
?>
26+
--EXPECT--
27+
Enum case E::Test is deprecated
28+
Enum case E::Test2 is deprecated, use E::Test instead

Zend/zend_attributes.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function __construct() {}
7575
/**
7676
* @strict-properties
7777
*/
78-
#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION)]
78+
#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION|Attribute::TARGET_CLASS_CONSTANT)]
7979
final class Deprecated
8080
{
8181
public readonly ?string $message;

Zend/zend_attributes_arginfo.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_compile.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8120,6 +8120,12 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as
81208120

81218121
if (attr_ast) {
81228122
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
8123+
8124+
zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
8125+
8126+
if (deprecated) {
8127+
ZEND_CLASS_CONST_FLAGS(c) = ZEND_CLASS_CONST_FLAGS(c) | ZEND_ACC_DEPRECATED;
8128+
}
81238129
}
81248130
}
81258131
}
@@ -8549,6 +8555,12 @@ static void zend_compile_enum_case(zend_ast *ast)
85498555
zend_ast *attr_ast = ast->child[3];
85508556
if (attr_ast) {
85518557
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
8558+
8559+
zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
8560+
8561+
if (deprecated) {
8562+
ZEND_CLASS_CONST_FLAGS(c) = ZEND_CLASS_CONST_FLAGS(c) | ZEND_ACC_DEPRECATED;
8563+
}
85528564
}
85538565
}
85548566

Zend/zend_execute.c

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,50 +1723,63 @@ ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void)
17231723
zend_throw_error(NULL, "%s", msg);
17241724
}
17251725

1726-
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
1726+
ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute(HashTable *attributes, zend_class_entry* scope, zend_string **message_suffix)
17271727
{
1728-
zend_string *message_suffix = zend_empty_string;
1728+
*message_suffix = zend_empty_string;
17291729

1730-
if (fbc->common.attributes != NULL) {
1731-
zend_attribute *deprecated = zend_get_attribute_str(fbc->common.attributes, "deprecated", sizeof("deprecated")-1);
1730+
if (!attributes) {
1731+
return SUCCESS;
1732+
}
17321733

1733-
if (deprecated->argc >= 1) {
1734-
zval message;
1734+
zend_attribute *deprecated = zend_get_attribute_str(attributes, "deprecated", sizeof("deprecated")-1);
17351735

1736-
if (FAILURE != zend_get_attribute_value(&message, deprecated, 0, fbc->common.scope)) {
1737-
if (EXPECTED(Z_TYPE(message) == IS_STRING)) {
1738-
/* Fast path: Just copy the string. */
1739-
message_suffix = zend_string_copy(Z_STR(message));
1740-
zval_ptr_dtor(&message);
1741-
} else {
1742-
/* Slow path: Not a string, pass this through the constructor for
1743-
* consistent error handling.
1744-
*/
1745-
zval obj;
1736+
if (deprecated && deprecated->argc >= 1) {
1737+
zval message;
17461738

1747-
object_init_ex(&obj, zend_ce_deprecated);
1748-
zend_call_method_with_1_params(Z_OBJ_P(&obj), zend_ce_deprecated, &zend_ce_deprecated->constructor, "__construct", NULL, &message);
1749-
zval_ptr_dtor(&message);
1739+
if (FAILURE != zend_get_attribute_value(&message, deprecated, 0, scope)) {
1740+
if (EXPECTED(Z_TYPE(message) == IS_STRING)) {
1741+
/* Fast path: Just copy the string. */
1742+
*message_suffix = zend_string_copy(Z_STR(message));
1743+
zval_ptr_dtor(&message);
1744+
} else {
1745+
/* Slow path: Not a string, pass this through the constructor for
1746+
* consistent error handling.
1747+
*/
1748+
zval obj;
17501749

1751-
if (EG(exception)) {
1752-
zval_ptr_dtor(&obj);
1753-
return;
1754-
}
1750+
object_init_ex(&obj, zend_ce_deprecated);
1751+
zend_call_method_with_1_params(Z_OBJ_P(&obj), zend_ce_deprecated, &zend_ce_deprecated->constructor, "__construct", NULL, &message);
1752+
zval_ptr_dtor(&message);
17551753

1756-
zval *z;
1754+
if (EG(exception)) {
1755+
zval_ptr_dtor(&obj);
1756+
return FAILURE;
1757+
}
17571758

1758-
if ((z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL)) == NULL) {
1759-
zval_ptr_dtor(&obj);
1760-
return;
1761-
}
1759+
zval *z;
17621760

1763-
message_suffix = zend_string_copy(Z_STR_P(z));
1761+
if ((z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL)) == NULL) {
17641762
zval_ptr_dtor(&obj);
1763+
return FAILURE;
17651764
}
1765+
1766+
*message_suffix = zend_string_copy(Z_STR_P(z));
1767+
zval_ptr_dtor(&obj);
17661768
}
17671769
}
17681770
}
17691771

1772+
return SUCCESS;
1773+
}
1774+
1775+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
1776+
{
1777+
zend_string *message_suffix = zend_empty_string;
1778+
1779+
if (get_deprecation_suffix_from_attribute(fbc->common.attributes, fbc->common.scope, &message_suffix) == FAILURE) {
1780+
return;
1781+
}
1782+
17701783
int code = fbc->type == ZEND_INTERNAL_FUNCTION ? E_DEPRECATED : E_USER_DEPRECATED;
17711784

17721785
if (fbc->common.scope) {
@@ -1787,6 +1800,28 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_functi
17871800
zend_string_release(message_suffix);
17881801
}
17891802

1803+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name)
1804+
{
1805+
zend_string *message_suffix = zend_empty_string;
1806+
1807+
if (get_deprecation_suffix_from_attribute(c->attributes, c->ce, &message_suffix) == FAILURE) {
1808+
return;
1809+
}
1810+
1811+
int code = c->ce->type == ZEND_INTERNAL_CLASS ? E_DEPRECATED : E_USER_DEPRECATED;
1812+
char *type = (ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE) ? "Enum case" : "Constant";
1813+
1814+
zend_error_unchecked(code, "%s %s::%s is deprecated%s%S",
1815+
type,
1816+
ZSTR_VAL(c->ce->name),
1817+
ZSTR_VAL(constant_name),
1818+
ZSTR_LEN(message_suffix) > 0 ? ", " : "",
1819+
message_suffix
1820+
);
1821+
1822+
zend_string_release(message_suffix);
1823+
}
1824+
17901825
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void)
17911826
{
17921827
zend_error(E_DEPRECATED, "Automatic conversion of false to array is deprecated");

Zend/zend_execute.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ extern ZEND_API const zend_internal_function zend_pass_function;
6262

6363
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data);
6464
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc);
65+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name);
6566
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void);
6667
ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num);
6768
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim);

Zend/zend_vm_def.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6037,7 +6037,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
60376037

60386038
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
60396039
if (UNEXPECTED(is_constant_deprecated)) {
6040-
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name));
6040+
zend_deprecated_class_constant(c, constant_name);
60416041

60426042
if (EG(exception)) {
60436043
ZVAL_UNDEF(EX_VAR(opline->result.var));

Zend/zend_vm_execute.h

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)