InDepthArgumentsResolver   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 98.25%

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 1
dl 0
loc 132
ccs 56
cts 57
cp 0.9825
rs 9.76
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getParameters() 0 9 2
A match() 0 20 5
C matchType() 0 36 12
B compareParameters() 0 22 6
B compareParameterClasses() 0 16 8
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the rybakit/arguments-resolver package.
7
 *
8
 * (c) Eugene Leonovich <[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 ArgumentsResolver;
15
16
class InDepthArgumentsResolver extends ArgumentsResolver
17
{
18
    /**
19
     * @var \ReflectionParameter[]
20
     */
21
    private $sortedParameters;
22
23
    /**
24
     * {@inheritdoc}
25
     */
26 11
    protected function getParameters() : array
27
    {
28 11
        if (null === $this->sortedParameters) {
29 11
            $this->sortedParameters = $this->reflection->getParameters();
30 11
            \uasort($this->sortedParameters, [__CLASS__, 'compareParameters']);
31
        }
32
33 11
        return $this->sortedParameters;
34
    }
35
36
    /**
37
     * {@inheritdoc}
38
     */
39 11
    protected function match(\ReflectionParameter $parameter, array $parameters) : ?array
40
    {
41 11
        $found = null;
42
43 11
        foreach ($parameters as $key => $value) {
44 8
            if (!self::matchType($parameter, $value)) {
45 6
                continue;
46
            }
47
48 5
            if ($key === $parameter->name) {
49 2
                return [$key, $value];
50
            }
51
52 5
            if (!$found) {
53 5
                $found = [$key, $value];
54
            }
55
        }
56
57 9
        return $found;
58
    }
59
60
    /**
61
     * Checks if the value matches the parameter type.
62
     *
63
     * @param mixed $value
64
     */
65 8
    private static function matchType(\ReflectionParameter $parameter, $value) : bool
66
    {
67 8
        if (!$type = $parameter->getType()) {
68 2
            return true;
69
        }
70
71 7
        $typeName = $type->getName();
72
73 7
        if ('array' === $typeName) {
74 2
            return \is_array($value);
75
        }
76
77 6
        if ('callable' === $typeName) {
78 2
            return \is_callable($value);
79
        }
80
81 5
        if (!$type->isBuiltin()) {
82 5
            if (!\is_object($value)) {
83 2
                return false;
84
            }
85
86 4
            $class = new \ReflectionClass($typeName);
87
88 4
            return $class && $class->isInstance($value);
89
        }
90
91 1
        switch ($typeName) {
92 1
            case 'bool': return \is_bool($value);
93 1
            case 'float': return \is_float($value);
94 1
            case 'int': return \is_int($value);
95 1
            case 'string': return \is_string($value);
96 1
            case 'iterable': return \is_iterable($value);
97
        }
98
99
        return true;
100
    }
101
102
    /**
103
     * Compares reflection parameters by type and position.
104
     */
105 7
    private static function compareParameters(\ReflectionParameter $a, \ReflectionParameter $b) : int
106
    {
107 7
        $aType = $a->getType();
108 7
        $bType = $b->getType();
109
110 7
        if (0 !== $result = self::compareParameterClasses($aType, $bType)) {
111 3
            return $result;
112
        }
113
114 5
        $aTypeName = $aType ? $aType->getName() : null;
115 5
        $bTypeName = $bType ? $bType->getName() : null;
116
117 5
        if (('array' === $aTypeName) ^ ('array' === $bTypeName)) {
118 2
            return ('array' === $bTypeName) << 1 - 1;
119
        }
120
121 5
        if (('callable' === $aTypeName) ^ ('callable' === $bTypeName)) {
122 2
            return ('callable' === $bTypeName) << 1 - 1;
123
        }
124
125 4
        return $a->getPosition() - $b->getPosition();
126
    }
127
128
    /**
129
     * Compares reflection parameters by class hierarchy.
130
     */
131 7
    private static function compareParameterClasses(?\ReflectionType $a, ?\ReflectionType $b) : int
132
    {
133 7
        $a = $a && !$a->isBuiltin()
134 4
            ? new \ReflectionClass($a->getName())
135 7
            : null;
136
137 7
        $b = $b && !$b->isBuiltin()
138 4
            ? new \ReflectionClass($b->getName())
139 7
            : null;
140
141 7
        if ($a && $b) {
142 3
            return $a->isSubclassOf($b->name) ? -1 : (int) $b->isSubclassOf($a->name);
143
        }
144
145 4
        return (int) !$a - (int) !$b;
146
    }
147
}
148