Skip to content

Commit 5fe6e82

Browse files
committed
Lazy objects
1 parent 1fbb666 commit 5fe6e82

File tree

161 files changed

+10434
-59
lines changed

Some content is hidden

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

161 files changed

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