Skip to content

Commit a80360d

Browse files
committed
Deprecate direct access to static trait members
Static trait members may only be accessed through a class in which the trait is used, not directly on the trait. A complication here is that we should not store static methods/properties for which a deprecation is triggered in a cache slot. As the check for this is simple and cheap, I'm handling this in the cache slot population code in the VM. The alternative would be to pass the cache slot down into the fetching code. Part of https://wiki.php.net/rfc/deprecations_php_8_1.
1 parent cdbe39b commit a80360d

File tree

7 files changed

+138
-35
lines changed

7 files changed

+138
-35
lines changed

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ PHP 8.1 UPGRADE NOTES
330330
e.g. a truncation from 1.9 to 1, is deprecated. This affects array keys,
331331
int parameter and return types, and operators working on integers.
332332
RFC: https://wiki.php.net/rfc/implicit-float-int-deprecate
333+
. Calling a static method or accessing a static property directly on a trait
334+
is deprecated. Static methods and properties should only be accessed on a
335+
class using the trait.
336+
RFC: https://wiki.php.net/rfc/deprecations_php_8_1
333337
. Returning a non-array from __sleep will raise a warning
334338
. Returning by reference from a void function is deprecated.
335339
RFC: https://wiki.php.net/rfc/deprecations_php_8_1
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
--TEST--
2+
Direct access to static trait members is deprecated
3+
--FILE--
4+
<?php
5+
6+
trait T {
7+
public static $foo;
8+
public static function foo() {
9+
echo "Foo\n";
10+
}
11+
public static function __callStatic($name, $args) {
12+
echo "CallStatic($name)\n";
13+
}
14+
}
15+
16+
class C {
17+
use T;
18+
}
19+
20+
function test() {
21+
T::$foo = 42;
22+
var_dump(T::$foo);
23+
T::foo();
24+
T::bar();
25+
echo "\n";
26+
}
27+
28+
// Call twice to test cache slot behavior.
29+
test();
30+
test();
31+
32+
C::$foo = 42;
33+
var_dump(C::$foo);
34+
C::foo();
35+
C::bar();
36+
37+
?>
38+
--EXPECTF--
39+
Deprecated: Accessing static trait property T::$foo is deprecated, it should only be accessed on a class using the trait in %s on line %d
40+
41+
Deprecated: Accessing static trait property T::$foo is deprecated, it should only be accessed on a class using the trait in %s on line %d
42+
int(42)
43+
44+
Deprecated: Calling static trait method T::foo is deprecated, it should only be called on a class using the trait in %s on line %d
45+
Foo
46+
47+
Deprecated: Calling static trait method T::bar is deprecated, it should only be called on a class using the trait in %s on line %d
48+
CallStatic(bar)
49+
50+
51+
Deprecated: Accessing static trait property T::$foo is deprecated, it should only be accessed on a class using the trait in %s on line %d
52+
53+
Deprecated: Accessing static trait property T::$foo is deprecated, it should only be accessed on a class using the trait in %s on line %d
54+
int(42)
55+
56+
Deprecated: Calling static trait method T::foo is deprecated, it should only be called on a class using the trait in %s on line %d
57+
Foo
58+
59+
Deprecated: Calling static trait method T::bar is deprecated, it should only be called on a class using the trait in %s on line %d
60+
CallStatic(bar)
61+
62+
int(42)
63+
Foo
64+
CallStatic(bar)

Zend/tests/type_declarations/typed_properties_043.phpt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,19 @@ Bar::$parentProp = new Foo;
4040
var_dump(Bar::$selfProp, Bar::$selfNullProp, Bar::$parentProp);
4141

