xref: /PHP-7.4/Zend/tests/closure_061.phpt (revision 78773890)
1--TEST--
2Rebinding of ::getClosure()s
3--FILE--
4<?php
5
6use SplDoublyLinkedList as DLL;
7
8function func($arg) { }
9
10class Cls {
11    public function method() {}
12    public static function staticMethod($arg) {}
13}
14
15class ClsChild extends Cls {}
16
17class ClsUnrelated {}
18
19/* Format: [Function, [Obj, Scope]] */
20$tests = [
21    ['func', [
22        [null,         null],
23        [new Cls,      null],
24        [new Cls,      'Cls'],
25        [null,         'Cls'],
26        [null,         'stdClass'],
27        [new stdClass, null],
28    ]],
29
30    ['strlen', [
31        [null,         null],
32        [new Cls,      null],
33        [new Cls,      'Cls'],
34        [null,         'Cls'],
35        [null,         'stdClass'],
36        [new stdClass, null],
37    ]],
38
39    [['Cls', 'staticMethod'], [
40        [null,   'Cls'],
41        [new Cls, null],
42        [new Cls, 'Cls'],
43        [null,    null],
44        [null,    'ClsChild'],
45        [null,    'ClsUnrelated'],
46    ]],
47
48    [[new Cls, 'method'], [
49        [null,             'Cls'],
50        [new Cls,          'Cls'],
51        [new ClsChild,     'Cls'],
52        [new ClsUnrelated, 'Cls'],
53        [new Cls,          null],
54        [new Cls,          'ClsUnrelated'],
55        [new Cls,          'ClsChild'],
56    ]],
57
58    [[new DLL, 'count'], [
59        [new DLL, DLL::class],
60        [new SplStack, DLL::class],
61        [new ClsUnrelated, DLL::class],
62        [null, null],
63        [null, DLL::class],
64        [new DLL, null],
65        [new DLL, ClsUnrelated::class],
66    ]],
67
68    [function() {}, [
69        [null,         null],
70        [new Cls,      null],
71        [new Cls,      'Cls'],
72        [null,         'Cls'],
73        [null,         'stdClass'],
74        [new stdClass, null],
75    ]],
76];
77
78set_error_handler(function($errno, $errstr) {
79    echo "$errstr\n\n";
80});
81
82foreach ($tests as list($fn, $bindings)) {
83    if (is_array($fn)) {
84        $r = new ReflectionMethod($fn[0], $fn[1]);
85        $c = $r->getClosure(is_object($fn[0]) ? $fn[0] : null);
86        $fnStr = is_object($fn[0]) ? "(new " . get_class($fn[0]) . ")->$fn[1]" : "$fn[0]::$fn[1]";
87    } else {
88        $c = (new ReflectionFunction($fn))->getClosure();
89        $fnStr = $fn;
90    }
91    if ($fn instanceof Closure) {
92        $fnStr = "(function() {})";
93    }
94
95    echo "$fnStr()\n" . str_repeat('-', strlen($fnStr) + 2), "\n\n";
96
97    foreach ($bindings as list($obj, $scope)) {
98        $objStr = $obj ? "new " . get_class($obj) : "null";
99        $scopeStr = $scope ? "$scope::class" : "null";
100        echo "bindTo($objStr, $scopeStr):\n";
101
102        $ret = $c->bindTo($obj, $scope);
103        if ($ret !== null) {
104            echo "Success!\n\n";
105        }
106    }
107}
108
109?>
110--EXPECT--
111func()
112------
113
114bindTo(null, null):
115Success!
116
117bindTo(new Cls, null):
118Success!
119
120bindTo(new Cls, Cls::class):
121Cannot rebind scope of closure created from function
122
123bindTo(null, Cls::class):
124Cannot rebind scope of closure created from function
125
126bindTo(null, stdClass::class):
127Cannot bind closure to scope of internal class stdClass
128
129bindTo(new stdClass, null):
130Success!
131
132strlen()
133--------
134
135bindTo(null, null):
136Success!
137
138bindTo(new Cls, null):
139Success!
140
141bindTo(new Cls, Cls::class):
142Cannot rebind scope of closure created from function
143
144bindTo(null, Cls::class):
145Cannot rebind scope of closure created from function
146
147bindTo(null, stdClass::class):
148Cannot bind closure to scope of internal class stdClass
149
150bindTo(new stdClass, null):
151Success!
152
153Cls::staticMethod()
154-------------------
155
156bindTo(null, Cls::class):
157Success!
158
159bindTo(new Cls, null):
160Cannot bind an instance to a static closure
161
162bindTo(new Cls, Cls::class):
163Cannot bind an instance to a static closure
164
165bindTo(null, null):
166Cannot rebind scope of closure created from method
167
168bindTo(null, ClsChild::class):
169Cannot rebind scope of closure created from method
170
171bindTo(null, ClsUnrelated::class):
172Cannot rebind scope of closure created from method
173
174(new Cls)->method()
175-------------------
176
177bindTo(null, Cls::class):
178Unbinding $this of a method is deprecated
179
180Success!
181
182bindTo(new Cls, Cls::class):
183Success!
184
185bindTo(new ClsChild, Cls::class):
186Success!
187
188bindTo(new ClsUnrelated, Cls::class):
189Cannot bind method Cls::method() to object of class ClsUnrelated
190
191bindTo(new Cls, null):
192Cannot rebind scope of closure created from method
193
194bindTo(new Cls, ClsUnrelated::class):
195Cannot rebind scope of closure created from method
196
197bindTo(new Cls, ClsChild::class):
198Cannot rebind scope of closure created from method
199
200(new SplDoublyLinkedList)->count()
201----------------------------------
202
203bindTo(new SplDoublyLinkedList, SplDoublyLinkedList::class):
204Success!
205
206bindTo(new SplStack, SplDoublyLinkedList::class):
207Success!
208
209bindTo(new ClsUnrelated, SplDoublyLinkedList::class):
210Cannot bind method SplDoublyLinkedList::count() to object of class ClsUnrelated
211
212bindTo(null, null):
213Cannot unbind $this of internal method
214
215bindTo(null, SplDoublyLinkedList::class):
216Cannot unbind $this of internal method
217
218bindTo(new SplDoublyLinkedList, null):
219Cannot rebind scope of closure created from method
220
221bindTo(new SplDoublyLinkedList, ClsUnrelated::class):
222Cannot rebind scope of closure created from method
223
224(function() {})()
225-----------------
226
227bindTo(null, null):
228Success!
229
230bindTo(new Cls, null):
231Success!
232
233bindTo(new Cls, Cls::class):
234Success!
235
236bindTo(null, Cls::class):
237Success!
238
239bindTo(null, stdClass::class):
240Cannot bind closure to scope of internal class stdClass
241
242bindTo(new stdClass, null):
243Success!
244