Name   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 21
eloc 50
c 6
b 0
f 0
dl 0
loc 147
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A setName() 0 20 4
A getName() 0 16 3
A withAttributes() 0 18 4
A parseName() 0 19 5
A __construct() 0 13 3
A __invoke() 0 11 2
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 assert;
16
use function class_exists;
17
use function explode;
18
use function get_class;
19
use function is_object;
20
use function is_string;
21
use function preg_match;
22
use function substr;
23
use function trim;
24
25
/**
26
 * @psalm-import-type ParameterNameMapping from Types
27
 */
28
final class Name
29
{
30
    /**
31
     * 'Unnamed' name
32
     */
33
    public const ANY = '';
34
35
    /** @var string */
36
    private $name = '';
37
38
    /**
39
     * Named database
40
     *
41
     * format: array<varName, NamedName>
42
     *
43
     * @var ParameterNameMapping
0 ignored issues
show
Bug introduced by
The type Ray\Di\ParameterNameMapping 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...
44
     */
45
    private $names;
46
47
    /**
48
     * @param string|ParameterNameMapping|null $name
49
     */
50
    public function __construct($name = null)
51
    {
52
        if ($name === null) {
53
            return;
54
        }
55
56
        if (is_string($name)) {
57
            $this->setName($name);
58
59
            return;
60
        }
61
62
        $this->names = $name;
63
    }
64
65
    /**
66
     * Create instance from PHP8 attributes
67
     *
68
     * psalm does not know ReflectionAttribute?? PHPStan produces no type error here.
69
     */
70
    public static function withAttributes(ReflectionMethod $method): ?self
71
    {
72
        $params = $method->getParameters();
73
        $names = [];
74
        foreach ($params as $param) {
75
            /** @var array<ReflectionAttribute> $attributes */
76
            $attributes = $param->getAttributes();
77
            if ($attributes) {
0 ignored issues
show
Bug Best Practice introduced by
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 empty(..) or ! empty(...) instead.

Loading history...
78
                $name = self::getName($attributes);
79
                $names[$param->name] = $name;
80
            }
81
        }
82
83
        if ($names) {
84
            return new self($names);
0 ignored issues
show
Bug introduced by
$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 ignore-type  annotation

84
            return new self(/** @scrutinizer ignore-type */ $names);
Loading history...
85
        }
86
87
        return null;
88
    }
89
90
    /**
91
     * @param non-empty-array<ReflectionAttribute> $attributes
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-array<ReflectionAttribute> at position 0 could not be parsed: Unknown type name 'non-empty-array' at position 0 in non-empty-array<ReflectionAttribute>.
Loading history...
92
     *
93
     * @throws ReflectionException
94
     *
95
     * @psalm-suppress MixedAssignment
96
     * @psalm-suppress MixedArgument
97
     */
98
    private static function getName(array $attributes): string
99
    {
100
        $refAttribute = $attributes[0];
101
        $attribute = $refAttribute->newInstance();
102
        if ($attribute instanceof Named) {
103
            return $attribute->value;
104
        }
105
106
        $isQualifier = (bool) (new ReflectionClass($attribute))->getAttributes(Qualifier::class);
107
        if ($isQualifier) {
108
            assert(is_object($attribute)); // @phpstan-ignore-line
109
110
            return get_class($attribute);
111
        }
112
113
        return '';
114
    }
115
116
    public function __invoke(ReflectionParameter $parameter): string
117
    {
118
        // single variable named binding
119
        if ($this->name) {
120
            return $this->name;
121
        }
122
123
        $parameterName = $parameter->name;
124
125
        // multiple variable named binding
126
        return $this->names[$parameterName] ?? $this->names[self::ANY] ?? self::ANY;
127
    }
128
129
    private function setName(string $name): void
130
    {
131
        // annotation
132
        if (class_exists($name, false)) {
133
            $this->name = $name;
134
135
            return;
136
        }
137
138
        // single name
139
        // @Named(name)
140
        if ($name === self::ANY || preg_match('/^\w+$/', $name)) {
141
            $this->name = $name;
142
143
            return;
144
        }
145
146
        // name list
147
        // @Named(varName1=name1, varName2=name2)]
148
        $this->names = $this->parseName($name);
0 ignored issues
show
Documentation Bug introduced by
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..

Loading history...
149
    }
150
151
    /**
152
     * @return ParameterNameMapping
153
     *
154
     * @psalm-pure
155
     */
156
    private function parseName(string $name): array
157
    {
158
        $names = [];
159
        $keyValues = explode(',', $name);
160
        foreach ($keyValues as $keyValue) {
161
            $exploded = explode('=', $keyValue);
162
            if (isset($exploded[1])) {
163
                [$key, $value] = $exploded;
164
                if (isset($key[0]) && $key[0] === '$') {
165
                    $key = substr($key, 1);
166
                }
167
168
                $trimedKey = trim((string) $key);
169
170
                $names[$trimedKey] = trim($value);
171
            }
172
        }
173
174
        return $names;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $names returns the type array which is incompatible with the documented return type Ray\Di\ParameterNameMapping.
Loading history...
175
    }
176
}
177