Completed
Pull Request — master (#5)
by Eugene
01:02
created

InDepthArgumentsResolver   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 126
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 97.78%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 1
dl 0
loc 126
ccs 44
cts 45
cp 0.9778
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getParameters() 0 9 2
A match() 0 20 5
B matchType() 0 28 11
A compareParameters() 0 16 4
A compareParameterClasses() 0 11 4
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 \ReflectionParameter $parameter
64
     * @param mixed                $value
65
     *
66
     * @return bool
67
     */
68 8
    private static function matchType(\ReflectionParameter $parameter, $value) : bool
69
    {
70 8
        if ($class = $parameter->getClass()) {
71 5
            return \is_object($value) && $class->isInstance($value);
72
        }
73
74 4
        if ($parameter->isArray()) {
75 2
            return \is_array($value);
76
        }
77
78 3
        if ($parameter->isCallable()) {
79 2
            return \is_callable($value);
80
        }
81
82 2
        if (!$type = $parameter->getType()) {
83 2
            return true;
84
        }
85
86 1
        switch ($type->getName()) {
87 1
            case 'bool': return \is_bool($value);
88 1
            case 'float': return \is_float($value);
89 1
            case 'int': return \is_int($value);
90 1
            case 'string': return \is_string($value);
91 1
            case 'iterable': return \is_iterable($value);
92
        }
93
94
        return true;
95
    }
96
97
    /**
98
     * Compares reflection parameters by type and position.
99
     *
100
     * @param \ReflectionParameter $a
101
     * @param \ReflectionParameter $b
102
     *
103
     * @return int
104
     */
105 7
    private static function compareParameters(\ReflectionParameter $a, \ReflectionParameter $b) : int
106
    {
107 7
        if (0 !== $result = self::compareParameterClasses($a, $b)) {
108 3
            return $result;
109
        }
110
111 5
        if ($a->isArray() ^ $b->isArray()) {
112 2
            return $b->isArray() << 1 - 1;
113
        }
114
115 5
        if ($a->isCallable() ^ $b->isCallable()) {
116 2
            return $b->isCallable() << 1 - 1;
117
        }
118
119 4
        return $a->getPosition() - $b->getPosition();
120
    }
121
122
    /**
123
     * Compares reflection parameters by class hierarchy.
124
     *
125
     * @param \ReflectionParameter $a
126
     * @param \ReflectionParameter $b
127
     *
128
     * @return int
129
     */
130 7
    private static function compareParameterClasses(\ReflectionParameter $a, \ReflectionParameter $b) : int
131
    {
132 7
        $a = $a->getClass();
133 7
        $b = $b->getClass();
134
135 7
        if ($a && $b) {
136 3
            return $a->isSubclassOf($b->name) ? -1 : (int) $b->isSubclassOf($a->name);
137
        }
138
139 4
        return (int) !$a - (int) !$b;
140
    }
141
}
142