Skip to content

Commit ea686cb

Browse files
committed
Lazy objects
1 parent 7d99a9c commit ea686cb

File tree

170 files changed

+10430
-306
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+10430
-306
lines changed

Zend/tests/lazy_objects/003.phpt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
Lazy objects: readonly properties can be lazily initialized
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public readonly int $a;
8+
9+
public function __construct() {
10+
$this->a = 1;
11+
}
12+
}
13+
14+
print "# Ghost:\n";
15+
16+
$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor();
17+
(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) {
18+
var_dump("initializer");
19+
$obj->__construct();
20+
});
21+
22+
var_dump($obj);
23+
var_dump($obj->a);
24+
var_dump($obj);
25+
26+
print "# Virtual:\n";
27+
28+
$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor();
29+
(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) {
30+
var_dump("initializer");
31+
return new C();
32+
});
33+
34+
var_dump($obj);
35+
var_dump($obj->a);
36+
var_dump($obj->a);
37+
var_dump($obj);
38+
39+
--EXPECTF--
40+
# Ghost:
41+
lazy ghost object(C)#%d (0) {
42+
["a"]=>
43+
uninitialized(int)
44+
}
45+
string(11) "initializer"
46+
int(1)
47+
object(C)#%d (1) {
48+
["a"]=>
49+
int(1)
50+
}
51+
# Virtual:
52+
lazy proxy object(C)#%d (0) {
53+
["a"]=>
54+
uninitialized(int)
55+
}
56+
string(11) "initializer"
57+
int(1)
58+
int(1)
59+
lazy proxy object(C)#%d (1) {
60+
["instance"]=>
61+
object(C)#%d (1) {
62+
["a"]=>
63+
int(1)
64+
}
65+
}

Zend/tests/lazy_objects/004.phpt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
Lazy objects: readonly classes can be lazily initialized
3+
--FILE--
4+
<?php
5+
6+
readonly class C {
7+
public int $a;
8+
9+
public function __construct() {
10+
$this->a = 1;
11+
}
12+
}
13+
14+
print "# Ghost:\n";
15+
16+
$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor();
17+
(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) {
18+
var_dump("initializer");
19+
$obj->__construct();
20+
});
21+
22+
var_dump($obj);
23+
var_dump($obj->a);
24+
var_dump($obj);
25+
26+
print "# Virtual:\n";
27+
28+
$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor();
29+
(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) {
30+
var_dump("initializer");
31+
return new C();
32+
});
33+
34+
var_dump($obj);
35+
var_dump($obj->a);
36+
var_dump($obj->a);
37+
var_dump($obj);
38+
39+
--EXPECTF--
40+
# Ghost:
41+
lazy ghost object(C)#%d (0) {
42+
["a"]=>
43+
uninitialized(int)
44+
}
45+
string(11) "initializer"
46+
int(1)
47+
object(C)#%d (1) {
48+
["a"]=>
49+
int(1)
50+
}
51+
# Virtual:
52+
lazy proxy object(C)#%d (0) {
53+
["a"]=>
54+
uninitialized(int)
55+
}
56+
string(11) "initializer"
57+
int(1)
58+
int(1)
59+
lazy proxy object(C)#%d (1) {
60+
["instance"]=>
61+
object(C)#%d (1) {
62+
["a"]=>
63+
int(1)
64+
}
65+
}

