RegularCallableCallFixerTest.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Tests\Fixer\FunctionNotation;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  16. *
  17. * @internal
  18. *
  19. * @covers \PhpCsFixer\Fixer\FunctionNotation\RegularCallableCallFixer
  20. *
  21. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\FunctionNotation\RegularCallableCallFixer>
  22. */
  23. final class RegularCallableCallFixerTest extends AbstractFixerTestCase
  24. {
  25. /**
  26. * @dataProvider provideFixCases
  27. */
  28. public function testFix(string $expected, ?string $input = null): void
  29. {
  30. $this->doTest($expected, $input);
  31. }
  32. /**
  33. * @return iterable<int|string, array{0: string, 1?: string}>
  34. */
  35. public static function provideFixCases(): iterable
  36. {
  37. yield 'call by name - list' => [
  38. '<?php
  39. dont_touch_me(1, 2);
  40. foo();
  41. foo();
  42. call_user_func("foo" . "bar"); // not (yet?) supported by Fixer, possible since PHP 7+
  43. var_dump(1, 2);
  44. Bar\Baz::d(1, 2);
  45. \Bar\Baz::d(1, 2);',
  46. '<?php
  47. dont_touch_me(1, 2);
  48. call_user_func(\'foo\');
  49. call_user_func("foo");
  50. call_user_func("foo" . "bar"); // not (yet?) supported by Fixer, possible since PHP 7+
  51. call_user_func("var_dump", 1, 2);
  52. call_user_func("Bar\Baz::d", 1, 2);
  53. call_user_func("\Bar\Baz::d", 1, 2);',
  54. ];
  55. yield 'call by name - array' => [
  56. '<?php Bar\Baz::d(...[1, 2]);',
  57. '<?php call_user_func_array("Bar\Baz::d", [1, 2]);',
  58. ];
  59. yield 'call by array-as-name, not supported' => [
  60. '<?php
  61. call_user_func(array("Bar\baz", "myCallbackMethod"), 1, 2);
  62. call_user_func(["Bar\baz", "myCallbackMethod"], 1, 2);
  63. call_user_func([$obj, "myCallbackMethod"], 1, 2);
  64. call_user_func([$obj, $cb."Method"], 1, 2);
  65. call_user_func(array(__NAMESPACE__ ."Foo", "test"), 1, 2);
  66. call_user_func(array("Foo", "parent::method"), 1, 2); // no way to convert `parent::`
  67. ',
  68. ];
  69. yield 'call by variable' => [
  70. '<?php
  71. $c(1, 2);
  72. $a["b"]["c"](1, 2);
  73. ',
  74. '<?php
  75. call_user_func($c, 1, 2);
  76. call_user_func($a["b"]["c"], 1, 2);
  77. ',
  78. ];
  79. yield 'call with comments' => [
  80. '<?php
  81. dont_touch_me(/* a */1, 2/** b */);
  82. foo();
  83. foo(/* a */1, 2/** b */);
  84. foo(/* a *//** b *//** c */1/** d */,/** e */ 2);
  85. call_user_func("foo" . "bar"); // not (yet?) supported by Fixer, possible since PHP 7+
  86. var_dump(1, /*
  87. aaa
  88. */ 2);
  89. var_dump(3 /*
  90. aaa
  91. */, 4);
  92. Bar\Baz::d(1, 2);
  93. \Bar\Baz::d(1, 2);',
  94. '<?php
  95. dont_touch_me(/* a */1, 2/** b */);
  96. call_user_func(\'foo\');
  97. call_user_func("foo", /* a */1, 2/** b */);
  98. call_user_func("foo"/* a *//** b */, /** c */1/** d */,/** e */ 2);
  99. call_user_func("foo" . "bar"); // not (yet?) supported by Fixer, possible since PHP 7+
  100. call_user_func("var_dump", 1, /*
  101. aaa
  102. */ 2);
  103. call_user_func("var_dump", 3 /*
  104. aaa
  105. */, 4);
  106. call_user_func("Bar\Baz::d", 1, 2);
  107. call_user_func("\Bar\Baz::d", 1, 2);',
  108. ];
  109. yield 'single var' => [
  110. '<?php $foo() ?>',
  111. '<?php \call_user_func($foo) ?>',
  112. ];
  113. yield 'unsafe repeated variable' => [
  114. '<?php call_user_func($foo, $foo = "bar");',
  115. ];
  116. yield 'call by property' => [
  117. '<?php
  118. ($f->c)(1, 2);
  119. ($f->{c})(1, 2);
  120. ($x["y"]->c)(1, 2);
  121. ($x["y"]->{"c"})(1, 2);
  122. ',
  123. '<?php
  124. call_user_func($f->c, 1, 2);
  125. call_user_func($f->{c}, 1, 2);
  126. call_user_func($x["y"]->c, 1, 2);
  127. call_user_func($x["y"]->{"c"}, 1, 2);
  128. ',
  129. ];
  130. yield 'call by anon-function' => [
  131. '<?php
  132. (function ($a, $b) { var_dump($a, $b); })(1, 2);
  133. (static function ($a, $b) { var_dump($a, $b); })(1, 2);
  134. ',
  135. '<?php
  136. call_user_func(function ($a, $b) { var_dump($a, $b); }, 1, 2);
  137. call_user_func(static function ($a, $b) { var_dump($a, $b); }, 1, 2);
  138. ',
  139. ];
  140. yield 'complex cases' => [
  141. '<?php
  142. call_user_func(\'a\'.$a.$b, 1, 2);
  143. ($a/**/.$b)(1, 2);
  144. (function (){})();
  145. ($a["b"]["c"]->a)(1, 2, 3, 4);
  146. ($a::$b)(1, 2);
  147. ($a[1]::$b[2][3])([&$c], array(&$d));
  148. ',
  149. '<?php
  150. call_user_func(\'a\'.$a.$b, 1, 2);
  151. call_user_func($a/**/.$b, 1, 2);
  152. \call_user_func(function (){});
  153. call_user_func($a["b"]["c"]->a, 1, 2, 3, 4);
  154. call_user_func($a::$b, 1, 2);
  155. call_user_func($a[1]::$b[2][3], [&$c], array(&$d));
  156. ',
  157. ];
  158. yield [
  159. '<?php ($a(1, 2))([&$x], array(&$z));',
  160. '<?php call_user_func($a(1, 2), [&$x], array(&$z));',
  161. ];
  162. yield 'redeclare/override' => [
  163. '<?php
  164. if (!function_exists("call_user_func")) {
  165. function call_user_func($foo){}
  166. }
  167. ',
  168. ];
  169. yield 'function name with escaped slash' => [
  170. '<?php \pack(...$args);',
  171. '<?php call_user_func_array("\\\pack", $args);',
  172. ];
  173. yield 'function call_user_func_array with leading slash' => [
  174. '<?php \pack(...$args);',
  175. '<?php \call_user_func_array("\\\pack", $args);',
  176. ];
  177. yield 'function call_user_func_array caps' => [
  178. '<?php \pack(...$args);',
  179. '<?php \CALL_USER_FUNC_ARRAY("\\\pack", $args);',
  180. ];
  181. yield [
  182. '<?php foo(1,);',
  183. '<?php call_user_func("foo", 1,);',
  184. ];
  185. yield 'empty string double quote' => [
  186. '<?php call_user_func("", 1,);',
  187. ];
  188. yield 'empty string single quote' => [
  189. '<?php call_user_func(\' \', 1,);',
  190. ];
  191. yield 'string with padding' => [
  192. '<?php call_user_func(" padded ", 1,);',
  193. ];
  194. yield 'binary string lower double quote' => [
  195. '<?php call_user_func(b"foo", 1,);',
  196. ];
  197. yield 'binary string upper single quote' => [
  198. '<?php call_user_func(B"foo", 1,);',
  199. ];
  200. yield 'static property as first argument' => [
  201. '<?php
  202. class Foo {
  203. public static $factory;
  204. public static function createFromFactory(...$args) {
  205. return call_user_func_array(static::$factory, $args);
  206. }
  207. }',
  208. ];
  209. }
  210. /**
  211. * @dataProvider provideFixPre80Cases
  212. *
  213. * @requires PHP <8.0
  214. */
  215. public function testFixPre80(string $expected, ?string $input = null): void
  216. {
  217. $this->doTest($expected, $input);
  218. }
  219. /**
  220. * @return iterable<array{string, 1?: string}>
  221. */
  222. public static function provideFixPre80Cases(): iterable
  223. {
  224. yield 'call by variable' => [
  225. '<?php
  226. $a{"b"}{"c"}(1, 2);
  227. ',
  228. '<?php
  229. call_user_func($a{"b"}{"c"}, 1, 2);
  230. ',
  231. ];
  232. }
  233. /**
  234. * @dataProvider provideFix81Cases
  235. *
  236. * @requires PHP 8.1
  237. */
  238. public function testFix81(string $expected, ?string $input = null): void
  239. {
  240. $this->doTest($expected, $input);
  241. }
  242. /**
  243. * @return iterable<array{string}>
  244. */
  245. public static function provideFix81Cases(): iterable
  246. {
  247. yield [
  248. '<?php \call_user_func(...) ?>',
  249. ];
  250. }
  251. }