Reflector::getDependenciesFromParameters()   B
last analyzed

Complexity

Conditions 9
Paths 3

Size

Total Lines 30
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 30
rs 8.0555
c 0
b 0
f 0
cc 9
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Reflection\Reflector;
15
16
use Closure;
17
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use ReflectionClass;
19
use ReflectionClassConstant;
20
use ReflectionFunction;
21
use ReflectionFunctionAbstract;
22
use ReflectionMethod;
23
use ReflectionNamedType;
24
use ReflectionParameter;
25
use ReflectionProperty;
26
use UnitEnum;
0 ignored issues
show
Bug introduced by
The type UnitEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use Valkyrja\Reflection\Reflector\Contract\ReflectorContract as Contract;
28
use Valkyrja\Reflection\Throwable\Exception\RuntimeException;
29
30
use function class_exists;
31
use function interface_exists;
32
use function is_callable;
33
34
class Reflector implements Contract
35
{
36
    /**
37
     * Cached reflection classes.
38
     *
39
     * @var array<string, ReflectionClass>
40
     */
41
    protected array $classReflections = [];
42
43
    /**
44
     * Cached reflection classes.
45
     *
46
     * @var array<string, ReflectionClassConstant>
47
     */
48
    protected array $constantReflections = [];
49
50
    /**
51
     * Cached reflection classes.
52
     *
53
     * @var array<string, ReflectionProperty>
54
     */
55
    protected array $propertyReflections = [];
56
57
    /**
58
     * Cached reflection classes.
59
     *
60
     * @var array<string, ReflectionMethod>
61
     */
62
    protected array $methodReflections = [];
63
64
    /**
65
     * Cached reflection classes.
66
     *
67
     * @var array<string, ReflectionFunction>
68
     */
69
    protected array $functionReflections = [];
70
71
    /**
72
     * @inheritDoc
73
     */
74
    #[Override]
75
    public function forClass(string $class): ReflectionClass
76
    {
77
        $index = $class;
78
79
        return $this->classReflections[$index]
80
            ??= new ReflectionClass($class);
81
    }
82
83
    /**
84
     * @inheritDoc
85
     */
86
    #[Override]
87
    public function forClassConstant(string $class, string $const): ReflectionClassConstant
88
    {
89
        $index = $class . $const;
90
91
        return $this->constantReflections[$index]
92
            ??= $this->forClass($class)->getReflectionConstant($const)
93
            ?: throw new RuntimeException("Failed to retrieve constant $const for $class");
94
    }
95
96
    /**
97
     * @inheritDoc
98
     */
99
    #[Override]
100
    public function forClassProperty(string $class, string $property): ReflectionProperty
101
    {
102
        $index = $class . $property;
103
104
        return $this->propertyReflections[$index]
105
            ??= $this->forClass($class)->getProperty($property);
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111
    #[Override]
112
    public function forClassMethod(string $class, string $method): ReflectionMethod
113
    {
114
        $index = $class . $method;
115
116
        return $this->methodReflections[$index]
117
            ??= $this->forClass($class)->getMethod($method);
118
    }
119
120
    /**
121
     * @inheritDoc
122
     */
123
    #[Override]
124
    public function forFunction(string $function): ReflectionFunction
125
    {
126
        $index = $function;
127
128
        return $this->functionReflections[$index]
129
            ??= new ReflectionFunction($function);
130
    }
131
132
    /**
133
     * @inheritDoc
134
     */
135
    #[Override]
136
    public function forClosure(Closure $closure): ReflectionFunction
137
    {
138
        return new ReflectionFunction($closure);
139
    }
140
141
    /**
142
     * @inheritDoc
143
     */
144
    #[Override]
145
    public function getDependencies(ReflectionFunctionAbstract $reflection): array
146
    {
147
        return $this->getDependenciesFromParameters(...$reflection->getParameters());
148
    }
149
150
    /**
151
     * @inheritDoc
152
     */
153
    #[Override]
154
    public function getDependenciesFromParameters(ReflectionParameter ...$parameters): array
155
    {
156
        // Setup to find any injectable objects through the service container
157
        $dependencies = [];
158
159
        // Iterate through the method's parameters
160
        foreach ($parameters as $parameter) {
161
            $type = $parameter->getType();
162
163
            if (
164
                // The type is a ReflectionNamedType
165
                $type instanceof ReflectionNamedType
166
                // The name is valid
167
                && ($name = $type->getName())
168
                // The name is not a callable
169
                && ! is_callable($name)
170
                // The class or interface exists
171
                && (class_exists($name) || interface_exists($name))
172
                // and it isn't an enum
173
                && ! is_a($name, UnitEnum::class, true)
174
                // It's not built in
175
                && ! $type->isBuiltin()
176
            ) {
177
                // Set the injectable in the array
178
                $dependencies[$parameter->getName()] = $name;
179
            }
180
        }
181
182
        return $dependencies;
183
    }
184
}
185