Skip to content

Commit 68bd5b0

Browse files
committed
Add Deprecated::$since
1 parent 051c6ec commit 68bd5b0

File tree

8 files changed

+174
-44
lines changed

8 files changed

+174
-44
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
#[\Deprecated]: $message property is readonly.
3+
--FILE--
4+
<?php
5+
6+
$d = new \Deprecated("foo");
7+
$d->message = 'bar';
8+
9+
?>
10+
--EXPECTF--
11+
Fatal error: Uncaught Error: Cannot modify readonly property Deprecated::$message in %s:%d
12+
Stack trace:
13+
#0 {main}
14+
thrown in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
#[\Deprecated]: $since property is readonly.
3+
--FILE--
4+
<?php
5+
6+
$d = new \Deprecated("foo", "1.0");
7+
$d->since = "2.0";
8+
9+
?>
10+
--EXPECTF--
11+
Fatal error: Uncaught Error: Cannot modify readonly property Deprecated::$since in %s:%d
12+
Stack trace:
13+
#0 {main}
14+
thrown in %s on line %d

Zend/tests/attributes/deprecated/functions/002.phpt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,21 @@ var_dump($reflection->getAttributes()[0]->newInstance());
2626

2727
?>
2828
--EXPECTF--
29-
object(Deprecated)#%d (1) {
29+
object(Deprecated)#%d (2) {
3030
["message"]=>
3131
NULL
32+
["since"]=>
33+
NULL
3234
}
33-
object(Deprecated)#%d (1) {
35+
object(Deprecated)#%d (2) {
3436
["message"]=>
3537
NULL
38+
["since"]=>
39+
NULL
3640
}
37-
object(Deprecated)#%d (1) {
41+
object(Deprecated)#%d (2) {
3842
["message"]=>
3943
string(18) "use test() instead"
44+
["since"]=>
45+
NULL
4046
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
#[\Deprecated]: Error message formats.
3+
--FILE--
4+
<?php
5+
6+
#[\Deprecated]
7+
function test1() {
8+
}
9+
10+
#[\Deprecated()]
11+
function test2() {
12+
}
13+
14+
#[\Deprecated("use test() instead")]
15+
function test3() {
16+
}
17+
18+
#[\Deprecated(message: "use test() instead", since: "1.0")]
19+
function test4() {
20+
}
21+
22+
#[\Deprecated(since: "1.0", message: "use test() instead")]
23+
function test5() {
24+
}
25+
26+
#[\Deprecated(since: "1.0")]
27+
function test6() {
28+
}
29+
30+
test1();
31+
test2();
32+
test3();
33+
test4();
34+
test5();
35+
test6();
36+
37+
?>
38+
--EXPECTF--
39+
Deprecated: Function test1() is deprecated in %s on line %d
40+
41+
Deprecated: Function test2() is deprecated in %s on line %d
42+
43+
Deprecated: Function test3() is deprecated, use test() instead in %s on line %d
44+
45+
Deprecated: Function test4() is deprecated since 1.0, use test() instead in %s on line %d
46+
47+
Deprecated: Function test5() is deprecated since 1.0, use test() instead in %s on line %d
48+
49+
Deprecated: Function test6() is deprecated since 1.0 in %s on line %d

Zend/zend_attributes.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,20 +150,37 @@ ZEND_METHOD(Override, __construct)
150150
ZEND_METHOD(Deprecated, __construct)
151151
{
152152
zend_string *message = NULL;
153+
zend_string *since = NULL;
154+
zend_string *property_name;
153155
zval value;
154156

155-
ZVAL_NULL(&value);
156-
157-
ZEND_PARSE_PARAMETERS_START(0, 1)
157+
ZEND_PARSE_PARAMETERS_START(0, 2)
158158
Z_PARAM_OPTIONAL
159159
Z_PARAM_STR_OR_NULL(message)
160+
Z_PARAM_STR_OR_NULL(since)
160161
ZEND_PARSE_PARAMETERS_END();
161162

163+
property_name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
162164
if (message) {
163165
ZVAL_STR(&value, message);
166+
} else {
167+
ZVAL_NULL(&value);
168+
}
169+
zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), property_name, &value);
170+
zend_string_release(property_name);
171+
172+
if (EG(exception)) {
173+
return;
164174
}
165175

166-
zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value);
176+
property_name = ZSTR_INIT_LITERAL("since", 0);
177+
if (since) {
178+
ZVAL_STR(&value, since);
179+
} else {
180+
ZVAL_NULL(&value);
181+
}
182+
zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), property_name, &value);
183+
zend_string_release(property_name);
167184
}
168185

169186
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)

Zend/zend_attributes.stub.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,7 @@ final class Deprecated
8080
{
8181
public readonly ?string $message;
8282

83-
public function __construct(?string $message = null) {}
83+
public readonly ?string $since;
84+
85+
public function __construct(?string $message = null, ?string $since = null) {}
8486
}

