resolveCallableDependencies()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 10
cts 10
cp 1
rs 9.4555
c 0
b 0
f 0
cc 5
nc 4
nop 1
crap 5
1
<?php declare(strict_types=1);
2
3
namespace Phact\Container\Builder;
4
5
use Closure;
6
use ReflectionClass;
7
use ReflectionException;
8
use ReflectionFunction;
9
use ReflectionFunctionAbstract;
10
use ReflectionMethod;
11
use ReflectionParameter;
12
13
class DependenciesResolver implements DependenciesResolverInterface
14
{
15
    /**
16
     * Constructors dependencies
17
     * @var array
18
     */
19
    protected $constructors = [];
20
21
    /**
22
     * Callable dependencies
23
     * @var array
24
     */
25
    protected $callables = [];
26
27
    /**
28
     * {@inheritDoc}
29
     */
30 26
    public function resolveConstructorDependencies(string $className, ?string $constructMethod = null): array
31
    {
32 26
        $key = $className . ($constructMethod ? '::' . $constructMethod : '');
33 26
        if (!isset($this->constructors[$key])) {
34 26
            $reflection = new ReflectionClass($className);
35 26
            $dependencies = [];
36 26
            if ($constructMethod === null) {
37 23
                $constructor = $reflection->getConstructor();
38
            } else {
39 3
                $constructor = new \ReflectionMethod($className, $constructMethod);
40
            }
41 26
            if ($constructor) {
42 21
                $dependencies = $this->resolveFunctionDependencies($constructor);
43
            }
44 26
            $this->constructors[$key] = $dependencies;
45
        }
46 26
        return $this->constructors[$key];
47
    }
48
49
50
    /**
51
     * {@inheritDoc}
52
     */
53 14
    public function resolveCallableDependencies(callable $callable): array
54
    {
55 14
        is_callable($callable, false, $name);
56 14
        if (!isset($this->callables[$name])) {
57 14
            if (is_array($callable)) {
58 11
                $reflection = new ReflectionMethod($callable[0], $callable[1]);
59 3
            } elseif (is_object($callable) && !$callable instanceof Closure) {
60 1
                $reflection = new ReflectionMethod($callable, '__invoke');
61
            } else {
62 2
                $reflection = new ReflectionFunction($callable);
63
            }
64 14
            $this->callables[$name] = $this->resolveFunctionDependencies($reflection);
65
        }
66 14
        return $this->callables[$name];
67
    }
68
69
    /**
70
     * Fetch dependencies from function by reflection
71
     *
72
     * @param ReflectionFunctionAbstract $reflection
73
     * @return Dependency[] Dependencies
74
     * @throws ReflectionException
75
     */
76 35
    protected function resolveFunctionDependencies(ReflectionFunctionAbstract $reflection): array
77
    {
78 35
        $dependencies = [];
79 35
        foreach ($reflection->getParameters() as $param) {
80 33
            if ($param->isVariadic()) {
81 1
                break;
82
            }
83
84 33
            list($type, $value) = $this->getTypeValueByParameter($param);
85
86 33
            $dependencies[] = new Dependency(
87 33
                $type,
88 33
                $param->name,
89 33
                $value
90
            );
91
        }
92 35
        return $dependencies;
93
    }
94
95
    /**
96
     * @param ReflectionParameter $parameter
97
     * @return array
98
     * @throws ReflectionException
99
     */
100 33
    protected function getTypeValueByParameter(ReflectionParameter $parameter): array
101
    {
102 33
        $value = null;
103 33
        $type = DependencyInterface::TYPE_VALUE;
104
105 33
        if ($c = $parameter->getClass()) {
106 29
            $type = DependencyInterface::TYPE_REQUIRED;
107 29
            if ($parameter->allowsNull()) {
108 6
                $type = DependencyInterface::TYPE_OPTIONAL;
109
            }
110 29
            $value = $c->name;
111 13
        } elseif ($parameter->isDefaultValueAvailable()) {
112 12
            $value = $parameter->getDefaultValue();
113
        }
114 33
        return [$type, $value];
115
    }
116
}
117