Passed
Pull Request — master (#15)
by Sergei
02:28
created

ParameterDefinition::resolve()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 16
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 24
ccs 15
cts 15
cp 1
crap 3
rs 9.7333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Definitions;
6
7
use Psr\Container\ContainerInterface;
8
use ReflectionNamedType;
9
use ReflectionParameter;
10
use ReflectionUnionType;
11
use Yiisoft\Definitions\Contract\DefinitionInterface;
12
use Yiisoft\Definitions\Exception\NotInstantiableException;
13
14
/**
15
 * Parameter definition resolves an object based on information from `ReflectionParameter` instance.
16
 */
17
final class ParameterDefinition implements DefinitionInterface
18
{
19
    private ReflectionParameter $parameter;
20
21 19
    public function __construct(ReflectionParameter $parameter)
22
    {
23 19
        $this->parameter = $parameter;
24 19
    }
25
26 20
    public function isVariadic(): bool
27
    {
28 20
        return $this->parameter->isVariadic();
29
    }
30
31 21
    public function isOptional(): bool
32
    {
33 21
        return $this->parameter->isOptional();
34
    }
35
36 19
    public function hasValue(): bool
37
    {
38 19
        return $this->parameter->isDefaultValueAvailable();
39
    }
40
41 23
    public function resolve(ContainerInterface $container)
42
    {
43 23
        if ($this->parameter->isDefaultValueAvailable()) {
44 19
            return $this->parameter->getDefaultValue();
45
        }
46
47 4
        if ($this->isOptional()) {
48 2
            throw new NotInstantiableException(
49 2
                sprintf(
50
                    'Can not determine default value of parameter "%s" when instantiating "%s" ' .
51 2
                    'because it is PHP internal. Please specify argument explicitly.',
52 2
                    $this->parameter->getName(),
53 2
                    $this->getCallable(),
54
                )
55
            );
56
        }
57
58 2
        throw new NotInstantiableException(
59 2
            sprintf(
60
                'Can not determine value of the "%s" parameter of type "%s" when instantiating "%s". ' .
61 2
                'Please specify argument explicitly.',
62 2
                $this->parameter->getName(),
63 2
                $this->getType(),
64 2
                $this->getCallable(),
65
            )
66
        );
67
    }
68
69 2
    private function getType(): string
70
    {
71
        /**
72
         * @psalm-suppress UndefinedDocblockClass
73
         *
74
         * @var ReflectionNamedType|ReflectionUnionType $type Could not be `null`
75
         * because in self::resolve() checked `$this->parameter->allowsNull()`.
76
         */
77 2
        $type = $this->parameter->getType();
78
79
        /** @psalm-suppress UndefinedClass, TypeDoesNotContainType */
80 2
        if ($type instanceof ReflectionUnionType) {
81
            /** @var ReflectionNamedType[] */
82
            $namedTypes = $type->getTypes();
83
            $names = array_map(
84
                static fn (ReflectionNamedType $t) => $t->getName(),
85
                $namedTypes
86
            );
87
            return implode('|', $names);
88
        }
89
90
        /** @var ReflectionNamedType $type */
91
92 2
        return $type->getName();
93
    }
94
95 4
    private function getCallable(): string
96
    {
97 4
        $callable = [];
98
99 4
        $class = $this->parameter->getDeclaringClass();
100 4
        if ($class !== null) {
101 3
            $callable[] = $class->getName();
102
        }
103 4
        $callable[] = $this->parameter->getDeclaringFunction()->getName() . '()';
104
105 4
        return implode('::', $callable);
106
    }
107
}
108