Skip to content

Commit 9c08243

Browse files
iliaalarnaud-lb
authored andcommitted
Fix GH-21478: Forward property operations to real instance for initialized lazy proxies
Closes GH-21480
1 parent 455ae28 commit 9c08243

13 files changed

+253
-12
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ PHP NEWS
55
- Core:
66
. Fixed bug GH-19983 (GC assertion failure with fibers, generators and
77
destructors). (iliaal)
8+
. Fixed bug GH-21478 (Forward property operations to real instance for
9+
initialized lazy proxies). (iliaal)
810

911
- DOM:
1012
. Fixed bug GH-21566 (Dom\XMLDocument::C14N() emits duplicate xmlns

Zend/tests/lazy_objects/gh18038-002.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,4 @@ var_dump($obj->prop);
3434
--EXPECT--
3535
init
3636
string(19) "RealInstance::__set"
37-
string(12) "Proxy::__set"
3837
int(2)

Zend/tests/lazy_objects/gh18038-004.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ var_dump($real->prop);
3636
--EXPECTF--
3737
init
3838
string(19) "RealInstance::__get"
39-
string(12) "Proxy::__get"
4039

4140
Warning: Undefined property: RealInstance::$prop in %s on line %d
4241
NULL

Zend/tests/lazy_objects/gh18038-007.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,5 @@ var_dump(isset($real->prop['']));
3636
--EXPECT--
3737
init
3838
string(21) "RealInstance::__isset"
39-
string(14) "Proxy::__isset"
4039
bool(false)
4140
bool(false)

Zend/tests/lazy_objects/gh18038-009.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,5 @@ var_dump(isset($real->prop));
3636
--EXPECT--
3737
init
3838
string(21) "RealInstance::__isset"
39-
string(14) "Proxy::__isset"
4039
bool(false)
4140
bool(false)

Zend/tests/lazy_objects/gh20875.phpt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,6 @@ Warning: Undefined variable $a in %s on line %d
3131

3232
Warning: Undefined variable $v in %s on line %d
3333

34-
Notice: Indirect modification of overloaded property A::$b has no effect in %s on line %d
35-
36-
Warning: Undefined variable $x in %s on line %d
37-
38-
Notice: Object of class stdClass could not be converted to int in %s on line %d
39-
40-
Warning: Undefined variable $v in %s on line %d
41-
4234
Notice: Indirect modification of overloaded property A::$f has no effect in %s on line %d
4335

4436
Fatal error: Uncaught Error: Cannot assign by reference to overloaded object in %s:%d
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-21478: __isset on lazy proxy should not double-invoke when real instance guard is set
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public $_;
8+
9+
public function __isset($name) {
10+
global $proxy;
11+
printf("__isset(\$%s) on %s\n", $name, $this::class);
12+
return isset($proxy->{$name});
13+
}
14+
}
15+
16+
class Bar extends Foo {}
17+
18+
$rc = new ReflectionClass(Bar::class);
19+
$proxy = $rc->newLazyProxy(function () {
20+
echo "Init\n";
21+
return new Foo();
22+
});
23+
24+
$real = $rc->initializeLazyObject($proxy);
25+
isset($real->x);
26+
27+
?>
28+
--EXPECT--
29+
Init
30+
__isset($x) on Foo
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-21478: Proxy's own __get runs when accessed directly (not from real instance)
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
private $_;
8+
9+
public function __get($name) {
10+
echo __CLASS__, " ", $name, "\n";
11+
}
12+
}
13+
14+
class Bar extends Foo {
15+
public function __get($name) {
16+
echo __CLASS__, " ", $name, "\n";
17+
}
18+
}
19+
20+
$rc = new ReflectionClass(Bar::class);
21+
$proxy = $rc->newLazyProxy(function () {
22+
return new Foo();
23+
});
24+
$rc->initializeLazyObject($proxy);
25+
26+
$proxy->x;
27+
28+
?>
29+
--EXPECT--
30+
Bar x
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-21478: No assertion failure when &__get forwards through initialized lazy proxy
3+
--FILE--
4+
<?php
5+
class Foo {
6+
public $_;
7+
8+
public function &__get($name) {
9+
global $proxy;
10+
printf("%s(\$%s) on %s\n", __METHOD__, $name, $this::class);
11+
return $proxy->{$name};
12+
}
13+
}
14+
15+
class Bar extends Foo {}
16+
17+
$rc = new ReflectionClass(Bar::class);
18+
$proxy = $rc->newLazyProxy(function () {
19+
echo "Init\n";
20+
return new Foo();
21+
});
22+
23+
$real = $rc->initializeLazyObject($proxy);
24+
$a = &$real->x;
25+
var_dump($a);
26+
?>
27+
--EXPECTF--
28+
Init
29+
Foo::__get($x) on Foo
30+
31+
Warning: Undefined property: Foo::$x in %s on line %d
32+
NULL
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-21478: __set on lazy proxy should not double-invoke when real instance guard is set
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class Foo {
8+
public $_;
9+
10+
public function __set($name, $value) {
11+
global $proxy;
12+
printf("__set(\$%s) on %s\n", $name, $this::class);
13+
$proxy->{$name} = $value;
14+
}
15+
}
16+
17+
#[AllowDynamicProperties]
18+
class Bar extends Foo {}
19+
20+
$rc = new ReflectionClass(Bar::class);
21+
$proxy = $rc->newLazyProxy(function () {
22+
echo "Init\n";
23+
return new Foo();
24+
});
25+
26+
$real = $rc->initializeLazyObject($proxy);
27+
$real->x = 1;
28+
29+
?>
30+
--EXPECT--
31+
Init
32+
__set($x) on Foo

0 commit comments

Comments
 (0)