Skip to content

Commit 26f5009

Browse files
committed
Fix lazy proxy calling magic methods twice
Fixes GH-18038 Closes GH-18039
1 parent b6b9e47 commit 26f5009

14 files changed

+503
-21
lines changed

Diff for: NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ PHP NEWS
55
- Core:
66
. Fixed bug GH-17711 and GH-18022 (Infinite recursion on deprecated attribute
77
evaluation). (ilutov)
8+
. Fixed bug GH-18038 (Lazy proxy calls magic methods twice). (Arnaud)
89

910
- Standard:
1011
. Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()).

Diff for: Zend/tests/lazy_objects/gh18038-001.phpt

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GH-18038 001: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class C {
8+
public $_;
9+
public function __set($name, $value) {
10+
var_dump(__METHOD__);
11+
$this->$name = $value * 2;
12+
}
13+
}
14+
15+
$rc = new ReflectionClass(C::class);
16+
17+
$obj = $rc->newLazyProxy(function () {
18+
echo "init\n";
19+
return new C;
20+
});
21+
22+
$obj->prop = 1;
23+
var_dump($obj->prop);
24+
25+
?>
26+
--EXPECT--
27+
string(8) "C::__set"
28+
init
29+
int(2)

Diff for: Zend/tests/lazy_objects/gh18038-002.phpt

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
GH-18038 002: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class RealInstance {
8+
public $_;
9+
public function __set($name, $value) {
10+
global $obj;
11+
var_dump(get_class($this)."::".__FUNCTION__);
12+
$obj->$name = $value * 2;
13+
unset($this->$name);
14+
$this->$name = $value * 2;
15+
}
16+
}
17+
18+
#[AllowDynamicProperties]
19+
class Proxy extends RealInstance {
20+
}
21+
22+
$rc = new ReflectionClass(Proxy::class);
23+
24+
$obj = $rc->newLazyProxy(function () {
25+
echo "init\n";
26+
return new RealInstance;
27+
});
28+
29+
$real = $rc->initializeLazyObject($obj);
30+
$real->prop = 1;
31+
var_dump($obj->prop);
32+
33+
?>
34+
--EXPECT--
35+
init
36+
string(19) "RealInstance::__set"
37+
string(12) "Proxy::__set"
38+
int(2)

Diff for: Zend/tests/lazy_objects/gh18038-003.phpt

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-18038 003: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class C {
8+
public $_;
9+
public function __get($name) {
10+
var_dump(__METHOD__);
11+
return $this->$name;
12+
}
13+
}
14+
15+
$rc = new ReflectionClass(C::class);
16+
17+
$obj = $rc->newLazyProxy(function () {
18+
echo "init\n";
19+
return new C;
20+
});
21+
22+
var_dump($obj->prop);
23+
24+
?>
25+
--EXPECTF--
26+
string(8) "C::__get"
27+
init
28+
29+
Warning: Undefined property: C::$prop in %s on line %d
30+
NULL

Diff for: Zend/tests/lazy_objects/gh18038-004.phpt

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
--TEST--
2+
GH-18038 004: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class RealInstance {
8+
public $_;
9+
public function __get($name) {
10+
global $obj;
11+
var_dump(get_class($this)."::".__FUNCTION__);
12+
var_dump($obj->$name);
13+
return $this->$name;
14+
}
15+
}
16+
17+
#[AllowDynamicProperties]
18+
class Proxy extends RealInstance {
19+
public function __get($name) {
20+
var_dump(get_class($this)."::".__FUNCTION__);
21+
return $this->$name;
22+
}
23+
}
24+
25+
$rc = new ReflectionClass(Proxy::class);
26+
27+
$obj = $rc->newLazyProxy(function () {
28+
echo "init\n";
29+
return new RealInstance;
30+
});
31+
32+
$real = $rc->initializeLazyObject($obj);
33+
var_dump($real->prop);
34+
35+
?>
36+
--EXPECTF--
37+
init
38+
string(19) "RealInstance::__get"
39+
string(12) "Proxy::__get"
40+
41+
Warning: Undefined property: RealInstance::$prop in %s on line %d
42+
NULL
43+
44+
Warning: Undefined property: RealInstance::$prop in %s on line %d
45+
NULL

Diff for: Zend/tests/lazy_objects/gh18038-005.phpt

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-18038 005: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class C {
8+
public $_;
9+
public function __isset($name) {
10+
var_dump(__METHOD__);
11+
return isset($this->$name['']);
12+
}
13+
}
14+
15+
$rc = new ReflectionClass(C::class);
16+
17+
$obj = $rc->newLazyProxy(function () {
18+
echo "init\n";
19+
return new C;
20+
});
21+
22+
var_dump(isset($obj->prop['']));
23+
24+
?>
25+
--EXPECT--
26+
string(10) "C::__isset"
27+
init
28+
bool(false)

Diff for: Zend/tests/lazy_objects/gh18038-006.phpt

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
GH-18038 006: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class C {
8+
public $_;
9+
public function __isset($name) {
10+
var_dump(__METHOD__);
11+
return isset($this->$name['']);
12+
}
13+
public function __get($name) {
14+
var_dump(__METHOD__);
15+
return $this->$name[''];
16+
}
17+
}
18+
19+
$rc = new ReflectionClass(C::class);
20+
21+
$obj = $rc->newLazyProxy(function () {
22+
echo "init\n";
23+
return new C;
24+
});
25+
26+
var_dump(isset($obj->prop['']));
27+
28+
?>
29+
--EXPECTF--
30+
string(10) "C::__isset"
31+
string(8) "C::__get"
32+
init
33+
34+
Warning: Undefined property: C::$prop in %s on line %d
35+
36+
Warning: Trying to access array offset on null in %s on line %d
37+
bool(false)

Diff for: Zend/tests/lazy_objects/gh18038-007.phpt

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
GH-18038 007: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class RealInstance {
8+
public $_;
9+
public function __isset($name) {
10+
global $obj;
11+
var_dump(get_class($this)."::".__FUNCTION__);
12+
var_dump(isset($obj->$name['']));
13+
return isset($this->$name['']);
14+
}
15+
}
16+
17+
#[AllowDynamicProperties]
18+
class Proxy extends RealInstance {
19+
public function __isset($name) {
20+
var_dump(get_class($this)."::".__FUNCTION__);
21+
return isset($this->$name['']);
22+
}
23+
}
24+
25+
$rc = new ReflectionClass(Proxy::class);
26+
27+
$obj = $rc->newLazyProxy(function () {
28+
echo "init\n";
29+
return new RealInstance;
30+
});
31+
32+
$real = $rc->initializeLazyObject($obj);
33+
var_dump(isset($real->prop['']));
34+
35+
?>
36+
--EXPECT--
37+
init
38+
string(21) "RealInstance::__isset"
39+
string(14) "Proxy::__isset"
40+
bool(false)
41+
bool(false)

Diff for: Zend/tests/lazy_objects/gh18038-008.phpt

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-18038 008: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class C {
8+
public $_;
9+
public function __isset($name) {
10+
var_dump(__METHOD__);
11+
return isset($this->$name);
12+
}
13+
}
14+
15+
$rc = new ReflectionClass(C::class);
16+
17+
$obj = $rc->newLazyProxy(function () {
18+
echo "init\n";
19+
return new C;
20+
});
21+
22+
var_dump(isset($obj->prop));
23+
24+
?>
25+
--EXPECT--
26+
string(10) "C::__isset"
27+
init
28+
bool(false)

Diff for: Zend/tests/lazy_objects/gh18038-009.phpt

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
GH-18038 009: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class RealInstance {
8+
public $_;
9+
public function __isset($name) {
10+
global $obj;
11+
var_dump(get_class($this)."::".__FUNCTION__);
12+
var_dump(isset($obj->$name));
13+
return isset($this->$name);
14+
}
15+
}
16+
17+
#[AllowDynamicProperties]
18+
class Proxy extends RealInstance {
19+
public function __isset($name) {
20+
var_dump(get_class($this)."::".__FUNCTION__);
21+
return isset($this->$name);
22+
}
23+
}
24+
25+
$rc = new ReflectionClass(Proxy::class);
26+
27+
$obj = $rc->newLazyProxy(function () {
28+
echo "init\n";
29+
return new RealInstance;
30+
});
31+
32+
$real = $rc->initializeLazyObject($obj);
33+
var_dump(isset($real->prop));
34+
35+
?>
36+
--EXPECT--
37+
init
38+
string(21) "RealInstance::__isset"
39+
string(14) "Proxy::__isset"
40+
bool(false)
41+
bool(false)

Diff for: Zend/tests/lazy_objects/gh18038-010.phpt

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
GH-18038 010: Lazy proxy calls magic methods twice
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class C {
8+
public $_;
9+
public function __unset($name) {
10+
var_dump(__METHOD__);
11+
unset($this->$name);
12+
}
13+
}
14+
15+
$rc = new ReflectionClass(C::class);
16+
17+
$obj = $rc->newLazyProxy(function () {
18+
echo "init\n";
19+
return new C;
20+
});
21+
22+
unset($obj->prop);
23+
var_dump($obj);
24+
25+
?>
26+
--EXPECTF--
27+
string(10) "C::__unset"
28+
init
29+
lazy proxy object(C)#%d (1) {
30+
["instance"]=>
31+
object(C)#%d (1) {
32+
["_"]=>
33+
NULL
34+
}
35+
}

0 commit comments

Comments
 (0)