Passed
Push — master ( 3a280d...539d3e )
by Alexander
02:49 queued 01:18
created

DefinitionExtractor   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 51
Duplicated Lines 0 %

Test Coverage

Coverage 86.96%

Importance

Changes 0
Metric Value
wmc 16
eloc 20
dl 0
loc 51
ccs 20
cts 23
cp 0.8696
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A fromCallable() 0 3 1
B fromParameter() 0 18 10
A fromFunction() 0 7 2
A fromClassName() 0 8 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory\Extractors;
6
7
use Yiisoft\Factory\Definitions\DefinitionInterface;
8
use Yiisoft\Factory\Definitions\ClassDefinition;
9
use Yiisoft\Factory\Definitions\InvalidDefinition;
10
use Yiisoft\Factory\Definitions\ValueDefinition;
11
use Yiisoft\Factory\Exceptions\NotInstantiableException;
12
13
/**
14
 * Class DefinitionExtractor
15
 * This implementation resolves dependencies by using class type hints.
16
 * Note that service names need not match the parameter names, parameter names are ignored
17
 */
18
class DefinitionExtractor implements ExtractorInterface
19
{
20 13
    public function fromClassName(string $class): array
21
    {
22 13
        $reflectionClass = new \ReflectionClass($class);
23 13
        if (!$reflectionClass->isInstantiable()) {
24 5
            throw new NotInstantiableException($class);
25
        }
26 13
        $constructor = $reflectionClass->getConstructor();
27 13
        return $constructor === null ? [] : $this->fromFunction($constructor);
28
    }
29
30
    /**
31
     * @suppress PhanUndeclaredMethod
32
     */
33 11
    private function fromFunction(\ReflectionFunctionAbstract $reflectionFunction): array
34
    {
35 11
        $result = [];
36 11
        foreach ($reflectionFunction->getParameters() as $parameter) {
37 11
            $result[$parameter->getName()] = $this->fromParameter($parameter);
38
        }
39 11
        return $result;
40
    }
41
42
    /**
43
     * @suppress PhanUndeclaredMethod
44
     */
45 11
    private function fromParameter(\ReflectionParameter $parameter): DefinitionInterface
46
    {
47 11
        $type = $parameter->getType();
48 11
        $hasDefault = $parameter->isOptional() || $parameter->isDefaultValueAvailable() || (isset($type) && $type->allowsNull());
49
50 11
        if (!$hasDefault && $type === null) {
51
            return new InvalidDefinition();
52
        }
53
54
        // Our parameter has a class type hint
55 11
        if ($type !== null && !$type->isBuiltin()) {
56 8
            return new ClassDefinition($type->getName(), $type->allowsNull());
57
        }
58
59
        // Our parameter does not have a class type hint and either has a default value or is nullable.
60 4
        return new ValueDefinition(
61 4
            $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null,
62 4
            $type !== null ? $type->getName() : null
63
        );
64
    }
65
66
    public function fromCallable(callable $callable): array
67
    {
68
        return $this->fromFunction(new \ReflectionFunction(\Closure::fromCallable($callable)));
69
    }
70
}
71