4242
?>
43-
--EXPECT--
43+
--EXPECTF--
44+
Deprecated: Accessing static trait property Test::$selfProp is deprecated, it should only be accessed on a class using the trait in %s on line %d
4445
Cannot assign stdClass to property Test::$selfProp of type self
46+
47+
Deprecated: Accessing static trait property Test::$selfNullProp is deprecated, it should only be accessed on a class using the trait in %s on line %d
4548
Cannot assign stdClass to property Test::$selfNullProp of type ?self
49+
50+
Deprecated: Accessing static trait property Test::$parentProp is deprecated, it should only be accessed on a class using the trait in %s on line %d
4651
Cannot assign stdClass to property Test::$parentProp of type parent
52+
53+
Deprecated: Accessing static trait property Test::$selfNullProp is deprecated, it should only be accessed on a class using the trait in %s on line %d
54+
55+
Deprecated: Accessing static trait property Test::$selfNullProp is deprecated, it should only be accessed on a class using the trait in %s on line %d
4756
NULL
4857
object(Bar)#3 (0) {
4958
}

Zend/zend_execute.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3024,7 +3024,8 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval
30243024

30253025
*prop_info = property_info;
30263026

3027-
if (EXPECTED(op1_type == IS_CONST)) {
3027+
if (EXPECTED(op1_type == IS_CONST)
3028+
&& EXPECTED(!(property_info->ce->ce_flags & ZEND_ACC_TRAIT))) {
30283029
CACHE_POLYMORPHIC_PTR(cache_slot, ce, *retval);
30293030
CACHE_PTR(cache_slot + sizeof(void *) * 2, property_info);
30303031
}

Zend/zend_object_handlers.c

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,32 +1307,37 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
13071307
lc_function_name = zend_string_tolower(function_name);
13081308
}
13091309

1310+
zend_function *fbc;
13101311
zval *func = zend_hash_find(&ce->function_table, lc_function_name);
1311-
if (UNEXPECTED(!func)) {
1312-
if (UNEXPECTED(!key)) {
1313-
zend_string_release_ex(lc_function_name, 0);
1314-
}
1315-
return get_static_method_fallback(ce, function_name);
1316-
}
1317-
1318-
zend_function *fbc = Z_FUNC_P(func);
1319-
if (!(fbc->op_array.fn_flags & ZEND_ACC_PUBLIC)) {
1320-
zend_class_entry *scope = zend_get_executed_scope();
1321-
if (UNEXPECTED(fbc->common.scope != scope)) {
1322-
if (UNEXPECTED(fbc->op_array.fn_flags & ZEND_ACC_PRIVATE)
1323-
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), scope))) {
1324-
zend_function *fallback_fbc = get_static_method_fallback(ce, function_name);
1325-
if (!fallback_fbc) {
1326-
zend_bad_method_call(fbc, function_name, scope);
1312+
if (EXPECTED(func)) {
1313+
fbc = Z_FUNC_P(func);
1314+
if (!(fbc->op_array.fn_flags & ZEND_ACC_PUBLIC)) {
1315+
zend_class_entry *scope = zend_get_executed_scope();
1316+
if (UNEXPECTED(fbc->common.scope != scope)) {
1317+
if (UNEXPECTED(fbc->op_array.fn_flags & ZEND_ACC_PRIVATE)
1318+
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), scope))) {
1319+
zend_function *fallback_fbc = get_static_method_fallback(ce, function_name);
1320+
if (!fallback_fbc) {
1321+
zend_bad_method_call(fbc, function_name, scope);
1322+
}
1323+
fbc = fallback_fbc;
13271324
}
1328-
fbc = fallback_fbc;
13291325
}
13301326
}
1327+
} else {
1328+
fbc = get_static_method_fallback(ce, function_name);
13311329
}
13321330

