1 | <?php |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | namespace Stratadox\Di; |
||||||
6 | |||||||
7 | use Psr\Container\ContainerInterface; |
||||||
0 ignored issues
–
show
|
|||||||
8 | use ReflectionClass; |
||||||
9 | |||||||
10 | final class AutoWiring implements ContainerInterface |
||||||
11 | { |
||||||
12 | private $container; |
||||||
13 | private $links; |
||||||
14 | |||||||
15 | private function __construct(ContainerInterface $container, array $links) |
||||||
16 | { |
||||||
17 | $this->container = $container; |
||||||
18 | $this->links = $links; |
||||||
19 | } |
||||||
20 | |||||||
21 | public static function the(ContainerInterface $container) : self |
||||||
22 | { |
||||||
23 | return new self($container, []); |
||||||
24 | } |
||||||
25 | |||||||
26 | public function link(string $interface, string $class) : self |
||||||
27 | { |
||||||
28 | return new self($this->container, [$interface => $class] + $this->links); |
||||||
29 | } |
||||||
30 | |||||||
31 | public function get($theService) |
||||||
32 | { |
||||||
33 | if (!$this->container->has($theService)) { |
||||||
34 | $this->resolve($theService); |
||||||
35 | } |
||||||
36 | return $this->container->get($theService); |
||||||
37 | } |
||||||
38 | |||||||
39 | public function has($theService) : bool |
||||||
40 | { |
||||||
41 | return class_exists($theService) || interface_exists($theService); |
||||||
42 | } |
||||||
43 | |||||||
44 | private function resolve(string $service) |
||||||
45 | { |
||||||
46 | if (interface_exists($service)) { |
||||||
47 | $this->resolveInterface($service); |
||||||
48 | } else { |
||||||
49 | $this->resolveClass($service); |
||||||
50 | } |
||||||
51 | } |
||||||
52 | |||||||
53 | private function resolveInterface(string $service) |
||||||
54 | { |
||||||
55 | $class = $this->links[$service]; |
||||||
56 | $this->resolveClass($class); |
||||||
57 | $this->container->set($service, function () use ($class) { |
||||||
0 ignored issues
–
show
The method
set() does not exist on Psr\Container\ContainerInterface . It seems like you code against a sub-type of Psr\Container\ContainerInterface such as Stratadox\Di\Container .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
58 | return $this->container->get($class); |
||||||
59 | }); |
||||||
60 | } |
||||||
61 | |||||||
62 | private function resolveClass(string $service) |
||||||
63 | { |
||||||
64 | $constructor = (new ReflectionClass($service))->getConstructor(); |
||||||
65 | $dependencies = []; |
||||||
66 | if (isset($constructor)) { |
||||||
67 | foreach ($constructor->getParameters() as $parameter) { |
||||||
68 | $dependency = (string) $parameter->getType(); |
||||||
69 | $this->resolve($dependency); |
||||||
70 | $dependencies[] = $dependency; |
||||||
71 | } |
||||||
72 | } |
||||||
73 | $this->container->set($service, |
||||||
74 | function () use ($service, $dependencies) { |
||||||
75 | $parameters = []; |
||||||
76 | foreach ($dependencies as $dependency) { |
||||||
77 | $parameters[] = $this->container->get($dependency); |
||||||
78 | } |
||||||
79 | return new $service(...$parameters); |
||||||
80 | } |
||||||
81 | ); |
||||||
82 | } |
||||||
83 | } |
||||||
84 |
Let?s assume that you have a directory layout like this:
and let?s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: