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