ContainerCallTest.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. namespace Illuminate\Tests\Container;
  3. use Closure;
  4. use Error;
  5. use Illuminate\Container\Container;
  6. use Illuminate\Contracts\Container\BindingResolutionException;
  7. use PHPUnit\Framework\TestCase;
  8. use stdClass;
  9. class ContainerCallTest extends TestCase
  10. {
  11. public function testCallWithAtSignBasedClassReferencesWithoutMethodThrowsException()
  12. {
  13. $this->expectException(Error::class);
  14. $this->expectExceptionMessage('Call to undefined function ContainerTestCallStub()');
  15. $container = new Container;
  16. $container->call('ContainerTestCallStub');
  17. }
  18. public function testCallWithAtSignBasedClassReferences()
  19. {
  20. $container = new Container;
  21. $result = $container->call(ContainerTestCallStub::class.'@work', ['foo', 'bar']);
  22. $this->assertEquals(['foo', 'bar'], $result);
  23. $container = new Container;
  24. $result = $container->call(ContainerTestCallStub::class.'@inject');
  25. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  26. $this->assertSame('taylor', $result[1]);
  27. $container = new Container;
  28. $result = $container->call(ContainerTestCallStub::class.'@inject', ['default' => 'foo']);
  29. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  30. $this->assertSame('foo', $result[1]);
  31. $container = new Container;
  32. $result = $container->call(ContainerTestCallStub::class, ['foo', 'bar'], 'work');
  33. $this->assertEquals(['foo', 'bar'], $result);
  34. }
  35. public function testCallWithCallableArray()
  36. {
  37. $container = new Container;
  38. $stub = new ContainerTestCallStub;
  39. $result = $container->call([$stub, 'work'], ['foo', 'bar']);
  40. $this->assertEquals(['foo', 'bar'], $result);
  41. }
  42. public function testCallWithStaticMethodNameString()
  43. {
  44. $container = new Container;
  45. $result = $container->call('Illuminate\Tests\Container\ContainerStaticMethodStub::inject');
  46. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  47. $this->assertSame('taylor', $result[1]);
  48. }
  49. public function testCallWithGlobalMethodName()
  50. {
  51. $container = new Container;
  52. $result = $container->call('Illuminate\Tests\Container\containerTestInject');
  53. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  54. $this->assertSame('taylor', $result[1]);
  55. }
  56. public function testCallWithBoundMethod()
  57. {
  58. $container = new Container;
  59. $container->bindMethod(ContainerTestCallStub::class.'@unresolvable', function ($stub) {
  60. return $stub->unresolvable('foo', 'bar');
  61. });
  62. $result = $container->call(ContainerTestCallStub::class.'@unresolvable');
  63. $this->assertEquals(['foo', 'bar'], $result);
  64. $container = new Container;
  65. $container->bindMethod(ContainerTestCallStub::class.'@unresolvable', function ($stub) {
  66. return $stub->unresolvable('foo', 'bar');
  67. });
  68. $result = $container->call([new ContainerTestCallStub, 'unresolvable']);
  69. $this->assertEquals(['foo', 'bar'], $result);
  70. $container = new Container;
  71. $result = $container->call([new ContainerTestCallStub, 'inject'], ['_stub' => 'foo', 'default' => 'bar']);
  72. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  73. $this->assertSame('bar', $result[1]);
  74. $container = new Container;
  75. $result = $container->call([new ContainerTestCallStub, 'inject'], ['_stub' => 'foo']);
  76. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  77. $this->assertSame('taylor', $result[1]);
  78. }
  79. public function testBindMethodAcceptsAnArray()
  80. {
  81. $container = new Container;
  82. $container->bindMethod([ContainerTestCallStub::class, 'unresolvable'], function ($stub) {
  83. return $stub->unresolvable('foo', 'bar');
  84. });
  85. $result = $container->call(ContainerTestCallStub::class.'@unresolvable');
  86. $this->assertEquals(['foo', 'bar'], $result);
  87. $container = new Container;
  88. $container->bindMethod([ContainerTestCallStub::class, 'unresolvable'], function ($stub) {
  89. return $stub->unresolvable('foo', 'bar');
  90. });
  91. $result = $container->call([new ContainerTestCallStub, 'unresolvable']);
  92. $this->assertEquals(['foo', 'bar'], $result);
  93. }
  94. public function testClosureCallWithInjectedDependency()
  95. {
  96. $container = new Container;
  97. $container->call(function (ContainerCallConcreteStub $stub) {
  98. //
  99. }, ['foo' => 'bar']);
  100. $container->call(function (ContainerCallConcreteStub $stub) {
  101. //
  102. }, ['foo' => 'bar', 'stub' => new ContainerCallConcreteStub]);
  103. }
  104. public function testCallWithDependencies()
  105. {
  106. $container = new Container;
  107. $result = $container->call(function (stdClass $foo, $bar = []) {
  108. return func_get_args();
  109. });
  110. $this->assertInstanceOf(stdClass::class, $result[0]);
  111. $this->assertEquals([], $result[1]);
  112. $result = $container->call(function (stdClass $foo, $bar = []) {
  113. return func_get_args();
  114. }, ['bar' => 'taylor']);
  115. $this->assertInstanceOf(stdClass::class, $result[0]);
  116. $this->assertSame('taylor', $result[1]);
  117. $stub = new ContainerCallConcreteStub;
  118. $result = $container->call(function (stdClass $foo, ContainerCallConcreteStub $bar) {
  119. return func_get_args();
  120. }, [ContainerCallConcreteStub::class => $stub]);
  121. $this->assertInstanceOf(stdClass::class, $result[0]);
  122. $this->assertSame($stub, $result[1]);
  123. /*
  124. * Wrap a function...
  125. */
  126. $result = $container->wrap(function (stdClass $foo, $bar = []) {
  127. return func_get_args();
  128. }, ['bar' => 'taylor']);
  129. $this->assertInstanceOf(Closure::class, $result);
  130. $result = $result();
  131. $this->assertInstanceOf(stdClass::class, $result[0]);
  132. $this->assertSame('taylor', $result[1]);
  133. }
  134. public function testCallWithVariadicDependency()
  135. {
  136. $stub1 = new ContainerCallConcreteStub;
  137. $stub2 = new ContainerCallConcreteStub;
  138. $container = new Container;
  139. $container->bind(ContainerCallConcreteStub::class, function () use ($stub1, $stub2) {
  140. return [
  141. $stub1,
  142. $stub2,
  143. ];
  144. });
  145. $result = $container->call(function (stdClass $foo, ContainerCallConcreteStub ...$bar) {
  146. return func_get_args();
  147. });
  148. $this->assertInstanceOf(stdClass::class, $result[0]);
  149. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[1]);
  150. $this->assertSame($stub1, $result[1]);
  151. $this->assertSame($stub2, $result[2]);
  152. }
  153. public function testCallWithCallableObject()
  154. {
  155. $container = new Container;
  156. $callable = new ContainerCallCallableStub;
  157. $result = $container->call($callable);
  158. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  159. $this->assertSame('jeffrey', $result[1]);
  160. }
  161. public function testCallWithCallableClassString()
  162. {
  163. $container = new Container;
  164. $result = $container->call(ContainerCallCallableClassStringStub::class);
  165. $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]);
  166. $this->assertSame('jeffrey', $result[1]);
  167. $this->assertInstanceOf(ContainerTestCallStub::class, $result[2]);
  168. }
  169. public function testCallWithoutRequiredParamsThrowsException()
  170. {
  171. $this->expectException(BindingResolutionException::class);
  172. $this->expectExceptionMessage('Unable to resolve dependency [Parameter #0 [ <required> $foo ]] in class Illuminate\Tests\Container\ContainerTestCallStub');
  173. $container = new Container;
  174. $container->call(ContainerTestCallStub::class.'@unresolvable');
  175. }
  176. public function testCallWithUnnamedParametersThrowsException()
  177. {
  178. $this->expectException(BindingResolutionException::class);
  179. $this->expectExceptionMessage('Unable to resolve dependency [Parameter #0 [ <required> $foo ]] in class Illuminate\Tests\Container\ContainerTestCallStub');
  180. $container = new Container;
  181. $container->call([new ContainerTestCallStub, 'unresolvable'], ['foo', 'bar']);
  182. }
  183. public function testCallWithoutRequiredParamsOnClosureThrowsException()
  184. {
  185. $this->expectException(BindingResolutionException::class);
  186. $this->expectExceptionMessage('Unable to resolve dependency [Parameter #0 [ <required> $foo ]] in class Illuminate\Tests\Container\ContainerCallTest');
  187. $container = new Container;
  188. $container->call(function ($foo, $bar = 'default') {
  189. return $foo;
  190. });
  191. }
  192. }
  193. class ContainerTestCallStub
  194. {
  195. public function work()
  196. {
  197. return func_get_args();
  198. }
  199. public function inject(ContainerCallConcreteStub $stub, $default = 'taylor')
  200. {
  201. return func_get_args();
  202. }
  203. public function unresolvable($foo, $bar)
  204. {
  205. return func_get_args();
  206. }
  207. }
  208. class ContainerCallConcreteStub
  209. {
  210. //
  211. }
  212. function containerTestInject(ContainerCallConcreteStub $stub, $default = 'taylor')
  213. {
  214. return func_get_args();
  215. }
  216. class ContainerStaticMethodStub
  217. {
  218. public static function inject(ContainerCallConcreteStub $stub, $default = 'taylor')
  219. {
  220. return func_get_args();
  221. }
  222. }
  223. class ContainerCallCallableStub
  224. {
  225. public function __invoke(ContainerCallConcreteStub $stub, $default = 'jeffrey')
  226. {
  227. return func_get_args();
  228. }
  229. }
  230. class ContainerCallCallableClassStringStub
  231. {
  232. public $stub;
  233. public $default;
  234. public function __construct(ContainerCallConcreteStub $stub, $default = 'jeffrey')
  235. {
  236. $this->stub = $stub;
  237. $this->default = $default;
  238. }
  239. public function __invoke(ContainerTestCallStub $dependency)
  240. {
  241. return [$this->stub, $this->default, $dependency];
  242. }
  243. }