1
|
|
|
<?php
|
2
|
|
|
|
3
|
|
|
namespace Aidphp\Di;
|
4
|
|
|
|
5
|
|
|
use Psr\Container\ContainerInterface;
|
6
|
|
|
use Psr\Container\ContainerExceptionInterface;
|
7
|
|
|
use ReflectionClass;
|
8
|
|
|
use ReflectionMethod;
|
9
|
|
|
use ReflectionException;
|
10
|
|
|
|
11
|
|
|
class Container implements ContainerInterface
|
12
|
|
|
{
|
13
|
|
|
protected $definitions = [];
|
14
|
|
|
protected $factories = [];
|
15
|
|
|
protected $instances = [];
|
16
|
|
|
|
17
|
8 |
|
public function define(string $id, string $class = null, array $params = [], bool $shared = true): self
|
18
|
|
|
{
|
19
|
8 |
|
unset($this->instances[$id], $this->factories[$id]);
|
20
|
8 |
|
$this->definitions[$id] = [$class ?? $id, $params, $shared];
|
21
|
8 |
|
return $this;
|
22
|
|
|
}
|
23
|
|
|
|
24
|
2 |
|
public function delegate(string $id, callable $factory, bool $shared = true): self
|
25
|
|
|
{
|
26
|
2 |
|
unset($this->instances[$id], $this->factories[$id]);
|
27
|
2 |
|
$this->factories[$id] = [$factory, $shared];
|
28
|
2 |
|
return $this;
|
29
|
|
|
}
|
30
|
|
|
|
31
|
24 |
|
public function get($id)
|
32
|
|
|
{
|
33
|
24 |
|
if (isset($this->instances[$id]))
|
34
|
|
|
{
|
35
|
2 |
|
return $this->instances[$id];
|
36
|
|
|
}
|
37
|
|
|
|
38
|
24 |
|
if (! isset($this->factories[$id]))
|
39
|
|
|
{
|
40
|
23 |
|
$this->factories[$id] = isset($this->definitions[$id])
|
41
|
8 |
|
? [$this->createFactory($this->definitions[$id][0], $this->definitions[$id][1]), $this->definitions[$id][2]]
|
42
|
21 |
|
: [$this->createFactory($id), false];
|
43
|
|
|
}
|
44
|
|
|
|
45
|
19 |
|
$instance = $this->factories[$id][0]($this);
|
46
|
|
|
|
47
|
17 |
|
if ($this->factories[$id][1])
|
48
|
|
|
{
|
49
|
8 |
|
$this->instances[$id] = $instance;
|
50
|
|
|
}
|
51
|
|
|
|
52
|
17 |
|
return $instance;
|
53
|
|
|
}
|
54
|
|
|
|
55
|
15 |
|
public function has($id): bool
|
56
|
|
|
{
|
57
|
15 |
|
return isset($this->instances[$id])
|
58
|
15 |
|
|| isset($this->factories[$id])
|
59
|
15 |
|
|| isset($this->definitions[$id])
|
60
|
15 |
|
|| class_exists($id);
|
61
|
|
|
}
|
62
|
|
|
|
63
|
23 |
|
protected function createFactory(string $class, array $params = []): callable
|
64
|
|
|
{
|
65
|
|
|
try
|
66
|
|
|
{
|
67
|
23 |
|
$refClass = new ReflectionClass($class);
|
68
|
|
|
}
|
69
|
1 |
|
catch (ReflectionException $e)
|
70
|
|
|
{
|
71
|
1 |
|
throw new NotFoundException($class);
|
72
|
|
|
}
|
73
|
|
|
|
74
|
22 |
|
if (! $refClass->isInstantiable())
|
75
|
|
|
{
|
76
|
6 |
|
throw new ContainerException('The class "' . $refClass->name . '" can not be instantiate');
|
77
|
|
|
}
|
78
|
|
|
|
79
|
18 |
|
if (null !== ($refMethod = $refClass->getConstructor()))
|
80
|
|
|
{
|
81
|
16 |
|
$resolver = $this->getArgsResolver($refMethod, $params);
|
82
|
|
|
$factory = function ($dic) use ($class, $resolver) {return new $class(...$resolver($dic));};
|
83
|
|
|
}
|
84
|
|
|
else
|
85
|
|
|
{
|
86
|
|
|
$factory = function ($dic) use ($class) {return new $class;};
|
|
|
|
|
87
|
|
|
}
|
88
|
|
|
|
89
|
18 |
|
return $factory;
|
90
|
|
|
}
|
91
|
|
|
|
92
|
16 |
|
protected function getArgsResolver(ReflectionMethod $method, array $params = []): callable
|
93
|
|
|
{
|
94
|
16 |
|
$paramsInfo = [];
|
95
|
|
|
|
96
|
16 |
|
foreach ($method->getParameters() as $param)
|
97
|
|
|
{
|
98
|
15 |
|
$paramsInfo[] = [
|
99
|
15 |
|
($class = $param->getClass()) ? $class->name : null,
|
100
|
15 |
|
$param
|
101
|
|
|
];
|
102
|
|
|
}
|
103
|
|
|
|
104
|
|
|
return function ($dic) use ($paramsInfo, $params) {
|
105
|
16 |
|
$values = [];
|
106
|
|
|
|
107
|
16 |
|
foreach ($paramsInfo as [$class, $param])
|
108
|
|
|
{
|
109
|
15 |
|
if ($class)
|
110
|
|
|
{
|
111
|
|
|
try
|
112
|
|
|
{
|
113
|
11 |
|
$values[] = $dic->get($class);
|
|
|
|
|
114
|
|
|
}
|
115
|
2 |
|
catch (ContainerExceptionInterface $e)
|
116
|
|
|
{
|
117
|
2 |
|
if (! $param->allowsNull())
|
|
|
|
|
118
|
|
|
{
|
119
|
1 |
|
throw new ParameterNotFoundException($param, $e);
|
|
|
|
|
120
|
|
|
}
|
121
|
|
|
|
122
|
10 |
|
$values[] = null;
|
123
|
|
|
}
|
124
|
|
|
}
|
125
|
4 |
|
elseif ($params)
|
|
|
|
|
126
|
|
|
{
|
127
|
1 |
|
$values[] = array_shift($params);
|
128
|
|
|
}
|
129
|
3 |
|
elseif ($param->isOptional())
|
|
|
|
|
130
|
|
|
{
|
131
|
2 |
|
$values[] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
|
|
|
|
|
132
|
|
|
}
|
133
|
|
|
else
|
134
|
|
|
{
|
135
|
1 |
|
throw new ParameterNotFoundException($param);
|
136
|
|
|
}
|
137
|
|
|
}
|
138
|
|
|
|
139
|
14 |
|
return $values;
|
140
|
16 |
|
};
|
141
|
|
|
}
|
142
|
|
|
} |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.