Passed
Pull Request — master (#74)
by Sergei
14:58 queued 11:48
created

ArgumentException::__construct()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 14
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 25
ccs 14
cts 14
cp 1
crap 4
rs 9.7998
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Injector;
6
7
use ReflectionFunctionAbstract;
8
use ReflectionIntersectionType;
0 ignored issues
show
Bug introduced by
The type ReflectionIntersectionType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use ReflectionNamedType;
10
use ReflectionParameter;
11
use ReflectionUnionType;
12
13
use function array_map;
14
use function get_class;
15
use function implode;
16
use function is_object;
17
use function method_exists;
18
use function sprintf;
19
use function substr;
20
use function var_export;
21
22
abstract class ArgumentException extends \InvalidArgumentException
23
{
24
    protected const EXCEPTION_MESSAGE = 'Something is wrong with argument "%s" when calling "%s"%s.';
25
26 38
    public function __construct(ReflectionFunctionAbstract $reflection, string $parameter)
27
    {
28 38
        $function = $reflection->getName();
29
        /** @psalm-var class-string|null $class */
30 38
        $class = $reflection->class ?? null;
31
32 38
        if ($class === null) {
33 32
            $method = $function;
34 32
            if (substr($method, -9) === '{closure}') {
35 32
                $method = $this->renderClosureSignature($reflection);
36
            }
37
        } else {
38 6
            $method = "{$class}::{$function}";
39
        }
40
41 38
        $fileName = $reflection->getFileName();
42 38
        $line = $reflection->getStartLine();
43
44 38
        $fileAndLine = '';
45 38
        if (!empty($fileName)) {
46 29
            $fileAndLine = " in \"$fileName\" at line $line";
47
        }
48
49
        /** @psalm-suppress MixedArgument */
50 38
        parent::__construct(sprintf(static::EXCEPTION_MESSAGE, $parameter, $method, $fileAndLine));
51
    }
52
53 20
    private function renderClosureSignature(ReflectionFunctionAbstract $reflection): string
54
    {
55 20
        $closureParameters = [];
56
57 20
        foreach ($reflection->getParameters() as $parameter) {
58 19
            $parameterString = sprintf(
59 19
                '%s%s%s$%s',
60
                // type
61 19
                $this->renderParameterType($parameter),
62
                // reference
63 19
                $parameter->isPassedByReference() ? '&' : '',
64
                // variadic
65 19
                $parameter->isVariadic() ? '...' : '',
66 19
                $parameter->getName(),
67 19
            );
68 19
            if ($parameter->isDefaultValueAvailable()) {
69
                /** @var mixed $default */
70 6
                $default = $parameter->getDefaultValue();
71 6
                $parameterString .= ' = ';
72 6
                if (is_object($default)) {
73
                    $parameterString .= 'new ' . get_class($default) . '(...)';
74 6
                } elseif ($parameter->isDefaultValueConstant()) {
75
                    /** @psalm-suppress PossiblyNullOperand */
76 3
                    $parameterString .= $parameter->getDefaultValueConstantName();
77
                } else {
78 3
                    $parameterString .= var_export($default, true);
79
                }
80
            }
81 19
            $closureParameters[] = $parameterString;
82
        }
83
84 20
        $static = method_exists($reflection, 'isStatic') && $reflection->isStatic() ? 'static ' : '';
85 20
        return $static . 'function (' . implode(', ', $closureParameters) . ')';
86
    }
87
88 19
    private function renderParameterType(ReflectionParameter $parameter): string
89
    {
90
        /** @var ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null $type */
91 19
        $type = $parameter->getType();
92 19
        if ($type instanceof ReflectionNamedType) {
93 16
            return sprintf(
94 16
                '%s%s ',
95 16
                $parameter->allowsNull() ? '?' : '',
96 16
                $type->getName()
97 16
            );
98
        }
99 7
        if ($type instanceof ReflectionUnionType) {
0 ignored issues
show
introduced by
$type is always a sub-type of ReflectionUnionType.
Loading history...
100
            /** @var ReflectionNamedType[] $types */
101 3
            $types = $type->getTypes();
102 3
            return implode('|', array_map(
103 3
                static fn (ReflectionNamedType $r) => $r->getName(),
104 3
                $types
105 3
            )) . ' ';
106
        }
107 4
        if ($type instanceof ReflectionIntersectionType) {
108
            /** @var ReflectionNamedType[] $types */
109
            $types = $type->getTypes();
110
            return implode('&', array_map(
111
                static fn (ReflectionNamedType $r) => $r->getName(),
112
                $types
113
            )) . ' ';
114
        }
115 4
        return '';
116
    }
117
}
118