Zend/tests/lazy_objects/005.phpt

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
--TEST--
2+
Lazy objects: initializer must return the right type
3+
--FILE--
4+
<?php
5+
6+
class B {
7+
public int $b;
8+
public function __construct() {
9+
$this->b = 1;
10+
}
11+
}
12+
13+
class C extends B {
14+
}
15+
16+
class D extends C {
17+
public int $b; // override
18+
}
19+
20+
class E extends B {
21+
public function __construct() { // override
22+
}
23+
}
24+
25+
print "# Ghost initializer must return NULL or no value:\n";
26+
27+
$obj = (new ReflectionClass(C::class))->newLazyGhost(function ($obj) {
28+
var_dump("initializer");
29+
$obj->__construct();
30+
return new stdClass;
31+
});
32+
33+
var_dump($obj);
34+
try {
35+
var_dump($obj->a);
36+
} catch (\Error $e) {
37+
printf("%s: %s\n", $e::class, $e->getMessage());
38+
}
39+
var_dump($obj);
40+
41+
print "# Virtual initializer must return an instance of a compatible class:\n";
42+
print "## Valid cases:\n";
43+
44+
$tests = [
45+
[C::class, new C()],
46+
[C::class, new B()],
47+
[D::class, new B()],
48+
];
49+
50+
foreach ($tests as [$class, $instance]) {
51+
$reflector = new ReflectionClass($class);
52+
$obj = $reflector->newLazyProxy(function ($obj) use ($instance) {
53+
var_dump("initializer");
54+
$instance->b = 1;
55+
return $instance;
56+
});
57+
58+
printf("## %s vs %s\n", get_class($obj), is_object($instance) ? get_class($instance) : gettype($instance));
59+
var_dump($obj->b);
60+
var_dump($obj);
61+
}
62+
63+
print "## Invalid cases:\n";
64+
65+
$tests = [
66+
[C::class, new stdClass],
67+
[C::class, new DateTime()],
68+
[C::class, null],
69+
[C::class, new D()],
70+
[E::class, new B()],
71+
];
72+
73+
foreach ($tests as [$class, $instance]) {
74+
$obj = (new ReflectionClass($class))->newInstanceWithoutConstructor();
75+
(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) use ($instance) {
76+
var_dump("initializer");
77+
return $instance;
78+
});
79+
80+
try {
81+
printf("## %s vs %s\n", get_class($obj), is_object($instance) ? get_class($instance) : gettype($instance));
82+
var_dump($obj->a);
83+
} catch (\Error $e) {
84+
printf("%s: %s\n", $e::class, $e->getMessage());
85+
}
86+
}
87+
88+
$obj = (new ReflectionClass(C::class))->newLazyProxy(function ($obj) {
89+
var_dump("initializer");
90+
return $obj;
91+
});
92+
93+
try {
94+
printf("## %s vs itself\n", get_class($obj));
95+
var_dump($obj->a);
96+
} catch (\Error $e) {
97+
printf("%s: %s\n", $e::class, $e->getMessage());
98+
}
99+
100+
--EXPECTF--
101+
# Ghost initializer must return NULL or no value:
102+
lazy ghost object(C)#%d (0) {
103+
["b"]=>
104+
uninitialized(int)
105+
}
106+
string(11) "initializer"
107+
TypeError: Lazy object initializer must return NULL or no value
108+
lazy ghost object(C)#%d (0) {
109+
["b"]=>
110+
uninitialized(int)
111+
}
112+
# Virtual initializer must return an instance of a compatible class:
113+
## Valid cases:
114+
## C vs C
115+
string(11) "initializer"
116+
int(1)
117+
lazy proxy object(C)#%d (1) {
118+
["instance"]=>
119+
object(C)#%d (1) {
120+
["b"]=>
121+
int(1)
122+
}
123+
}
124+
## C vs B
125+
string(11) "initializer"
126+
int(1)
127+
lazy proxy object(C)#%d (1) {
128+
["instance"]=>
129+
object(B)#%d (1) {
130+
["b"]=>
131+
int(1)
132+
}
133+
}
134+
## D vs B
135+
string(11) "initializer"
136+
int(1)
137+
lazy proxy object(D)#%d (1) {
138+
["instance"]=>
139+
object(B)#%d (1) {
140+
["b"]=>
141+
int(1)
142+
}
143+
}
144+
## Invalid cases:
145+
## C vs stdClass
146+
string(11) "initializer"
147+
TypeError: The real instance class stdClass is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor, __constructor, or __clone methods.
148+
## C vs DateTime
149+
string(11) "initializer"
150+
TypeError: The real instance class DateTime is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor, __constructor, or __clone methods.
151+
## C vs NULL
152+
string(11) "initializer"
153+
TypeError: The real instance class null is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor, __constructor, or __clone methods.
154+
## C vs D
155+
string(11) "initializer"
156+
TypeError: The real instance class D is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor, __constructor, or __clone methods.
157+
## E vs B
158+
string(11) "initializer"
159+
TypeError: The real instance class B is not compatible with the proxy class E. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor, __constructor, or __clone methods.
160+
## C vs itself
161+
string(11) "initializer"
162+
Error: Lazy proxy factory must return a non-lazy object

Zend/tests/lazy_objects/006.phpt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
Lazy objects: Foreach initializes object
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public int $a;
8+
public function __construct() {
9+
var_dump(__METHOD__);
10+
$this->a = 1;
11+
}
12+
}
13+
14+
print "# Ghost:\n";
15+
16+
$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor();
17+
(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) {
18+
var_dump("initializer");
19+
$obj->__construct();
20+
});
21+
22+
foreach ($obj as $prop => $value) {
23+
var_dump($prop, $value);
24+
}
25+
26+
print "# Virtual:\n";
27+
28+
$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor();
29+
(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) {
30+
var_dump("initializer");
31+
return new C();
32+
});
33+
34+
foreach ($obj as $prop => $value) {
35+
var_dump($prop, $value);
36+
}
37+
38+
--EXPECTF--
39+
# Ghost:
40+
string(11) "initializer"
41+
string(14) "C::__construct"
42+
string(1) "a"
43+
int(1)
44+
# Virtual:
45+
string(11) "initializer"
46+
string(14) "C::__construct"
47+
string(1) "a"
48+
int(1)

0 commit comments

Comments
 (0)