1333-
if (fbc && UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1334-
zend_abstract_method_call(fbc);
1335-
fbc = NULL;
1331+
if (EXPECTED(fbc)) {
1332+
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1333+
zend_abstract_method_call(fbc);
1334+
fbc = NULL;
1335+
} else if (UNEXPECTED(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
1336+
zend_error(E_DEPRECATED,
1337+
"Calling static trait method %s::%s is deprecated, "
1338+
"it should only be called on a class using the trait",
1339+
ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
1340+
}
13361341
}
13371342

13381343
if (UNEXPECTED(!key)) {
@@ -1428,6 +1433,13 @@ ZEND_API zval *zend_std_get_static_property_with_info(zend_class_entry *ce, zend
14281433
return NULL;
14291434
}
14301435

1436+
if (UNEXPECTED(ce->ce_flags & ZEND_ACC_TRAIT)) {
1437+
zend_error(E_DEPRECATED,
1438+
"Accessing static trait property %s::$%s is deprecated, "
1439+
"it should only be accessed on a class using the trait",
1440+
ZSTR_VAL(property_info->ce->name), ZSTR_VAL(property_name));
1441+
}
1442+
14311443
return ret;
14321444
}
14331445
/* }}} */

Zend/zend_vm_def.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3615,7 +3615,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
36153615
HANDLE_EXCEPTION();
36163616
}
36173617
if (OP2_TYPE == IS_CONST &&
3618-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
3618+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
3619+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
36193620
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
36203621
}
36213622
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {

Zend/zend_vm_execute.h

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6812,7 +6812,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
68126812
HANDLE_EXCEPTION();
68136813
}
68146814
if (IS_CONST == IS_CONST &&
6815-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
6815+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
6816+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
68166817
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
68176818
}
68186819
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -9139,7 +9140,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
91399140
HANDLE_EXCEPTION();
91409141
}
91419142
if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
9142-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
9143+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
9144+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
91439145
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
91449146
}
91459147
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -9882,7 +9884,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
98829884
HANDLE_EXCEPTION();
98839885
}
98849886
if (IS_UNUSED == IS_CONST &&
9885-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
9887+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
9888+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
98869889
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
98879890
}
98889891
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -11489,7 +11492,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
1148911492
HANDLE_EXCEPTION();
1149011493
}
1149111494
if (IS_CV == IS_CONST &&
11492-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
11495+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
11496+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
1149311497
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
1149411498
}
1149511499
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -23954,7 +23958,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
2395423958
HANDLE_EXCEPTION();
2395523959
}
2395623960
if (IS_CONST == IS_CONST &&
23957-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
23961+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
23962+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
2395823963
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
2395923964
}
2396023965
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -26494,7 +26499,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
2649426499
HANDLE_EXCEPTION();
2649526500
}
2649626501
if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
26497-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
26502+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
26503+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
2649826504
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
2649926505
}
2650026506
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -27788,7 +27794,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
2778827794
HANDLE_EXCEPTION();
2778927795
}
2779027796
if (IS_UNUSED == IS_CONST &&
27791-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
27797+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
27798+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
2779227799
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
2779327800
}
2779427801
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -30494,7 +30501,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
3049430501
HANDLE_EXCEPTION();
3049530502
}
3049630503
if (IS_CV == IS_CONST &&
30497-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
30504+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
30505+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
3049830506
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
3049930507
}
3050030508
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -32626,7 +32634,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
3262632634
HANDLE_EXCEPTION();
3262732635
}
3262832636
if (IS_CONST == IS_CONST &&
32629-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
32637+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
32638+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
3263032639
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
3263132640
}
3263232641
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -34523,7 +34532,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
3452334532
HANDLE_EXCEPTION();
3452434533
}
3452534534
if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
34526-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
34535+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
34536+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
3452734537
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
3452834538
}
3452934539
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -34937,7 +34947,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
3493734947
HANDLE_EXCEPTION();
3493834948
}
3493934949
if (IS_UNUSED == IS_CONST &&
34940-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
34950+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
34951+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
3494134952
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
3494234953
}
3494334954
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
@@ -37016,7 +37027,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
3701637027
HANDLE_EXCEPTION();
3701737028
}
3701837029
if (IS_CV == IS_CONST &&
37019-
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
37030+
EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
37031+
EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
3702037032
CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
3702137033
}
3702237034
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {

0 commit comments

Comments
 (0)