Zend/zend_attributes_arginfo.h

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

Zend/zend_execute.c

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,43 +1733,67 @@ ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute
17331733

17341734
zend_attribute *deprecated = zend_get_attribute_str(attributes, "deprecated", sizeof("deprecated")-1);
17351735

1736-
if (deprecated && deprecated->argc >= 1) {
1737-
zval message;
1738-
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;
1736+
if (!deprecated) {
1737+
return SUCCESS;
1738+
}
17491739

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);
1740+
if (deprecated->argc == 0) {
1741+
return SUCCESS;
1742+
}
17531743

1754-
if (EG(exception)) {
1755-
zval_ptr_dtor(&obj);
1756-
return FAILURE;
1757-
}
1744+
zend_string *message = zend_empty_string;
1745+
zend_string *since = zend_empty_string;
17581746

1759-
zval *z;
1747+
zval obj;
1748+
ZVAL_UNDEF(&obj);
1749+
zval *z = NULL;
1750+
zend_string *property;
1751+
if (FAILURE == zend_get_attribute_object(&obj, zend_ce_deprecated, deprecated, scope, NULL)) {
1752+
return FAILURE;
1753+
}
17601754

1761-
if ((z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL)) == NULL) {
1762-
zval_ptr_dtor(&obj);
1763-
return FAILURE;
1764-
}
1755+
property = ZSTR_KNOWN(ZEND_STR_MESSAGE);
1756+
if ((z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), property, false, NULL)) == NULL) {
1757+
goto fail;
1758+
}
1759+
zend_string_release(property);
1760+
if (Z_TYPE_P(z) == IS_STRING) {
1761+
message = zend_string_copy(Z_STR_P(z));
1762+
}
17651763

1766-
*message_suffix = zend_string_copy(Z_STR_P(z));
1767-
zval_ptr_dtor(&obj);
1768-
}
1769-
}
1764+
property = ZSTR_INIT_LITERAL("since", 0);
1765+
if ((z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), property, false, NULL)) == NULL) {
1766+
goto fail;
1767+
}
1768+
zend_string_release(property);
1769+
1770+
if (Z_TYPE_P(z) == IS_STRING) {
1771+
since = zend_string_copy(Z_STR_P(z));
17701772
}
17711773

1774+
*message_suffix = zend_strpprintf_unchecked(
1775+
0,
1776+
"%s%S%s%S",
1777+
ZSTR_LEN(since) > 0 ? " since " : "",
1778+
since,
1779+
ZSTR_LEN(message) > 0 ? ", " : "",
1780+
message
1781+
);
1782+
1783+
zend_string_release(since);
1784+
zend_string_release(message);
1785+
zval_ptr_dtor(&obj);
1786+
17721787
return SUCCESS;
1788+
1789+
fail:
1790+
zend_string_release(since);
1791+
zend_string_release(message);
1792+
zval_ptr_dtor(&obj);
1793+
zval_ptr_dtor(z);
1794+
zend_string_release(property);
1795+
1796+
return FAILURE;
17731797
}
17741798

17751799
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
@@ -1783,16 +1807,14 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_functi
17831807
int code = fbc->type == ZEND_INTERNAL_FUNCTION ? E_DEPRECATED : E_USER_DEPRECATED;
17841808

17851809
if (fbc->common.scope) {
1786-
zend_error_unchecked(code, "Method %s::%s() is deprecated%s%S",
1810+
zend_error_unchecked(code, "Method %s::%s() is deprecated%S",
17871811
ZSTR_VAL(fbc->common.scope->name),
17881812
ZSTR_VAL(fbc->common.function_name),
1789-
ZSTR_LEN(message_suffix) > 0 ? ", " : "",
17901813
message_suffix
17911814
);
17921815
} else {
1793-
zend_error_unchecked(code, "Function %s() is deprecated%s%S",
1816+
zend_error_unchecked(code, "Function %s() is deprecated%S",
17941817
ZSTR_VAL(fbc->common.function_name),
1795-
ZSTR_LEN(message_suffix) > 0 ? ", " : "",
17961818
message_suffix
17971819
);
17981820
}
@@ -1811,11 +1833,10 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_
18111833
int code = c->ce->type == ZEND_INTERNAL_CLASS ? E_DEPRECATED : E_USER_DEPRECATED;
18121834
char *type = (ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE) ? "Enum case" : "Constant";
18131835

1814-
zend_error_unchecked(code, "%s %s::%s is deprecated%s%S",
1836+
zend_error_unchecked(code, "%s %s::%s is deprecated%S",
18151837
type,
18161838
ZSTR_VAL(c->ce->name),
18171839
ZSTR_VAL(constant_name),
1818-
ZSTR_LEN(message_suffix) > 0 ? ", " : "",
18191840
message_suffix
18201841
);
18211842

0 commit comments

Comments
 (0)