Skip to content

Commit 9a250cc

Browse files
committed
Add separate static property through trait if parent already declares it
Fixes GH-10935 Closes GH-10937
1 parent ebf86d2 commit 9a250cc

File tree

5 files changed

+101
-2
lines changed

5 files changed

+101
-2
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ PHP NEWS
2929
(ilutov)
3030
. Fix bug GH-10168, GH-10582 (Various segfaults with destructors and VM return
3131
values). (dstogov, nielsdos, ilutov)
32+
. Fix bug GH-10935 (Use of trait doesn't redeclare static property if class
33+
has inherited it from its parent). (ilutov)
3234

3335
- Date:
3436
. Implement More Appropriate Date/Time Exceptions RFC. (Derick)

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ PHP 8.3 UPGRADE NOTES
3535
proc_get_status() to check whether the result was cached.
3636
. Zend Max Execution Timers is now enabled by default for ZTS builds on
3737
Linux.
38+
. Uses of traits with static properties will now redeclare static properties
39+
inherited from the parent class. This will create a separate static property
40+
storage for the current class. This is analogous to adding the static
41+
property to the class directly without traits.
3842

3943
- FFI:
4044
. C functions that have a return type of void now return null instead of

Zend/tests/gh10935.phpt

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
--TEST--
2+
GH-1093: Add separate static property through trait if parent already declares it
3+
--FILE--
4+
<?php
5+
trait Foo {
6+
static $test;
7+
8+
public static function getFooSelf() {
9+
return self::$test;
10+
}
11+
12+
public static function getFooStatic() {
13+
return static::$test;
14+
}
15+
}
16+
trait Bar {
17+
public static function getBarSelf() {
18+
return self::$test;
19+
}
20+
21+
public static function getBarStatic() {
22+
return static::$test;
23+
}
24+
}
25+
26+
class A {
27+
use Foo;
28+
use Bar;
29+
30+
public static function getASelf() {
31+
return self::$test;
32+
}
33+
34+
public static function getAStatic() {
35+
return static::$test;
36+
}
37+
}
38+
39+
class B extends A {
40+
use Foo;
41+
42+
public static function getBSelf() {
43+
return self::$test;
44+
}
45+
46+
public static function getBStatic() {
47+
return static::$test;
48+
}
49+
}
50+
51+
A::$test = 'A';
52+
B::$test = 'B';
53+
54+
echo 'A::$test: ' . A::$test . "\n";
55+
echo 'A::getASelf(): ' . A::getASelf() . "\n";
56+
echo 'A::getAStatic(): ' . A::getAStatic() . "\n";
57+
echo 'A::getFooSelf(): ' . A::getFooSelf() . "\n";
58+
echo 'A::getFooStatic(): ' . A::getFooStatic() . "\n";
59+
echo 'B::$test: ' . B::$test . "\n";
60+
echo 'B::getASelf(): ' . B::getASelf() . "\n";
61+
echo 'B::getAStatic(): ' . B::getAStatic() . "\n";
62+
echo 'B::getBSelf(): ' . B::getBSelf() . "\n";
63+
echo 'B::getBStatic(): ' . B::getBStatic() . "\n";
64+
echo 'B::getFooSelf(): ' . B::getFooSelf() . "\n";
65+
echo 'B::getFooStatic(): ' . B::getFooStatic() . "\n";
66+
echo 'B::getBarSelf(): ' . B::getBarSelf() . "\n";
67+
echo 'B::getBarStatic(): ' . B::getBarStatic() . "\n";
68+
?>
69+
--EXPECT--
70+
A::$test: A
71+
A::getASelf(): A
72+
A::getAStatic(): A
73+
A::getFooSelf(): A
74+
A::getFooStatic(): A
75+
B::$test: B
76+
B::getASelf(): A
77+
B::getAStatic(): B
78+
B::getBSelf(): B
79+
B::getBStatic(): B
80+
B::getFooSelf(): B
81+
B::getFooStatic(): B
82+
B::getBarSelf(): A
83+
B::getBarStatic(): B

Zend/zend_inheritance.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2377,7 +2377,9 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent
23772377
ZSTR_VAL(prop_name),
23782378
ZSTR_VAL(ce->name));
23792379
}
2380-
continue;
2380+
if (!(flags & ZEND_ACC_STATIC)) {
2381+
continue;
2382+
}
23812383
}
23822384
}
23832385

ext/opcache/zend_persist.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,15 @@ void zend_update_parent_ce(zend_class_entry *ce)
10821082
end = parent->parent ? parent->parent->default_static_members_count : 0;
10831083
for (; i >= end; i--) {
10841084
zval *p = &ce->default_static_members_table[i];
1085-
ZVAL_INDIRECT(p, &parent->default_static_members_table[i]);
1085+
/* The static property may have been overridden by a trait
1086+
* during inheritance. In that case, the property default
1087+
* value is replaced by zend_declare_typed_property() at the
1088+
* property index of the parent property. Make sure we only
1089+
* point to the parent property value if the child value was
1090+
* already indirect. */
1091+
if (Z_TYPE_P(p) == IS_INDIRECT) {
1092+
ZVAL_INDIRECT(p, &parent->default_static_members_table[i]);
1093+
}
10861094
}
10871095

10881096
parent = parent->parent;

0 commit comments

Comments
 (0)