Skip to content

Commit 8b41bca

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: [ci skip] NEWS for GH-15960 Deny resetting an object as lazy during property iteration Ensure to initialize lazy object in foreach Do not null out obj->properties when resetting object Fix handling of undef property during foreach by ref on hooked class
2 parents 57c4b94 + e02e6be commit 8b41bca

8 files changed

+377
-67
lines changed

Zend/tests/lazy_objects/init_trigger_foreach.phpt

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ Lazy objects: Foreach initializes object
55

66
class C {
77
public int $a;
8+
public int $b;
89
public function __construct() {
910
var_dump(__METHOD__);
1011
$this->a = 1;
12+
$this->b = 2;
1113
}
1214
}
1315

@@ -24,6 +26,17 @@ foreach ($obj as $prop => $value) {
2426
var_dump($prop, $value);
2527
}
2628

29+
print "# Ghost (by ref):\n";
30+
31+
$obj = $reflector->newLazyGhost(function ($obj) {
32+
var_dump("initializer");
33+
$obj->__construct();
34+
});
35+
36+
foreach ($obj as $prop => &$value) {
37+
var_dump($prop, $value);
38+
}
39+
2740
print "# Proxy:\n";
2841

2942
$obj = $reflector->newLazyProxy(function ($obj) {
@@ -35,14 +48,110 @@ foreach ($obj as $prop => $value) {
3548
var_dump($prop, $value);
3649
}
3750

38-
--EXPECTF--
51+
print "# Proxy (by ref):\n";
52+
53+
$obj = $reflector->newLazyProxy(function ($obj) {
54+
var_dump("initializer");
55+
return new C();
56+
});
57+
58+
foreach ($obj as $prop => &$value) {
59+
var_dump($prop, $value);
60+
}
61+
62+
print "# Ghost (init failure)\n";
63+
64+
$fail = true;
65+
$obj = $reflector->newLazyGhost(function ($obj) use (&$fail) {
66+
if ($fail) {
67+
throw new Exception("initializer");
68+
} else {
69+
var_dump("initializer");
70+
$obj->__construct();
71+
}
72+
});
73+
74+
try {
75+
foreach ($obj as $prop => $value) {
76+
var_dump($prop, $value);
77+
}
78+
} catch (Exception $e) {
79+
printf("%s: %s\n", $e::class, $e->getMessage());
80+
}
81+
82+
$fail = false;
83+
foreach ($obj as $prop => $value) {
84+
var_dump($prop, $value);
85+
}
86+
87+
print "# Ghost (init failure, by ref)\n";
88+
89+
$fail = true;
90+
$obj = $reflector->newLazyGhost(function ($obj) use (&$fail) {
91+
if ($fail) {
92+
throw new Exception("initializer");
93+
} else {
94+
var_dump("initializer");
95+
$obj->__construct();
96+
}
97+
});
98+
99+
try {
100+
foreach ($obj as $prop => &$value) {
101+
var_dump($prop, $value);
102+
}
103+
} catch (Exception $e) {
104+
printf("%s: %s\n", $e::class, $e->getMessage());
105+
}
106+
107+
$fail = false;
108+
foreach ($obj as $prop => &$value) {
109+
var_dump($prop, $value);
110+
}
111+
112+
?>
113+
--EXPECT--
39114
# Ghost:
40115
string(11) "initializer"
41116
string(14) "C::__construct"
42117
string(1) "a"
43118
int(1)
119+
string(1) "b"
120+
int(2)
121+
# Ghost (by ref):
122+
string(11) "initializer"
123+
string(14) "C::__construct"
124+
string(1) "a"
125+
int(1)
126+
string(1) "b"
127+
int(2)
44128
# Proxy:
45129
string(11) "initializer"
46130
string(14) "C::__construct"
47131
string(1) "a"
48132
int(1)
133+
string(1) "b"
134+
int(2)
135+
# Proxy (by ref):
136+
string(11) "initializer"
137+
string(14) "C::__construct"
138+
string(1) "a"
139+
int(1)
140+
string(1) "b"
141+
int(2)
142+
# Ghost (init failure)
143+
Exception: initializer
144+
string(11) "initializer"
145+
string(14) "C::__construct"
146+
string(1) "a"
147+
int(1)
148+
string(1) "b"
149+
int(2)
150+
# Ghost (init failure, by ref)
151+
Exception: initializer
152+
string(11) "initializer"
153+
string(14) "C::__construct"
154+
string(1) "a"
155+
int(1)
156+
string(1) "b"
157+
int(2)

Zend/tests/lazy_objects/init_trigger_foreach_hooks.phpt

Lines changed: 103 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,79 @@ Lazy objects: Foreach initializes object
66
#[AllowDynamicProperties]
77
class C {
88
public int $a;
9+
private int $_b;
910
public int $b {
10-
get { return $this->b; }
11-
set(int $value) { $this->b = $value; }
11+
&get { $ref = &$this->_b; return $ref; }
1212
}
13-
public int $c {
14-
get { return $this->a + 2; }
15-
}
16-
public function __construct() {
13+
public function __construct(bool $addDynamic = true) {
1714
var_dump(__METHOD__);
1815
$this->a = 1;
19-
$this->b = 2;
20-
$this->d = 4;
16+
$this->_b = 2;
17+
if ($addDynamic) {
18+
$this->c = 3;
19+
$this->d = 4;
20+
unset($this->c);
21+
}
2122
}
2223
}
2324

2425
$reflector = new ReflectionClass(C::class);
2526

26-
print "# Ghost:\n";
27+
function test(string $name, object $obj) {
28+
printf("# %s:\n", $name);
29+
foreach ($obj as $prop => $value) {
30+
var_dump($prop, $value);
31+
}
32+
foreach ($obj as $prop => &$value) {
33+
var_dump($prop, $value);
34+
}
35+
}
2736

2837
$obj = $reflector->newLazyGhost(function ($obj) {
2938
var_dump("initializer");
3039
$obj->__construct();
3140
});
3241

33-
foreach ($obj as $prop => $value) {
34-
var_dump($prop, $value);
35-
}
42+
test('Ghost', $obj);
43+
44+
$obj = $reflector->newLazyProxy(function ($obj) {
45+
var_dump("initializer");
46+
return new C();
47+
});
48+
49+
test('Proxy', $obj);
3650

37-
print "# Proxy:\n";
51+
$obj = $reflector->newLazyGhost(function ($obj) {
52+
var_dump("initializer");
53+
$obj->__construct(addDynamic: false);
54+
});
55+
56+
test('Ghost (no dynamic)', $obj);
3857

3958
$obj = $reflector->newLazyProxy(function ($obj) {
4059
var_dump("initializer");
60+
return new C(addDynamic: false);
61+
});
62+
63+
test('Proxy (no dynamic)', $obj);
64+
65+
print "# Proxy of proxy (initialization)\n";
66+
67+
$obj = $reflector->newLazyProxy(function ($obj) use (&$obj2, $reflector) {
68+
var_dump("initializer");
69+
return $obj2 = new C();
70+
});
71+
$reflector->initializeLazyObject($obj);
72+
$reflector->resetAsLazyProxy($obj2, function () {
4173
return new C();
4274
});
4375

44-
foreach ($obj as $prop => $value) {
45-
var_dump($prop, $value);
46-
}
76+
test('Proxy of proxy', $obj);
4777

4878
print "# Ghost (init exception):\n";
4979

5080
$obj = $reflector->newLazyGhost(function ($obj) {
51-
throw new \Exception();
81+
throw new \Exception("initializer");
5282
});
5383

5484
try {
@@ -60,7 +90,7 @@ try {
6090
print "# Proxy (init exception):\n";
6191

6292
$obj = $reflector->newLazyProxy(function ($obj) {
63-
throw new \Exception();
93+
throw new \Exception("initializer");
6494
});
6595

6696
try {
@@ -77,8 +107,12 @@ string(1) "a"
77107
int(1)
78108
string(1) "b"
79109
int(2)
80-
string(1) "c"
81-
int(3)
110+
string(1) "d"
111+
int(4)
112+
string(1) "a"
113+
int(1)
114+
string(1) "b"
115+
int(2)
82116
string(1) "d"
83117
int(4)
84118
# Proxy:
@@ -88,9 +122,54 @@ string(1) "a"
88122
int(1)
89123
string(1) "b"
90124
int(2)
91-
string(1) "c"
92-
int(3)
125+
string(1) "d"
126+
int(4)
127+
string(1) "a"
128+
int(1)
129+
string(1) "b"
130+
int(2)
131+
string(1) "d"
132+
int(4)
133+
# Ghost (no dynamic):
134+
string(11) "initializer"
135+
string(14) "C::__construct"
136+
string(1) "a"
137+
int(1)
138+
string(1) "b"
139+
int(2)
140+
string(1) "a"
141+
int(1)
142+
string(1) "b"
143+
int(2)
144+
# Proxy (no dynamic):
145+
string(11) "initializer"
146+
string(14) "C::__construct"
147+
string(1) "a"
148+
int(1)
149+
string(1) "b"
150+
int(2)
151+
string(1) "a"
152+
int(1)
153+
string(1) "b"
154+
int(2)
155+
# Proxy of proxy (initialization)
156+
string(11) "initializer"
157+
string(14) "C::__construct"
158+
# Proxy of proxy:
159+
string(14) "C::__construct"
160+
string(1) "a"
161+
int(1)
162+
string(1) "b"
163+
int(2)
164+
string(1) "d"
165+
int(4)
166+
string(1) "a"
167+
int(1)
168+
string(1) "b"
169+
int(2)
170+
string(1) "d"
171+
int(4)
93172
# Ghost (init exception):
94-
Exception:
173+
Exception: initializer
95174
# Proxy (init exception):
96-
Exception:
175+
Exception: initializer

Zend/tests/lazy_objects/reset_as_lazy_resets_dynamic_props.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ var_dump($obj);
4747
--EXPECTF--
4848
# Ghost:
4949
string(18) "Canary::__destruct"
50-
lazy ghost object(C)#%d (0) {
50+
lazy ghost object(C)#%d (%d) {
5151
}
5252
string(11) "initializer"
5353
object(Canary)#%d (0) {
@@ -62,7 +62,7 @@ object(C)#%d (2) {
6262
# Proxy:
6363
string(18) "Canary::__destruct"
6464
string(18) "Canary::__destruct"
65-
lazy proxy object(C)#%d (0) {
65+
lazy proxy object(C)#%d (%d) {
6666
}
6767
string(11) "initializer"
6868
object(Canary)#%d (0) {

Zend/tests/property_hooks/foreach.phpt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ class ByRef {
2323
}
2424
}
2525
public function __construct() {
26+
$this->undef = 'dynamic';
2627
$this->dynamic = 'dynamic';
28+
unset($this->undef);
2729
}
2830
}
2931

0 commit comments

Comments
 (0)