ReflectionClosure2Test.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. <?php
  2. use Foo\Bar;
  3. // Fake
  4. use Foo\Baz as Qux;
  5. use Laravel\SerializableClosure\Support\ReflectionClosure;
  6. // Dirty CS
  7. define(Bar::class, Bar::class);
  8. use function Foo\f1;
  9. test('resolve arguments', function () {
  10. $f1 = function (Bar $p) {
  11. };
  12. $e1 = 'function (\Foo\Bar $p) {
  13. }';
  14. $f2 = function (Bar\Test $p) {
  15. };
  16. $e2 = 'function (\Foo\Bar\Test $p) {
  17. }';
  18. $f3 = function (Qux $p) {
  19. };
  20. $e3 = 'function (\Foo\Baz $p) {
  21. }';
  22. $f4 = function (Qux\Test $p) {
  23. };
  24. $e4 = 'function (\Foo\Baz\Test $p) {
  25. }';
  26. $f5 = function (array $p, string $x) {
  27. };
  28. $e5 = 'function (array $p, string $x) {
  29. }';
  30. $f6 = function ($a = self::VALUE) {
  31. };
  32. $e6 = 'function ($a = self::VALUE) {
  33. }';
  34. $f7 = function ($a = parent::VALUE) {
  35. };
  36. $e7 = 'function ($a = parent::VALUE) {
  37. }';
  38. $f8 = function ($a = [self::VALUE, parent::VALUE]) {
  39. };
  40. $e8 = 'function ($a = [self::VALUE, parent::VALUE]) {
  41. }';
  42. expect($f1)->toBeCode($e1);
  43. expect($f2)->toBeCode($e2);
  44. expect($f3)->toBeCode($e3);
  45. expect($f4)->toBeCode($e4);
  46. expect($f5)->toBeCode($e5);
  47. expect($f6)->toBeCode($e6);
  48. expect($f7)->toBeCode($e7);
  49. expect($f8)->toBeCode($e8);
  50. });
  51. test('resolve return type', function () {
  52. $f1 = function (): Bar {
  53. };
  54. $e1 = 'function (): \Foo\Bar {
  55. }';
  56. $f2 = function (): Bar\Test {
  57. };
  58. $e2 = 'function (): \Foo\Bar\Test {
  59. }';
  60. $f3 = function (): Qux {
  61. };
  62. $e3 = 'function (): \Foo\Baz {
  63. }';
  64. $f4 = function (): Qux\Test {
  65. };
  66. $e4 = 'function (): \Foo\Baz\Test {
  67. }';
  68. $f5 = function (): \Foo {
  69. };
  70. $e5 = 'function (): \Foo {
  71. }';
  72. $f6 = function (): Foo {
  73. };
  74. $e6 = 'function (): \Foo {
  75. }';
  76. $f7 = function (): array {
  77. };
  78. $e7 = 'function (): array {
  79. }';
  80. $f8 = function (): string {
  81. };
  82. $e8 = 'function (): string {
  83. }';
  84. $f9 = function () {
  85. return Relative\CONST_X + 1;
  86. };
  87. $e9 = 'function () {
  88. return \Relative\CONST_X + 1;
  89. }';
  90. expect($f1)->toBeCode($e1);
  91. expect($f2)->toBeCode($e2);
  92. expect($f3)->toBeCode($e3);
  93. expect($f4)->toBeCode($e4);
  94. expect($f5)->toBeCode($e5);
  95. expect($f6)->toBeCode($e6);
  96. expect($f7)->toBeCode($e7);
  97. expect($f8)->toBeCode($e8);
  98. expect($f9)->toBeCode($e9);
  99. });
  100. test('closure inside closure', function () {
  101. $f1 = function () {
  102. return function ($a): A {
  103. return $a;
  104. };
  105. };
  106. $e1 = 'function () {
  107. return function ($a): \A {
  108. return $a;
  109. };
  110. }';
  111. $f2 = function () {
  112. return function (A $a): A {
  113. return $a;
  114. };
  115. };
  116. $e2 = 'function () {
  117. return function (\A $a): \A {
  118. return $a;
  119. };
  120. }';
  121. expect($f1)->toBeCode($e1);
  122. expect($f2)->toBeCode($e2);
  123. });
  124. test('anonymous inside closure', function () {
  125. $f1 = function () {
  126. return new class() extends A {};
  127. };
  128. $e1 = 'function () {
  129. return new class() extends \A {};
  130. }';
  131. $f2 = function () {
  132. return new class() extends A implements B {};
  133. };
  134. $e2 = 'function () {
  135. return new class() extends \A implements \B {};
  136. }';
  137. $f3 = function () {
  138. return new class()
  139. {
  140. public function x(A $a): B
  141. {
  142. }
  143. };
  144. };
  145. $e3 = 'function () {
  146. return new class()
  147. {
  148. public function x(\A $a): \B
  149. {
  150. }
  151. };
  152. }';
  153. expect($f1)->toBeCode($e1);
  154. expect($f2)->toBeCode($e2);
  155. expect($f3)->toBeCode($e3);
  156. });
  157. test('closure resolve traits names in anonymous classes', function () {
  158. $f1 = function () {
  159. new class()
  160. {
  161. use Bar;
  162. };
  163. };
  164. $e1 = 'function () {
  165. new class()
  166. {
  167. use \Foo\Bar;
  168. };
  169. }';
  170. $f2 = function () {
  171. new class()
  172. {
  173. use Bar\Test;
  174. };
  175. };
  176. $e2 = 'function () {
  177. new class()
  178. {
  179. use \Foo\Bar\Test;
  180. };
  181. }';
  182. $f3 = function () {
  183. new class()
  184. {
  185. use Qux;
  186. };
  187. };
  188. $e3 = 'function () {
  189. new class()
  190. {
  191. use \Foo\Baz;
  192. };
  193. }';
  194. $f4 = function () {
  195. new class()
  196. {
  197. use Qux\Test;
  198. };
  199. };
  200. $e4 = 'function () {
  201. new class()
  202. {
  203. use \Foo\Baz\Test;
  204. };
  205. }';
  206. $f5 = function () {
  207. new class()
  208. {
  209. use \Foo;
  210. };
  211. };
  212. $e5 = 'function () {
  213. new class()
  214. {
  215. use \Foo;
  216. };
  217. }';
  218. $f6 = function () {
  219. new class()
  220. {
  221. use Foo;
  222. };
  223. };
  224. $e6 = 'function () {
  225. new class()
  226. {
  227. use \Foo;
  228. };
  229. }';
  230. $f7 = function () {
  231. new class()
  232. {
  233. use Bar;
  234. };
  235. function a(Qux $q): Bar
  236. {
  237. f1();
  238. $a = new class() extends Bar {};
  239. }
  240. };
  241. $e7 = 'function () {
  242. new class()
  243. {
  244. use \Foo\Bar;
  245. };
  246. function a(\Foo\Baz $q): \Foo\Bar
  247. {
  248. \Foo\f1();
  249. $a = new class() extends \Foo\Bar {};
  250. }
  251. }';
  252. expect($f1)->toBeCode($e1);
  253. expect($f2)->toBeCode($e2);
  254. expect($f3)->toBeCode($e3);
  255. expect($f4)->toBeCode($e4);
  256. expect($f5)->toBeCode($e5);
  257. expect($f6)->toBeCode($e6);
  258. expect($f7)->toBeCode($e7);
  259. });
  260. test('keyword as static method', function () {
  261. $f1 = function () {
  262. Bar::new();
  263. };
  264. $e1 = 'function () {
  265. \Foo\Bar::new();
  266. }';
  267. $f2 = function () {
  268. Bar::__FILE__();
  269. };
  270. $e2 = 'function () {
  271. \Foo\Bar::__FILE__();
  272. }';
  273. $f3 = function () {
  274. Bar::__CLASS__();
  275. };
  276. $e3 = 'function () {
  277. \Foo\Bar::__CLASS__();
  278. }';
  279. $f4 = function () {
  280. Bar::__DIR__();
  281. };
  282. $e4 = 'function () {
  283. \Foo\Bar::__DIR__();
  284. }';
  285. $f5 = function () {
  286. Bar::__FUNCTION__();
  287. };
  288. $e5 = 'function () {
  289. \Foo\Bar::__FUNCTION__();
  290. }';
  291. $f6 = function () {
  292. Bar::__METHOD__();
  293. };
  294. $e6 = 'function () {
  295. \Foo\Bar::__METHOD__();
  296. }';
  297. $f7 = function () {
  298. Bar::function();
  299. };
  300. $e7 = 'function () {
  301. \Foo\Bar::function();
  302. }';
  303. $f8 = function () {
  304. Bar::instanceof();
  305. };
  306. $e8 = 'function () {
  307. \Foo\Bar::instanceof();
  308. }';
  309. $f9 = function () {
  310. Bar::__LINE__();
  311. };
  312. $e9 = 'function () {
  313. \Foo\Bar::__LINE__();
  314. }';
  315. $f10 = function () {
  316. Bar::__NAMESPACE__();
  317. };
  318. $e10 = 'function () {
  319. \Foo\Bar::__NAMESPACE__();
  320. }';
  321. $f11 = function () {
  322. Bar::__TRAIT__();
  323. };
  324. $e11 = 'function () {
  325. \Foo\Bar::__TRAIT__();
  326. }';
  327. $f12 = function () {
  328. Bar::use();
  329. };
  330. $e12 = 'function () {
  331. \Foo\Bar::use();
  332. }';
  333. expect($f1)->toBeCode($e1);
  334. expect($f2)->toBeCode($e2);
  335. expect($f3)->toBeCode($e3);
  336. expect($f4)->toBeCode($e4);
  337. expect($f5)->toBeCode($e5);
  338. expect($f6)->toBeCode($e6);
  339. expect($f7)->toBeCode($e7);
  340. expect($f8)->toBeCode($e8);
  341. expect($f9)->toBeCode($e9);
  342. expect($f10)->toBeCode($e10);
  343. expect($f11)->toBeCode($e11);
  344. expect($f12)->toBeCode($e12);
  345. });
  346. test('this inside anonymous class', function () {
  347. $f1 = function () {
  348. return new class()
  349. {
  350. public function a()
  351. {
  352. $self = $this;
  353. }
  354. };
  355. };
  356. $f2 = function () {
  357. return new class()
  358. {
  359. public function a()
  360. {
  361. $self = $this;
  362. return new class()
  363. {
  364. public function a()
  365. {
  366. $self = $this;
  367. }
  368. };
  369. }
  370. };
  371. };
  372. $f3 = function () {
  373. $self = $this;
  374. return new class()
  375. {
  376. public function a()
  377. {
  378. $self = $this;
  379. }
  380. };
  381. };
  382. $f4 = function () {
  383. return new class()
  384. {
  385. public function a()
  386. {
  387. $self = $this;
  388. }
  389. };
  390. $self = $this;
  391. };
  392. expect((new ReflectionClosure($f1))->isBindingRequired())->toBeFalse();
  393. expect((new ReflectionClosure($f2))->isBindingRequired())->toBeFalse();
  394. expect((new ReflectionClosure($f3))->isBindingRequired())->toBeTrue();
  395. expect((new ReflectionClosure($f4))->isBindingRequired())->toBeTrue();
  396. });
  397. test('is scope required', function () {
  398. $f1 = function () {
  399. static::test();
  400. };
  401. $f2 = function ($x = self::CONST_X) {
  402. };
  403. $f3 = function ($x = parent::CONST_X) {
  404. };
  405. $f4 = function () {
  406. static $i = 1;
  407. };
  408. $f5 = function () {
  409. return function () {
  410. static $i = 0;
  411. };
  412. };
  413. $f6 = function () {
  414. return function () {
  415. static::test();
  416. };
  417. };
  418. $f7 = $f5();
  419. $f8 = $f6();
  420. $f9 = function () {
  421. new static();
  422. };
  423. $f10 = function () {
  424. new self();
  425. };
  426. $f11 = function () {
  427. $a = static function ($retries) {
  428. return 750 * $retries;
  429. };
  430. };
  431. expect((new ReflectionClosure($f1))->isScopeRequired())->toBeTrue();
  432. expect((new ReflectionClosure($f2))->isScopeRequired())->toBeTrue();
  433. expect((new ReflectionClosure($f3))->isScopeRequired())->toBeTrue();
  434. expect((new ReflectionClosure($f4))->isScopeRequired())->toBeFalse();
  435. expect((new ReflectionClosure($f5))->isScopeRequired())->toBeFalse();
  436. expect((new ReflectionClosure($f6))->isScopeRequired())->toBeFalse();
  437. expect((new ReflectionClosure($f7))->isScopeRequired())->toBeFalse();
  438. expect((new ReflectionClosure($f8))->isScopeRequired())->toBeTrue();
  439. expect((new ReflectionClosure($f9))->isScopeRequired())->toBeTrue();
  440. expect((new ReflectionClosure($f10))->isScopeRequired())->toBeTrue();
  441. expect((new ReflectionClosure($f11))->isScopeRequired())->toBeFalse();
  442. });