Passed
Push — master ( d4add0...533366 )
by Alexander
05:10 queued 02:59
created

DefinitionExtractor::fromParameter()   B

Complexity

Conditions 10
Paths 7

Size

Total Lines 36
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 19.1124

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 19
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 36
ccs 11
cts 20
cp 0.55
crap 19.1124
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory\Extractors;
6
7
use Yiisoft\Factory\Definitions\ClassDefinition;
8
use Yiisoft\Factory\Definitions\DefinitionInterface;
9
use Yiisoft\Factory\Definitions\ParameterDefinition;
10
use Yiisoft\Factory\Exceptions\NotInstantiableException;
11
12
/**
13
 * Class DefinitionExtractor
14
 * This implementation resolves dependencies by using class type hints.
15
 * Note that service names need not match the parameter names, parameter names are ignored
16
 */
17
class DefinitionExtractor implements ExtractorInterface
18
{
19
    /**
20
     * @param class-string $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
21
     */
22 12
    public function fromClassName(string $class): array
23
    {
24 12
        $reflectionClass = new \ReflectionClass($class);
25 12
        if (!$reflectionClass->isInstantiable()) {
26 5
            throw new NotInstantiableException($class);
27
        }
28 12
        $constructor = $reflectionClass->getConstructor();
29 12
        return $constructor === null ? [] : $this->fromFunction($constructor);
30
    }
31
32
    /**
33
     * @suppress PhanUndeclaredMethod
34
     */
35 11
    private function fromFunction(\ReflectionFunctionAbstract $reflectionFunction): array
36
    {
37 11
        $result = [];
38 11
        foreach ($reflectionFunction->getParameters() as $parameter) {
39 11
            $result[$parameter->getName()] = $this->fromParameter($parameter);
40
        }
41 11
        return $result;
42
    }
43
44
    /**
45
     * @suppress PhanUndeclaredMethod
46
     */
47 11
    private function fromParameter(\ReflectionParameter $parameter): DefinitionInterface
48
    {
49 11
        $type = $parameter->getType();
50
51
        // PHP 8 union type is used as type hint
52
        /** @psalm-suppress UndefinedClass, TypeDoesNotContainType */
53 11
        if ($type instanceof \ReflectionUnionType) {
54
            $types = [];
55
            foreach ($type->getTypes() as $unionType) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $type->getTypes() targeting ReflectionUnionType::getTypes() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
The expression $type->getTypes() of type null is not traversable.
Loading history...
56
                if (!$unionType->isBuiltin()) {
57
                    $typeName = $unionType->getName();
58
                    if ($typeName === 'self') {
59
                        $typeName = $parameter->getDeclaringClass()->getName();
60
                    }
61
62
                    $types[] = $typeName;
63
                }
64
            }
65
            return new ClassDefinition(implode('|', $types), $type->allowsNull());
66
        }
67
68
        // Our parameter has a class type hint
69 11
        if ($type !== null && !$type->isBuiltin()) {
70 7
            $typeName = $type->getName();
71 7
            if ($typeName === 'self') {
72
                $typeName = $parameter->getDeclaringClass()->getName();
73
            }
74
75 7
            return new ClassDefinition($typeName, $type->allowsNull());
76
        }
77
78
        // Our parameter does not have a class type hint and either has a default value or is nullable.
79 5
        return new ParameterDefinition(
80 5
            $parameter,
81 5
            $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null,
82 5
            $type !== null ? $type->getName() : null
83
        );
84
    }
85
86
    public function fromCallable(callable $callable): array
87
    {
88
        return $this->fromFunction(new \ReflectionFunction(\Closure::fromCallable($callable)));
89
    }
90
}
91