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):
178Cannot unbind $this of method
179
180bindTo(new Cls, Cls::class):
181Success!
182
183bindTo(new ClsChild, Cls::class):
184Success!
185
186bindTo(new ClsUnrelated, Cls::class):
187Cannot bind method Cls::method() to object of class ClsUnrelated
188
189bindTo(new Cls, null):
190Cannot rebind scope of closure created from method
191
192bindTo(new Cls, ClsUnrelated::class):
193Cannot rebind scope of closure created from method
194
195bindTo(new Cls, ClsChild::class):
196Cannot rebind scope of closure created from method
197
198(new SplDoublyLinkedList)->count()
199----------------------------------
200
201bindTo(new SplDoublyLinkedList, SplDoublyLinkedList::class):
202Success!
203
204bindTo(new SplStack, SplDoublyLinkedList::class):
205Success!
206
207bindTo(new ClsUnrelated, SplDoublyLinkedList::class):
208Cannot bind method SplDoublyLinkedList::count() to object of class ClsUnrelated
209
210bindTo(null, null):
211Cannot unbind $this of method
212
213bindTo(null, SplDoublyLinkedList::class):
214Cannot unbind $this of method
215
216bindTo(new SplDoublyLinkedList, null):
217Cannot rebind scope of closure created from method
218
219bindTo(new SplDoublyLinkedList, ClsUnrelated::class):
220Cannot rebind scope of closure created from method
221
222(function() {})()
223-----------------
224
225bindTo(null, null):
226Success!
227
228bindTo(new Cls, null):
229Success!
230
231bindTo(new Cls, Cls::class):
232Success!
233
234bindTo(null, Cls::class):
235Success!
236
237bindTo(null, stdClass::class):
238Cannot bind closure to scope of internal class stdClass
239
240bindTo(new stdClass, null):
241Success!
242