1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace Ray\Di; |
||||
6 | |||||
7 | use Ray\Di\Di\Named; |
||||
8 | use Ray\Di\Di\Qualifier; |
||||
9 | use ReflectionAttribute; |
||||
10 | use ReflectionClass; |
||||
11 | use ReflectionException; |
||||
12 | use ReflectionMethod; |
||||
13 | use ReflectionParameter; |
||||
14 | |||||
15 | use function class_exists; |
||||
16 | use function explode; |
||||
17 | use function get_class; |
||||
18 | use function is_string; |
||||
19 | use function preg_match; |
||||
20 | use function substr; |
||||
21 | use function trim; |
||||
22 | |||||
23 | /** |
||||
24 | * @psalm-import-type ParameterNameMapping from Types |
||||
25 | */ |
||||
26 | final class Name |
||||
27 | { |
||||
28 | /** |
||||
29 | * 'Unnamed' name |
||||
30 | */ |
||||
31 | public const ANY = ''; |
||||
32 | |||||
33 | /** @var string */ |
||||
34 | private $name = ''; |
||||
35 | |||||
36 | /** |
||||
37 | * Named database |
||||
38 | * |
||||
39 | * format: array<varName, NamedName> |
||||
40 | * |
||||
41 | * @var ParameterNameMapping |
||||
0 ignored issues
–
show
|
|||||
42 | */ |
||||
43 | private $names; |
||||
44 | |||||
45 | /** |
||||
46 | * @param string|ParameterNameMapping|null $name |
||||
47 | */ |
||||
48 | public function __construct($name = null) |
||||
49 | { |
||||
50 | if ($name === null) { |
||||
51 | return; |
||||
52 | } |
||||
53 | |||||
54 | if (is_string($name)) { |
||||
55 | $this->setName($name); |
||||
56 | |||||
57 | return; |
||||
58 | } |
||||
59 | |||||
60 | $this->names = $name; |
||||
61 | } |
||||
62 | |||||
63 | /** |
||||
64 | * Create instance from PHP8 attributes |
||||
65 | * |
||||
66 | * psalm does not know ReflectionAttribute?? PHPStan produces no type error here. |
||||
67 | */ |
||||
68 | public static function withAttributes(ReflectionMethod $method): ?self |
||||
69 | { |
||||
70 | $params = $method->getParameters(); |
||||
71 | $names = []; |
||||
72 | foreach ($params as $param) { |
||||
73 | /** @var array<ReflectionAttribute> $attributes */ |
||||
74 | $attributes = $param->getAttributes(); |
||||
75 | if ($attributes) { |
||||
0 ignored issues
–
show
The expression
$attributes of type ReflectionAttribute[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
76 | $name = self::getName($attributes); |
||||
77 | $names[$param->name] = $name; |
||||
78 | } |
||||
79 | } |
||||
80 | |||||
81 | if ($names) { |
||||
82 | return new self($names); |
||||
0 ignored issues
–
show
$names of type array is incompatible with the type Ray\Di\ParameterNameMapping|null|string expected by parameter $name of Ray\Di\Name::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
83 | } |
||||
84 | |||||
85 | return null; |
||||
86 | } |
||||
87 | |||||
88 | /** |
||||
89 | * @param non-empty-array<ReflectionAttribute> $attributes |
||||
0 ignored issues
–
show
|
|||||
90 | * |
||||
91 | * @throws ReflectionException |
||||
92 | * |
||||
93 | * @psalm-suppress MixedAssignment |
||||
94 | * @psalm-suppress MixedArgument |
||||
95 | */ |
||||
96 | private static function getName(array $attributes): string |
||||
97 | { |
||||
98 | $refAttribute = $attributes[0]; |
||||
99 | $attribute = $refAttribute->newInstance(); |
||||
100 | if ($attribute instanceof Named) { |
||||
101 | return $attribute->value; |
||||
102 | } |
||||
103 | |||||
104 | $isQualifier = (bool) (new ReflectionClass($attribute))->getAttributes(Qualifier::class); |
||||
105 | if ($isQualifier) { |
||||
106 | return get_class($attribute); |
||||
107 | } |
||||
108 | |||||
109 | return ''; |
||||
110 | } |
||||
111 | |||||
112 | public function __invoke(ReflectionParameter $parameter): string |
||||
113 | { |
||||
114 | // single variable named binding |
||||
115 | if ($this->name) { |
||||
116 | return $this->name; |
||||
117 | } |
||||
118 | |||||
119 | $parameterName = $parameter->name; |
||||
120 | |||||
121 | // multiple variable named binding |
||||
122 | return $this->names[$parameterName] ?? $this->names[self::ANY] ?? self::ANY; |
||||
123 | } |
||||
124 | |||||
125 | private function setName(string $name): void |
||||
126 | { |
||||
127 | // annotation |
||||
128 | if (class_exists($name, false)) { |
||||
129 | $this->name = $name; |
||||
130 | |||||
131 | return; |
||||
132 | } |
||||
133 | |||||
134 | // single name |
||||
135 | // @Named(name) |
||||
136 | if ($name === self::ANY || preg_match('/^\w+$/', $name)) { |
||||
137 | $this->name = $name; |
||||
138 | |||||
139 | return; |
||||
140 | } |
||||
141 | |||||
142 | // name list |
||||
143 | // @Named(varName1=name1, varName2=name2)] |
||||
144 | $this->names = $this->parseName($name); |
||||
0 ignored issues
–
show
It seems like
$this->parseName($name) of type array or array is incompatible with the declared type Ray\Di\ParameterNameMapping of property $names .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||
145 | } |
||||
146 | |||||
147 | /** |
||||
148 | * @return ParameterNameMapping |
||||
149 | * |
||||
150 | * @psalm-pure |
||||
151 | */ |
||||
152 | private function parseName(string $name): array |
||||
153 | { |
||||
154 | $names = []; |
||||
155 | $keyValues = explode(',', $name); |
||||
156 | foreach ($keyValues as $keyValue) { |
||||
157 | $exploded = explode('=', $keyValue); |
||||
158 | if (isset($exploded[1])) { |
||||
159 | [$key, $value] = $exploded; |
||||
160 | if (isset($key[0]) && $key[0] === '$') { |
||||
161 | $key = substr($key, 1); |
||||
162 | } |
||||
163 | |||||
164 | $trimedKey = trim((string) $key); |
||||
165 | |||||
166 | $names[$trimedKey] = trim($value); |
||||
167 | } |
||||
168 | } |
||||
169 | |||||
170 | return $names; |
||||
0 ignored issues
–
show
|
|||||
171 | } |
||||
172 | } |
||||
173 |
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths