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