Skip to content

Commit 1cf2b89

Browse files
committed
Add #[Deprecated] attribute based on ZEND_ACC_DEPRECATED
1 parent 58d459f commit 1cf2b89

File tree

6 files changed

+112
-0
lines changed

6 files changed

+112
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
#[Deprecated] attribute
3+
--FILE--
4+
<?php
5+
6+
error_reporting(E_ALL | E_DEPRECATED);
7+
ini_set('display_errors', true);
8+
9+
#[Deprecated]
10+
function test() {
11+
}
12+
13+
#[Deprecated("use test() instead")]
14+
function test2() {
15+
}
16+
17+
test();
18+
test2();
19+
call_user_func("test");
20+
--EXPECTF--
21+
Deprecated: Function test is deprecated in %s
22+
23+
Deprecated: Function test2 is deprecated use test() instead in %s
24+
25+
Deprecated: Function test is deprecated in %s

Zend/zend_attributes.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "zend_smart_str.h"
2525

2626
ZEND_API zend_class_entry *zend_ce_attribute;
27+
ZEND_API zend_class_entry *zend_ce_deprecated_attribute;
2728

2829
static HashTable internal_attributes;
2930

@@ -55,6 +56,28 @@ void validate_attribute(zend_attribute *attr, uint32_t target, zend_class_entry
5556
}
5657
}
5758

59+
void validate_deprecated_attribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
60+
{
61+
// TODO: More proper signature validation: Too many args, incorrect arg names.
62+
if (attr->argc == 1) {
63+
zval message;
64+
65+
/* As this is run in the middle of compilation, fetch the attribute value without
66+
* specifying a scope. The class is not fully linked yet, and we may seen an
67+
* inconsistent state. */
68+
if (FAILURE == zend_get_attribute_value(&message, attr, 0, NULL)) {
69+
return;
70+
}
71+
72+
if (Z_TYPE(message) != IS_STRING) {
73+
zend_error_noreturn(E_COMPILE_ERROR,
74+
"Deprecated::__construct: Argument #1 ($message) must be of type string, %s given",
75+
zend_zval_type_name(&message)
76+
);
77+
}
78+
}
79+
}
80+
5881
ZEND_METHOD(Attribute, __construct)
5982
{
6083
zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
@@ -289,6 +312,13 @@ void zend_register_attribute_ce(void)
289312

290313
attr = zend_internal_attribute_register(zend_ce_attribute, ZEND_ATTRIBUTE_TARGET_CLASS);
291314
attr->validator = validate_attribute;
315+
316+
INIT_CLASS_ENTRY(ce, "Deprecated", NULL);
317+
zend_ce_deprecated_attribute = zend_register_internal_class(&ce);
318+
zend_ce_deprecated_attribute->ce_flags |= ZEND_ACC_FINAL;
319+
320+
attr = zend_internal_attribute_register(zend_ce_deprecated_attribute, ZEND_ATTRIBUTE_TARGET_FUNCTION | ZEND_ATTRIBUTE_TARGET_METHOD);
321+
attr->validator = validate_deprecated_attribute;
292322
}
293323

294324
void zend_attributes_shutdown(void)

Zend/zend_compile.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6876,6 +6876,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
68766876
zend_ast *return_type_ast = decl->child[3];
68776877
zend_bool is_method = decl->kind == ZEND_AST_METHOD;
68786878
zend_string *method_lcname;
6879+
zend_attribute *deprecated;
68796880

68806881
zend_class_entry *orig_class_entry = CG(active_class_entry);
68816882
zend_op_array *orig_op_array = CG(active_op_array);
@@ -6965,6 +6966,13 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
69656966
} else if (uses_ast) {
69666967
zend_compile_closure_uses(uses_ast);
69676968
}
6969+
6970+
deprecated = zend_get_attribute_str(op_array->attributes, "deprecated", sizeof("deprecated")-1);
6971+
6972+
if (deprecated && stmt_ast != NULL) {
6973+
op_array->fn_flags |= ZEND_ACC_DEPRECATED;
6974+
}
6975+
69686976
zend_compile_stmt(stmt_ast);
69696977

