[DI] Add hints to exceptions thrown by AutowiringPass
This commit is contained in:
parent
2ad59231c6
commit
d7557cf975
@ -50,13 +50,13 @@ class AutowirePass extends AbstractRecursivePass
|
||||
continue;
|
||||
}
|
||||
|
||||
$classOrInterface = class_exists($type) ? 'class' : 'interface';
|
||||
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$type]);
|
||||
$this->container = $container;
|
||||
$classOrInterface = class_exists($type, false) ? 'class' : 'interface';
|
||||
|
||||
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $type, $id, $classOrInterface, $matchingServices));
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": multiple candidate services exist for %s "%s".%s', $id, $classOrInterface, $type, $this->createTypeAlternatives($type)));
|
||||
}
|
||||
} finally {
|
||||
// Free memory
|
||||
$this->container = null;
|
||||
$this->definedTypes = array();
|
||||
$this->types = null;
|
||||
$this->ambiguousServiceTypes = array();
|
||||
@ -108,7 +108,12 @@ class AutowirePass extends AbstractRecursivePass
|
||||
$this->currentDefinition = $value;
|
||||
|
||||
try {
|
||||
if (!$value->isAutowired() || !$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
|
||||
if (!$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
|
||||
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass()));
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
@ -117,8 +122,6 @@ class AutowirePass extends AbstractRecursivePass
|
||||
|
||||
if ($constructor = $reflectionClass->getConstructor()) {
|
||||
array_unshift($methodCalls, array($constructor->name, $value->getArguments()));
|
||||
} elseif ($value->getArguments()) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": class %s has no constructor but arguments are defined.', $this->currentId, $reflectionClass->name));
|
||||
}
|
||||
|
||||
$methodCalls = $this->autowireCalls($reflectionClass, $methodCalls, $autowiredMethods);
|
||||
@ -203,11 +206,13 @@ class AutowirePass extends AbstractRecursivePass
|
||||
unset($autowiredMethods[$lcMethod]);
|
||||
} else {
|
||||
if (!$reflectionClass->hasMethod($method)) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() does not exist.', $this->currentId, $reflectionClass->name, $method));
|
||||
$class = $reflectionClass->name;
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
}
|
||||
$reflectionMethod = $reflectionClass->getMethod($method);
|
||||
if (!$reflectionMethod->isPublic()) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() must be public.', $this->currentId, $reflectionClass->name, $method));
|
||||
$class = $reflectionClass->name;
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() must be public.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,10 +227,13 @@ class AutowirePass extends AbstractRecursivePass
|
||||
if (!$reflectionMethod->getNumberOfParameters()) {
|
||||
continue; // skip getters
|
||||
}
|
||||
$method = $reflectionMethod->name;
|
||||
|
||||
if (!$reflectionMethod->isPublic()) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() must be public.', $this->currentId, $reflectionClass->name, $reflectionMethod->name));
|
||||
$class = $reflectionClass->name;
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() must be public.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
}
|
||||
$methodCalls[] = array($reflectionMethod->name, $this->autowireMethod($reflectionMethod, array()));
|
||||
$methodCalls[] = array($method, $this->autowireMethod($reflectionMethod, array()));
|
||||
}
|
||||
|
||||
return $methodCalls;
|
||||
@ -244,9 +252,11 @@ class AutowirePass extends AbstractRecursivePass
|
||||
private function autowireMethod(\ReflectionMethod $reflectionMethod, array $arguments)
|
||||
{
|
||||
$isConstructor = $reflectionMethod->isConstructor();
|
||||
$class = $reflectionMethod->class;
|
||||
$method = $reflectionMethod->name;
|
||||
|
||||
if (!$isConstructor && !$arguments && !$reflectionMethod->getNumberOfRequiredParameters()) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() has only optional arguments, thus must be wired explicitly.', $this->currentId, $reflectionMethod->class, $reflectionMethod->name));
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() has only optional arguments, thus must be wired explicitly.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
}
|
||||
|
||||
foreach ($reflectionMethod->getParameters() as $index => $parameter) {
|
||||
@ -265,7 +275,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
if (!$type) {
|
||||
// no default value? Then fail
|
||||
if (!$parameter->isOptional()) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": argument $%s of method %s::%s() must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $reflectionMethod->class, $reflectionMethod->name));
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": argument $%s of method %s() must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
}
|
||||
|
||||
if (!array_key_exists($index, $arguments)) {
|
||||
@ -279,7 +289,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
if ($value = $this->getAutowiredReference($type)) {
|
||||
$this->usedTypes[$type] = $this->currentId;
|
||||
} else {
|
||||
$failureMessage = $this->createTypeNotFoundMessage($type, 'argument $'.$parameter->name.' of method '.$reflectionMethod->class.'::'.$reflectionMethod->name.'()');
|
||||
$failureMessage = $this->createTypeNotFoundMessage($type, sprintf('argument $%s of method %s()', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
$value = $parameter->getDefaultValue();
|
||||
@ -315,14 +325,17 @@ class AutowirePass extends AbstractRecursivePass
|
||||
if (isset($overridenGetters[$lcMethod]) || $reflectionMethod->getNumberOfParameters() || $reflectionMethod->isConstructor()) {
|
||||
continue;
|
||||
}
|
||||
$class = $reflectionMethod->class;
|
||||
$method = $reflectionMethod->name;
|
||||
|
||||
if (!$type = InheritanceProxyHelper::getTypeHint($reflectionMethod, null, true)) {
|
||||
$type = InheritanceProxyHelper::getTypeHint($reflectionMethod);
|
||||
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": getter %s::%s() must%s have its return value be configured explicitly.', $this->currentId, $reflectionMethod->class, $reflectionMethod->name, $type ? '' : ' have a return-type hint or'));
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": getter %s() must%s have its return value be configured explicitly.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method, $type ? '' : ' have a return-type hint or'));
|
||||
}
|
||||
|
||||
if (!$typeRef = $this->getAutowiredReference($type)) {
|
||||
$this->container->log($this, $this->createTypeNotFoundMessage($type, 'return value of method '.$reflectionMethod->class.'::'.$reflectionMethod->name.'()'));
|
||||
$this->container->log($this, $this->createTypeNotFoundMessage($type, sprintf('return value of method %s()', $class !== $this->currentId ? $class.'::'.$method : $method)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -446,15 +459,14 @@ class AutowirePass extends AbstractRecursivePass
|
||||
*/
|
||||
private function createAutowiredDefinition(\ReflectionClass $typeHint)
|
||||
{
|
||||
if (isset($this->ambiguousServiceTypes[$typeHint->name])) {
|
||||
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
|
||||
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$typeHint->name]);
|
||||
if (isset($this->ambiguousServiceTypes[$type = $typeHint->name])) {
|
||||
$classOrInterface = class_exists($type) ? 'class' : 'interface';
|
||||
|
||||
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $this->currentId, $classOrInterface, $matchingServices));
|
||||
throw new RuntimeException(sprintf('Cannot autowire service "%s": multiple candidate services exist for %s "%s".%s', $this->currentId, $classOrInterface, $type, $this->createTypeAlternatives($type)));
|
||||
}
|
||||
|
||||
if (!$typeHint->isInstantiable()) {
|
||||
$this->container->log($this, sprintf('Type "%s" is not instantiable thus cannot be auto-registered for service "%s".', $typeHint->name, $this->currentId));
|
||||
$this->container->log($this, sprintf('Type "%s" is not instantiable thus cannot be auto-registered for service "%s".', $type, $this->currentId));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -463,8 +475,8 @@ class AutowirePass extends AbstractRecursivePass
|
||||
$currentDefinition = $this->currentDefinition;
|
||||
$definitions = $this->container->getDefinitions();
|
||||
$currentId = $this->currentId;
|
||||
$this->currentId = $argumentId = sprintf('autowired.%s', $typeHint->name);
|
||||
$this->currentDefinition = $argumentDefinition = new Definition($typeHint->name);
|
||||
$this->currentId = $argumentId = sprintf('autowired.%s', $type);
|
||||
$this->currentDefinition = $argumentDefinition = new Definition($type);
|
||||
$argumentDefinition->setPublic(false);
|
||||
$argumentDefinition->setAutowired(true);
|
||||
|
||||
@ -475,7 +487,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
$this->container->setDefinition($argumentId, $argumentDefinition);
|
||||
} catch (RuntimeException $e) {
|
||||
// revert any changes done to our internal state
|
||||
unset($this->types[$typeHint->name]);
|
||||
unset($this->types[$type]);
|
||||
$this->ambiguousServiceTypes = $ambiguousServiceTypes;
|
||||
$this->container->setDefinitions($definitions);
|
||||
$this->container->log($this, $e->getMessage());
|
||||
@ -486,7 +498,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
$this->currentDefinition = $currentDefinition;
|
||||
}
|
||||
|
||||
$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $typeHint->name, $this->currentId));
|
||||
$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId));
|
||||
|
||||
return new Reference($argumentId);
|
||||
}
|
||||
@ -494,11 +506,39 @@ class AutowirePass extends AbstractRecursivePass
|
||||
private function createTypeNotFoundMessage($type, $label)
|
||||
{
|
||||
if (!$classOrInterface = class_exists($type, false) ? 'class' : (interface_exists($type, false) ? 'interface' : null)) {
|
||||
return sprintf('Cannot autowire %s for service "%s": Class or interface "%s" does not exist.', $label, $this->currentId, $type);
|
||||
return sprintf('Cannot autowire service "%s": %s has type "%s" but this class does not exist.', $this->currentId, $label, $type);
|
||||
}
|
||||
$message = sprintf('No services were found matching the "%s" %s and it cannot be auto-registered', $type, $classOrInterface);
|
||||
$message = sprintf('no services were found matching the "%s" %s and it cannot be auto-registered for %s.', $type, $classOrInterface, $label);
|
||||
|
||||
return sprintf('Cannot autowire %s for service "%s": %s.', $label, $this->currentId, $message);
|
||||
return sprintf('Cannot autowire service "%s": %s', $this->currentId, $message);
|
||||
}
|
||||
|
||||
private function createTypeAlternatives($type)
|
||||
{
|
||||
$message = ' This type-hint could be aliased to ';
|
||||
|
||||
if (isset($this->ambiguousServiceTypes[$type])) {
|
||||
$message .= sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type]));
|
||||
} elseif (isset($this->types[$type])) {
|
||||
$message .= sprintf('the existing "%s" service', $this->types[$type]);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
$aliases = array();
|
||||
|
||||
foreach (class_parents($type) + class_implements($type) as $parent) {
|
||||
if ($this->container->has($parent)) {
|
||||
$aliases[] = $parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 < count($aliases)) {
|
||||
$message .= sprintf('; or be updated to one of the following: "%s"', implode('", "', $aliases));
|
||||
} elseif ($aliases) {
|
||||
$message .= sprintf('; or be updated to "%s"', $aliases[0]);
|
||||
}
|
||||
|
||||
return $message.'.';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +125,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @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).
|
||||
* @expectedExceptionMessage Cannot autowire service "a": multiple candidate services exist for interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface". This type-hint could be aliased to one of these existing services: "c1", "c2", "c3".
|
||||
*/
|
||||
public function testTypeCollision()
|
||||
{
|
||||
@ -143,7 +143,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @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).
|
||||
* @expectedExceptionMessage Cannot autowire service "a": multiple candidate services exist for class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo". This type-hint could be aliased to one of these existing services: "a1", "a2".
|
||||
*/
|
||||
public function testTypeNotGuessable()
|
||||
{
|
||||
@ -160,7 +160,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @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).
|
||||
* @expectedExceptionMessage Cannot autowire service "a": multiple candidate services exist for class "Symfony\Component\DependencyInjection\Tests\Compiler\A". This type-hint could be aliased to one of these existing services: "a1", "a2".
|
||||
*/
|
||||
public function testTypeNotGuessableWithSubclass()
|
||||
{
|
||||
@ -177,7 +177,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Cannot autowire argument $collision of method Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct() for service "a": No services were found matching the "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" interface and it cannot be auto-registered.
|
||||
* @expectedExceptionMessage Cannot autowire service "a": no services were found matching the "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" interface and it cannot be auto-registered for argument $collision of method Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct().
|
||||
*/
|
||||
public function testTypeNotGuessableNoServicesFound()
|
||||
{
|
||||
@ -295,7 +295,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Cannot autowire argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct() for service "a": Class or interface "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" does not exist.
|
||||
* @expectedExceptionMessage Cannot autowire service "a": argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct() has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.
|
||||
*/
|
||||
public function testClassNotFoundThrowsException()
|
||||
{
|
||||
@ -310,7 +310,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Cannot autowire argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct() for service "a": Class or interface "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" does not exist.
|
||||
* @expectedExceptionMessage Cannot autowire service "a": argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct() has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist.
|
||||
*/
|
||||
public function testParentClassNotFoundThrowsException()
|
||||
{
|
||||
@ -563,7 +563,7 @@ class AutowirePassTest extends TestCase
|
||||
/**
|
||||
* @requires PHP 7.1
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "getter_overriding". Multiple services exist for this class (a1, a2).
|
||||
* @expectedExceptionMessage Cannot autowire service "getter_overriding": multiple candidate services exist for class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo". This type-hint could be aliased to one of these existing services: "a1", "a2".
|
||||
*/
|
||||
public function testGetterOverridingWithAmbiguousServices()
|
||||
{
|
||||
@ -631,7 +631,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "setter_injection_collision". Multiple services exist for this interface (c1, c2).
|
||||
* @expectedExceptionMessage Cannot autowire service "setter_injection_collision": multiple candidate services exist for interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface". This type-hint could be aliased to one of these existing services: "c1", "c2".
|
||||
*/
|
||||
public function testSetterInjectionCollisionThrowsException()
|
||||
{
|
||||
@ -666,7 +666,7 @@ class AutowirePassTest extends TestCase
|
||||
* @dataProvider provideAutodiscoveredAutowiringOrder
|
||||
*
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMEssage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA, autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB).
|
||||
* @expectedExceptionMEssage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for service "a". Multiple services exist for this interface: autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA, autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB.
|
||||
*/
|
||||
public function testAutodiscoveredAutowiringOrder($class)
|
||||
{
|
||||
@ -716,7 +716,7 @@ class AutowirePassTest extends TestCase
|
||||
public function provideNotWireableCalls()
|
||||
{
|
||||
return array(
|
||||
array('setNotAutowireable', 'Cannot autowire argument $n of method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable() for service "foo": Class or interface "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" does not exist.'),
|
||||
array('setNotAutowireable', 'Cannot autowire service "foo": argument $n of method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable() has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.'),
|
||||
array('setBar', 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setBar() has only optional arguments, thus must be wired explicitly.'),
|
||||
array('setOptionalNotAutowireable', 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setOptionalNotAutowireable() has only optional arguments, thus must be wired explicitly.'),
|
||||
array('setOptionalNoTypeHint', 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setOptionalNoTypeHint() has only optional arguments, thus must be wired explicitly.'),
|
||||
@ -737,6 +737,24 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
$this->assertSame(array('service_container', 'e'), array_keys($container->getDefinitions()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Cannot autowire service "j": multiple candidate services exist for class "Symfony\Component\DependencyInjection\Tests\Compiler\I". This type-hint could be aliased to one of these existing services: "f", "i"; or be updated to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface".
|
||||
*/
|
||||
public function testAlternatives()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->setAlias(IInterface::class, 'i');
|
||||
$container->register('f', F::class);
|
||||
$container->register('i', I::class);
|
||||
$container->register('j', J::class)
|
||||
->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
|
||||
class Foo
|
||||
@ -813,6 +831,13 @@ class E
|
||||
}
|
||||
}
|
||||
|
||||
class J
|
||||
{
|
||||
public function __construct(I $i)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
interface CollisionInterface
|
||||
{
|
||||
}
|
||||
|
Reference in New Issue
Block a user