1--TEST--
2Lazy objects: initializer must return the right type
3--FILE--
4<?php
5
6class B {
7    public int $b;
8    public function __construct() {
9        $this->b = 1;
10    }
11    public function __destruct() {
12    }
13}
14
15class C extends B {
16}
17
18class D extends C {
19    public int $b; // override
20}
21
22class E extends B {
23    public function __destruct() { // override
24    }
25}
26
27$reflector = new ReflectionClass(C::class);
28
29print "# Ghost initializer must return NULL or no value:\n";
30
31$obj = $reflector->newLazyGhost(function ($obj) {
32    var_dump("initializer");
33    $obj->__construct();
34    return new stdClass;
35});
36
37var_dump($obj);
38try {
39    var_dump($obj->a);
40} catch (\Error $e) {
41    printf("%s: %s\n", $e::class, $e->getMessage());
42}
43var_dump($obj);
44
45print "# Proxy initializer must return an instance of a compatible class:\n";
46print "## Valid cases:\n";
47
48$tests = [
49    [C::class, new C()],
50    [C::class, new B()],
51    [D::class, new B()],
52];
53
54foreach ($tests as [$class, $instance]) {
55    $obj = (new ReflectionClass($class))->newLazyProxy(function ($obj) use ($instance) {
56        var_dump("initializer");
57        $instance->b = 1;
58        return $instance;
59    });
60
61    printf("## %s vs %s\n", get_class($obj), is_object($instance) ? get_class($instance) : gettype($instance));
62    var_dump($obj->b);
63    var_dump($obj);
64}
65
66print "## Invalid cases:\n";
67
68$tests = [
69    [C::class, new stdClass],
70    [C::class, new DateTime()],
71    [C::class, null],
72    [C::class, new D()],
73    [E::class, new B()],
74];
75
76foreach ($tests as [$class, $instance]) {
77    $obj = (new ReflectionClass($class))->newLazyProxy(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 = $reflector->newLazyProxy(function ($obj) {
91    var_dump("initializer");
92    return $obj;
93});
94
95try {
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:
104lazy ghost object(C)#%d (0) {
105  ["b"]=>
106  uninitialized(int)
107}
108string(11) "initializer"
109TypeError: Lazy object initializer must return NULL or no value
110lazy ghost object(C)#%d (0) {
111  ["b"]=>
112  uninitialized(int)
113}
114# Proxy initializer must return an instance of a compatible class:
115## Valid cases:
116## C vs C
117string(11) "initializer"
118int(1)
119lazy proxy object(C)#%d (1) {
120  ["instance"]=>
121  object(C)#%d (1) {
122    ["b"]=>
123    int(1)
124  }
125}
126## C vs B
127string(11) "initializer"
128int(1)
129lazy proxy object(C)#%d (1) {
130  ["instance"]=>
131  object(B)#%d (1) {
132    ["b"]=>
133    int(1)
134  }
135}
136## D vs B
137string(11) "initializer"
138int(1)
139lazy 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
148string(11) "initializer"
149TypeError: 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
151string(11) "initializer"
152TypeError: 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
154string(11) "initializer"
155TypeError: Lazy proxy factory must return an instance of a class compatible with C, null returned
156## C vs D
157string(11) "initializer"
158TypeError: 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
160string(11) "initializer"
161TypeError: 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
163string(11) "initializer"
164Error: Lazy proxy factory must return a non-lazy object
165