Passed
Push — master ( 13cd0c...0a761e )
by Alexander
02:39
created

DefinitionExtractor::fromClassName()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 12
c 2
b 0
f 0
nc 5
nop 1
dl 0
loc 21
ccs 12
cts 12
cp 1
crap 5
rs 9.5555
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Definitions\Infrastructure;
6
7
use ReflectionClass;
8
use ReflectionException;
9
use ReflectionFunctionAbstract;
10
use ReflectionParameter;
11
use Yiisoft\Definitions\Contract\DefinitionInterface;
12
use Yiisoft\Definitions\Exception\NotFoundException;
13
use Yiisoft\Definitions\Exception\NotInstantiableClassException;
14
use Yiisoft\Definitions\Exception\NotInstantiableException;
15
use Yiisoft\Definitions\ParameterDefinition;
16
17
/**
18
 * This class resolves dependencies by using class type hints.
19
 * Note that service names need not match the parameter names, parameter names are ignored
20
 *
21
 * @internal
22
 */
23
final class DefinitionExtractor
24
{
25
    private static ?self $instance = null;
26
27
    /**
28
     * @psalm-var array<string, array<string, DefinitionInterface>>
29
     */
30
    private static array $dependencies = [];
31
32 1
    private function __construct()
33
    {
34 1
    }
35
36
    /**
37
     * Get an instance of this class or create it.
38
     *
39
     * @return static An instance of this class.
40
     */
41 35
    public static function getInstance(): self
42
    {
43 35
        if (self::$instance === null) {
44 1
            self::$instance = new self();
45
        }
46
47 35
        return self::$instance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::instance could return the type null which is incompatible with the type-hinted return Yiisoft\Definitions\Infr...ure\DefinitionExtractor. Consider adding an additional type-check to rule them out.
Loading history...
48
    }
49
50
    /**
51
     * @psalm-param class-string $class
52
     *
53
     * @throws NotFoundException
54
     * @throws NotInstantiableException
55
     *
56
     * @return DefinitionInterface[]
57
     * @psalm-return array<string, DefinitionInterface>
58
     */
59 31
    public function fromClassName(string $class): array
60
    {
61 31
        if (isset(self::$dependencies[$class])) {
62 17
            return self::$dependencies[$class];
63
        }
64
65
        try {
66 14
            $reflectionClass = new ReflectionClass($class);
67 1
        } catch (ReflectionException $e) {
68 1
            throw new NotFoundException($class);
69
        }
70
71 13
        if (!$reflectionClass->isInstantiable()) {
72 1
            throw new NotInstantiableClassException($class);
73
        }
74
75 12
        $constructor = $reflectionClass->getConstructor();
76 12
        $dependencies = $constructor === null ? [] : $this->fromFunction($constructor);
77 12
        self::$dependencies[$class] = $dependencies;
78
79 12
        return $dependencies;
80
    }
81
82
    /**
83
     * @return DefinitionInterface[]
84
     * @psalm-return array<string, DefinitionInterface>
85
     */
86 16
    public function fromFunction(ReflectionFunctionAbstract $reflectionFunction): array
87
    {
88 16
        $result = [];
89 16
        foreach ($reflectionFunction->getParameters() as $parameter) {
90 16
            $result[$parameter->getName()] = $this->fromParameter($parameter);
91
        }
92 16
        return $result;
93
    }
94
95 16
    private function fromParameter(ReflectionParameter $parameter): DefinitionInterface
96
    {
97 16
        return new ParameterDefinition($parameter);
98
    }
99
}
100