AutowirePassTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Tests\Compiler;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
  13. use Symfony\Component\DependencyInjection\ContainerBuilder;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. /**
  16. * @author Kévin Dunglas <dunglas@gmail.com>
  17. */
  18. class AutowirePassTest extends TestCase
  19. {
  20. public function testProcess()
  21. {
  22. $container = new ContainerBuilder();
  23. $container->register('foo', __NAMESPACE__.'\Foo');
  24. $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
  25. $barDefinition->setAutowired(true);
  26. $pass = new AutowirePass();
  27. $pass->process($container);
  28. $this->assertCount(1, $container->getDefinition('bar')->getArguments());
  29. $this->assertEquals('foo', (string) $container->getDefinition('bar')->getArgument(0));
  30. }
  31. public function testProcessAutowireParent()
  32. {
  33. $container = new ContainerBuilder();
  34. $container->register('b', __NAMESPACE__.'\B');
  35. $cDefinition = $container->register('c', __NAMESPACE__.'\C');
  36. $cDefinition->setAutowired(true);
  37. $pass = new AutowirePass();
  38. $pass->process($container);
  39. $this->assertCount(1, $container->getDefinition('c')->getArguments());
  40. $this->assertEquals('b', (string) $container->getDefinition('c')->getArgument(0));
  41. }
  42. public function testProcessAutowireInterface()
  43. {
  44. $container = new ContainerBuilder();
  45. $container->register('f', __NAMESPACE__.'\F');
  46. $gDefinition = $container->register('g', __NAMESPACE__.'\G');
  47. $gDefinition->setAutowired(true);
  48. $pass = new AutowirePass();
  49. $pass->process($container);
  50. $this->assertCount(3, $container->getDefinition('g')->getArguments());
  51. $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(0));
  52. $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(1));
  53. $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(2));
  54. }
  55. public function testCompleteExistingDefinition()
  56. {
  57. $container = new ContainerBuilder();
  58. $container->register('b', __NAMESPACE__.'\B');
  59. $container->register('f', __NAMESPACE__.'\F');
  60. $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b'));
  61. $hDefinition->setAutowired(true);
  62. $pass = new AutowirePass();
  63. $pass->process($container);
  64. $this->assertCount(2, $container->getDefinition('h')->getArguments());
  65. $this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0));
  66. $this->assertEquals('f', (string) $container->getDefinition('h')->getArgument(1));
  67. }
  68. public function testCompleteExistingDefinitionWithNotDefinedArguments()
  69. {
  70. $container = new ContainerBuilder();
  71. $container->register('b', __NAMESPACE__.'\B');
  72. $container->register('f', __NAMESPACE__.'\F');
  73. $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument('');
  74. $hDefinition->setAutowired(true);
  75. $pass = new AutowirePass();
  76. $pass->process($container);
  77. $this->assertCount(2, $container->getDefinition('h')->getArguments());
  78. $this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0));
  79. $this->assertEquals('f', (string) $container->getDefinition('h')->getArgument(1));
  80. }
  81. /**
  82. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  83. * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (c1, c2, c3).
  84. */
  85. public function testTypeCollision()
  86. {
  87. $container = new ContainerBuilder();
  88. $container->register('c1', __NAMESPACE__.'\CollisionA');
  89. $container->register('c2', __NAMESPACE__.'\CollisionB');
  90. $container->register('c3', __NAMESPACE__.'\CollisionB');
  91. $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
  92. $aDefinition->setAutowired(true);
  93. $pass = new AutowirePass();
  94. $pass->process($container);
  95. }
  96. /**
  97. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  98. * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Multiple services exist for this class (a1, a2).
  99. */
  100. public function testTypeNotGuessable()
  101. {
  102. $container = new ContainerBuilder();
  103. $container->register('a1', __NAMESPACE__.'\Foo');
  104. $container->register('a2', __NAMESPACE__.'\Foo');
  105. $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument');
  106. $aDefinition->setAutowired(true);
  107. $pass = new AutowirePass();
  108. $pass->process($container);
  109. }
  110. /**
  111. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  112. * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Multiple services exist for this class (a1, a2).
  113. */
  114. public function testTypeNotGuessableWithSubclass()
  115. {
  116. $container = new ContainerBuilder();
  117. $container->register('a1', __NAMESPACE__.'\B');
  118. $container->register('a2', __NAMESPACE__.'\B');
  119. $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgumentForSubclass');
  120. $aDefinition->setAutowired(true);
  121. $pass = new AutowirePass();
  122. $pass->process($container);
  123. }
  124. /**
  125. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  126. * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". No services were found matching this interface and it cannot be auto-registered.
  127. */
  128. public function testTypeNotGuessableNoServicesFound()
  129. {
  130. $container = new ContainerBuilder();
  131. $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
  132. $aDefinition->setAutowired(true);
  133. $pass = new AutowirePass();
  134. $pass->process($container);
  135. }
  136. public function testTypeNotGuessableWithTypeSet()
  137. {
  138. $container = new ContainerBuilder();
  139. $container->register('a1', __NAMESPACE__.'\Foo');
  140. $container->register('a2', __NAMESPACE__.'\Foo');
  141. $container->register('a3', __NAMESPACE__.'\Foo')->addAutowiringType(__NAMESPACE__.'\Foo');
  142. $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument');
  143. $aDefinition->setAutowired(true);
  144. $pass = new AutowirePass();
  145. $pass->process($container);
  146. $this->assertCount(1, $container->getDefinition('a')->getArguments());
  147. $this->assertEquals('a3', (string) $container->getDefinition('a')->getArgument(0));
  148. }
  149. public function testWithTypeSet()
  150. {
  151. $container = new ContainerBuilder();
  152. $container->register('c1', __NAMESPACE__.'\CollisionA');
  153. $container->register('c2', __NAMESPACE__.'\CollisionB')->addAutowiringType(__NAMESPACE__.'\CollisionInterface');
  154. $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
  155. $aDefinition->setAutowired(true);
  156. $pass = new AutowirePass();
  157. $pass->process($container);
  158. $this->assertCount(1, $container->getDefinition('a')->getArguments());
  159. $this->assertEquals('c2', (string) $container->getDefinition('a')->getArgument(0));
  160. }
  161. public function testCreateDefinition()
  162. {
  163. $container = new ContainerBuilder();
  164. $coopTilleulsDefinition = $container->register('coop_tilleuls', __NAMESPACE__.'\LesTilleuls');
  165. $coopTilleulsDefinition->setAutowired(true);
  166. $pass = new AutowirePass();
  167. $pass->process($container);
  168. $this->assertCount(2, $container->getDefinition('coop_tilleuls')->getArguments());
  169. $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas', $container->getDefinition('coop_tilleuls')->getArgument(0));
  170. $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas', $container->getDefinition('coop_tilleuls')->getArgument(1));
  171. $dunglasDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas');
  172. $this->assertEquals(__NAMESPACE__.'\Dunglas', $dunglasDefinition->getClass());
  173. $this->assertFalse($dunglasDefinition->isPublic());
  174. $this->assertCount(1, $dunglasDefinition->getArguments());
  175. $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\lille', $dunglasDefinition->getArgument(0));
  176. $lilleDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille');
  177. $this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass());
  178. }
  179. public function testResolveParameter()
  180. {
  181. $container = new ContainerBuilder();
  182. $container->setParameter('class_name', __NAMESPACE__.'\Foo');
  183. $container->register('foo', '%class_name%');
  184. $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
  185. $barDefinition->setAutowired(true);
  186. $pass = new AutowirePass();
  187. $pass->process($container);
  188. $this->assertEquals('foo', $container->getDefinition('bar')->getArgument(0));
  189. }
  190. public function testOptionalParameter()
  191. {
  192. $container = new ContainerBuilder();
  193. $container->register('a', __NAMESPACE__.'\A');
  194. $container->register('foo', __NAMESPACE__.'\Foo');
  195. $optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter');
  196. $optDefinition->setAutowired(true);
  197. $pass = new AutowirePass();
  198. $pass->process($container);
  199. $definition = $container->getDefinition('opt');
  200. $this->assertNull($definition->getArgument(0));
  201. $this->assertEquals('a', $definition->getArgument(1));
  202. $this->assertEquals('foo', $definition->getArgument(2));
  203. }
  204. public function testDontTriggerAutowiring()
  205. {
  206. $container = new ContainerBuilder();
  207. $container->register('foo', __NAMESPACE__.'\Foo');
  208. $container->register('bar', __NAMESPACE__.'\Bar');
  209. $pass = new AutowirePass();
  210. $pass->process($container);
  211. $this->assertCount(0, $container->getDefinition('bar')->getArguments());
  212. }
  213. /**
  214. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  215. * @expectedExceptionMessage Cannot autowire argument 2 for Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument because the type-hinted class does not exist (Class Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass does not exist).
  216. */
  217. public function testClassNotFoundThrowsException()
  218. {
  219. $container = new ContainerBuilder();
  220. $aDefinition = $container->register('a', __NAMESPACE__.'\BadTypeHintedArgument');
  221. $aDefinition->setAutowired(true);
  222. $pass = new AutowirePass();
  223. $pass->process($container);
  224. }
  225. /**
  226. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  227. * @expectedExceptionMessage Cannot autowire argument 2 for Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument because the type-hinted class does not exist (Class Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass does not exist).
  228. */
  229. public function testParentClassNotFoundThrowsException()
  230. {
  231. $container = new ContainerBuilder();
  232. $aDefinition = $container->register('a', __NAMESPACE__.'\BadParentTypeHintedArgument');
  233. $aDefinition->setAutowired(true);
  234. $pass = new AutowirePass();
  235. $pass->process($container);
  236. }
  237. public function testDontUseAbstractServices()
  238. {
  239. $container = new ContainerBuilder();
  240. $container->register('abstract_foo', __NAMESPACE__.'\Foo')->setAbstract(true);
  241. $container->register('foo', __NAMESPACE__.'\Foo');
  242. $container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true);
  243. $pass = new AutowirePass();
  244. $pass->process($container);
  245. $arguments = $container->getDefinition('bar')->getArguments();
  246. $this->assertSame('foo', (string) $arguments[0]);
  247. }
  248. public function testSomeSpecificArgumentsAreSet()
  249. {
  250. $container = new ContainerBuilder();
  251. $container->register('foo', __NAMESPACE__.'\Foo');
  252. $container->register('a', __NAMESPACE__.'\A');
  253. $container->register('dunglas', __NAMESPACE__.'\Dunglas');
  254. $container->register('multiple', __NAMESPACE__.'\MultipleArguments')
  255. ->setAutowired(true)
  256. // set the 2nd (index 1) argument only: autowire the first and third
  257. // args are: A, Foo, Dunglas
  258. ->setArguments(array(
  259. 1 => new Reference('foo'),
  260. ));
  261. $pass = new AutowirePass();
  262. $pass->process($container);
  263. $definition = $container->getDefinition('multiple');
  264. $this->assertEquals(
  265. array(
  266. new Reference('a'),
  267. new Reference('foo'),
  268. new Reference('dunglas'),
  269. ),
  270. $definition->getArguments()
  271. );
  272. }
  273. /**
  274. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  275. * @expectedExceptionMessage Unable to autowire argument index 1 ($foo) for the service "arg_no_type_hint". If this is an object, give it a type-hint. Otherwise, specify this argument's value explicitly.
  276. */
  277. public function testScalarArgsCannotBeAutowired()
  278. {
  279. $container = new ContainerBuilder();
  280. $container->register('a', __NAMESPACE__.'\A');
  281. $container->register('dunglas', __NAMESPACE__.'\Dunglas');
  282. $container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
  283. ->setAutowired(true);
  284. $pass = new AutowirePass();
  285. $pass->process($container);
  286. $container->getDefinition('arg_no_type_hint');
  287. }
  288. /**
  289. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  290. * @expectedExceptionMessage Unable to autowire argument index 1 ($foo) for the service "not_really_optional_scalar". If this is an object, give it a type-hint. Otherwise, specify this argument's value explicitly.
  291. */
  292. public function testOptionalScalarNotReallyOptionalThrowException()
  293. {
  294. $container = new ContainerBuilder();
  295. $container->register('a', __NAMESPACE__.'\A');
  296. $container->register('lille', __NAMESPACE__.'\Lille');
  297. $container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional')
  298. ->setAutowired(true);
  299. $pass = new AutowirePass();
  300. $pass->process($container);
  301. }
  302. public function testOptionalScalarArgsDontMessUpOrder()
  303. {
  304. $container = new ContainerBuilder();
  305. $container->register('a', __NAMESPACE__.'\A');
  306. $container->register('lille', __NAMESPACE__.'\Lille');
  307. $container->register('with_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalar')
  308. ->setAutowired(true);
  309. $pass = new AutowirePass();
  310. $pass->process($container);
  311. $definition = $container->getDefinition('with_optional_scalar');
  312. $this->assertEquals(
  313. array(
  314. new Reference('a'),
  315. // use the default value
  316. 'default_val',
  317. new Reference('lille'),
  318. ),
  319. $definition->getArguments()
  320. );
  321. }
  322. public function testOptionalScalarArgsNotPassedIfLast()
  323. {
  324. $container = new ContainerBuilder();
  325. $container->register('a', __NAMESPACE__.'\A');
  326. $container->register('lille', __NAMESPACE__.'\Lille');
  327. $container->register('with_optional_scalar_last', __NAMESPACE__.'\MultipleArgumentsOptionalScalarLast')
  328. ->setAutowired(true);
  329. $pass = new AutowirePass();
  330. $pass->process($container);
  331. $definition = $container->getDefinition('with_optional_scalar_last');
  332. $this->assertEquals(
  333. array(
  334. new Reference('a'),
  335. new Reference('lille'),
  336. ),
  337. $definition->getArguments()
  338. );
  339. }
  340. public function testIgnoreServiceWithClassNotExisting()
  341. {
  342. $container = new ContainerBuilder();
  343. $container->register('class_not_exist', __NAMESPACE__.'\OptionalServiceClass');
  344. $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
  345. $barDefinition->setAutowired(true);
  346. $pass = new AutowirePass();
  347. $pass->process($container);
  348. $this->assertTrue($container->hasDefinition('bar'));
  349. }
  350. public function testProcessDoesNotTriggerDeprecations()
  351. {
  352. $container = new ContainerBuilder();
  353. $container->register('deprecated', 'Symfony\Component\DependencyInjection\Tests\Fixtures\DeprecatedClass')->setDeprecated(true);
  354. $container->register('foo', __NAMESPACE__.'\Foo');
  355. $container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true);
  356. $pass = new AutowirePass();
  357. $pass->process($container);
  358. $this->assertTrue($container->hasDefinition('deprecated'));
  359. $this->assertTrue($container->hasDefinition('foo'));
  360. $this->assertTrue($container->hasDefinition('bar'));
  361. }
  362. public function testEmptyStringIsKept()
  363. {
  364. $container = new ContainerBuilder();
  365. $container->register('a', __NAMESPACE__.'\A');
  366. $container->register('lille', __NAMESPACE__.'\Lille');
  367. $container->register('foo', __NAMESPACE__.'\MultipleArgumentsOptionalScalar')
  368. ->setAutowired(true)
  369. ->setArguments(array('', ''));
  370. $pass = new AutowirePass();
  371. $pass->process($container);
  372. $this->assertEquals(array(new Reference('a'), '', new Reference('lille')), $container->getDefinition('foo')->getArguments());
  373. }
  374. public function provideAutodiscoveredAutowiringOrder()
  375. {
  376. return array(
  377. array('CannotBeAutowiredForwardOrder'),
  378. array('CannotBeAutowiredReverseOrder'),
  379. );
  380. }
  381. /**
  382. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  383. * @expectedExceptionMessage Service "a" can use either autowiring or a factory, not both.
  384. */
  385. public function testWithFactory()
  386. {
  387. $container = new ContainerBuilder();
  388. $container->register('a', __NAMESPACE__.'\A')
  389. ->setFactory('foo')
  390. ->setAutowired(true);
  391. $pass = new AutowirePass();
  392. $pass->process($container);
  393. }
  394. }
  395. class Foo
  396. {
  397. }
  398. class Bar
  399. {
  400. public function __construct(Foo $foo)
  401. {
  402. }
  403. }
  404. class A
  405. {
  406. }
  407. class B extends A
  408. {
  409. }
  410. class C
  411. {
  412. public function __construct(A $a)
  413. {
  414. }
  415. }
  416. interface DInterface
  417. {
  418. }
  419. interface EInterface extends DInterface
  420. {
  421. }
  422. interface IInterface
  423. {
  424. }
  425. class I implements IInterface
  426. {
  427. }
  428. class F extends I implements EInterface
  429. {
  430. }
  431. class G
  432. {
  433. public function __construct(DInterface $d, EInterface $e, IInterface $i)
  434. {
  435. }
  436. }
  437. class H
  438. {
  439. public function __construct(B $b, DInterface $d)
  440. {
  441. }
  442. }
  443. interface CollisionInterface
  444. {
  445. }
  446. class CollisionA implements CollisionInterface
  447. {
  448. }
  449. class CollisionB implements CollisionInterface
  450. {
  451. }
  452. class CannotBeAutowired
  453. {
  454. public function __construct(CollisionInterface $collision)
  455. {
  456. }
  457. }
  458. class CannotBeAutowiredForwardOrder
  459. {
  460. public function __construct(CollisionA $a, CollisionInterface $b, CollisionB $c)
  461. {
  462. }
  463. }
  464. class CannotBeAutowiredReverseOrder
  465. {
  466. public function __construct(CollisionA $a, CollisionB $c, CollisionInterface $b)
  467. {
  468. }
  469. }
  470. class Lille
  471. {
  472. }
  473. class Dunglas
  474. {
  475. public function __construct(Lille $l)
  476. {
  477. }
  478. }
  479. class LesTilleuls
  480. {
  481. public function __construct(Dunglas $j, Dunglas $k)
  482. {
  483. }
  484. }
  485. class OptionalParameter
  486. {
  487. public function __construct(CollisionInterface $c = null, A $a, Foo $f = null)
  488. {
  489. }
  490. }
  491. class BadTypeHintedArgument
  492. {
  493. public function __construct(Dunglas $k, NotARealClass $r)
  494. {
  495. }
  496. }
  497. class BadParentTypeHintedArgument
  498. {
  499. public function __construct(Dunglas $k, OptionalServiceClass $r)
  500. {
  501. }
  502. }
  503. class NotGuessableArgument
  504. {
  505. public function __construct(Foo $k)
  506. {
  507. }
  508. }
  509. class NotGuessableArgumentForSubclass
  510. {
  511. public function __construct(A $k)
  512. {
  513. }
  514. }
  515. class MultipleArguments
  516. {
  517. public function __construct(A $k, $foo, Dunglas $dunglas)
  518. {
  519. }
  520. }
  521. class MultipleArgumentsOptionalScalar
  522. {
  523. public function __construct(A $a, $foo = 'default_val', Lille $lille = null)
  524. {
  525. }
  526. }
  527. class MultipleArgumentsOptionalScalarLast
  528. {
  529. public function __construct(A $a, Lille $lille, $foo = 'some_val')
  530. {
  531. }
  532. }
  533. class MultipleArgumentsOptionalScalarNotReallyOptional
  534. {
  535. public function __construct(A $a, $foo = 'default_val', Lille $lille)
  536. {
  537. }
  538. }