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