69706978
if (is_method) {

Zend/zend_execute.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,7 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_property_read(z
14891489

14901490
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
14911491
{
1492+
php_printf("yay deprecated\n");
14921493
if (fbc->common.scope) {
14931494
zend_error(E_DEPRECATED, "Method %s::%s() is deprecated",
14941495
ZSTR_VAL(fbc->common.scope->name),

Zend/zend_vm_def.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3945,6 +3945,10 @@ ZEND_VM_HOT_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
39453945
zend_function *fbc = call->func;
39463946
zval *ret;
39473947

3948+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
3949+
zend_deprecated_function(fbc);
3950+
}
3951+
39483952
SAVE_OPLINE();
39493953
EX(call) = call->prev_execute_data;
39503954

@@ -3979,6 +3983,10 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
39793983
ret = EX_VAR(opline->result.var);
39803984
}
39813985

3986+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
3987+
zend_deprecated_function(fbc);
3988+
}
3989+
39823990
call->prev_execute_data = execute_data;
39833991
execute_data = call;
39843992
i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC);
@@ -4074,6 +4082,10 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
40744082
ret = EX_VAR(opline->result.var);
40754083
}
40764084

4085+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
4086+
zend_deprecated_function(fbc);
4087+
}
4088+
40774089
call->prev_execute_data = execute_data;
40784090
execute_data = call;
40794091
i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC);

Zend/zend_vm_execute.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV
13391339
zend_function *fbc = call->func;
13401340
zval *ret;
13411341

1342+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1343+
zend_deprecated_function(fbc);
1344+
}
1345+
13421346
SAVE_OPLINE();
13431347
EX(call) = call->prev_execute_data;
13441348

@@ -1363,6 +1367,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV
13631367
zend_function *fbc = call->func;
13641368
zval *ret;
13651369

1370+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1371+
zend_deprecated_function(fbc);
1372+
}
1373+
13661374
SAVE_OPLINE();
13671375
EX(call) = call->prev_execute_data;
13681376

@@ -1387,6 +1395,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_OBS
13871395
zend_function *fbc = call->func;
13881396
zval *ret;
13891397

1398+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1399+
zend_deprecated_function(fbc);
1400+
}
1401+
13901402
SAVE_OPLINE();
13911403
EX(call) = call->prev_execute_data;
13921404

@@ -1421,6 +1433,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
14211433
ret = EX_VAR(opline->result.var);
14221434
}
14231435

1436+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1437+
zend_deprecated_function(fbc);
1438+
}
1439+
14241440
call->prev_execute_data = execute_data;
14251441
execute_data = call;
14261442
i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC);
@@ -1515,6 +1531,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
15151531
ret = EX_VAR(opline->result.var);
15161532
}
15171533

1534+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1535+
zend_deprecated_function(fbc);
1536+
}
1537+
15181538
call->prev_execute_data = execute_data;
15191539
execute_data = call;
15201540
i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC);
@@ -1609,6 +1629,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
16091629
ret = EX_VAR(opline->result.var);
16101630
}
16111631

1632+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1633+
zend_deprecated_function(fbc);
1634+
}
1635+
16121636
call->prev_execute_data = execute_data;
16131637
execute_data = call;
16141638
i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC);
@@ -1704,6 +1728,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
17041728
ret = EX_VAR(opline->result.var);
17051729
}
17061730

1731+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1732+
zend_deprecated_function(fbc);
1733+
}
1734+
17071735
call->prev_execute_data = execute_data;
17081736
execute_data = call;
17091737
i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC);
@@ -1812,6 +1840,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
18121840
ret = EX_VAR(opline->result.var);
18131841
}
18141842

1843+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1844+
zend_deprecated_function(fbc);
1845+
}
1846+
18151847
call->prev_execute_data = execute_data;
18161848
execute_data = call;
18171849
i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC);
@@ -1920,6 +1952,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
19201952
ret = EX_VAR(opline->result.var);
19211953
}
19221954

1955+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
1956+
zend_deprecated_function(fbc);
1957+
}
1958+
19231959
call->prev_execute_data = execute_data;
19241960
execute_data = call;
19251961
i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC);

0 commit comments

Comments
 (0)