Passed
Push — master ( 41e710...91ffae )
by Aleksei
06:19 queued 21s
created

Invoker::invoke()   C

Complexity

Conditions 14
Paths 26

Size

Total Lines 50
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 14.713

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 26
dl 0
loc 50
ccs 22
cts 26
cp 0.8462
rs 6.2666
c 1
b 0
f 0
cc 14
nc 26
nop 2
crap 14.713

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 Spiral\Core\Internal;
6
7
use Psr\Container\ContainerInterface;
8
use Spiral\Core\Exception\Container\ContainerException;
9
use Spiral\Core\Exception\Container\NotCallableException;
10
use Spiral\Core\Internal\Common\DestructorTrait;
11
use Spiral\Core\Internal\Common\Registry;
12
use Spiral\Core\InvokerInterface;
13
use Spiral\Core\Options;
14
use Spiral\Core\ResolverInterface;
15
16
/**
17
 * @psalm-type TResolver = class-string|non-empty-string|callable|array{class-string, non-empty-string}
18
 *
19
 * @internal
20
 */
21
final class Invoker implements InvokerInterface
22
{
23
    use DestructorTrait;
24
25
    private ContainerInterface $container;
26
    private ResolverInterface $resolver;
27
    private Options $options;
28
    private Actor $actor;
29
30 1443
    public function __construct(Registry $constructor)
31
    {
32 1443
        $constructor->set('invoker', $this);
33
34 1443
        $this->container = $constructor->get('container', ContainerInterface::class);
35 1443
        $this->resolver = $constructor->get('resolver', ResolverInterface::class);
36 1443
        $this->actor = $constructor->get('actor', Actor::class);
37 1443
        $this->options = $constructor->getOptions();
38
    }
39
40
    /**
41
     * @psalm-param TResolver $target
42
     */
43 806
    public function invoke(mixed $target, array $parameters = []): mixed
44
    {
45 806
        if (\is_array($target) && isset($target[1])) {
46
            // In a form of alias and method
47 607
            [$alias, $method] = $target;
48
49
            // Resolver instance or class name if the method is static (i.e. [ClassName::class, 'method'])
50 607
            if (\is_string($alias)) {
51
                // Detect return type
52 595
                $type = $this->actor->resolveType($alias, $binding, $singleton, $injector);
53
54 595
                if ($singleton === null) {
55 593
                    $type ??= $injector === null && $binding === null ? $alias : null;
56 593
                    $alias = \is_callable([$type, $method]) ? $type : $this->container->get($alias);
57
                } else {
58 460
                    $alias = $singleton;
59
                }
60
            }
61
62
            try {
63 603
                $method = new \ReflectionMethod($alias, $method);
64
            } catch (\ReflectionException $e) {
65
                throw new ContainerException($e->getMessage(), $e->getCode(), $e);
66
            }
67
68
            // Invoking factory method with resolved arguments
69 603
            return $method->invokeArgs(
70 603
                $method->isStatic() ? null : $alias,
71 603
                $this->resolver->resolveArguments($method, $parameters),
72 603
            );
73
        }
74
75 780
        if (\is_string($target) && \is_callable($target)) {
76 2
            $target = $target(...);
77
        }
78
79 780
        if ($target instanceof \Closure) {
80
            try {
81 778
                $reflection = new \ReflectionFunction($target);
82
            } catch (\ReflectionException $e) {
83
                throw new ContainerException($e->getMessage(), $e->getCode(), $e);
84
            }
85
86
            // Invoking Closure with resolved arguments
87 778
            return $reflection->invokeArgs(
88 778
                $this->resolver->resolveArguments($reflection, $parameters, $this->options->validateArguments),
89 778
            );
90
        }
91
92 2
        throw new NotCallableException('Unsupported callable.');
93
    }
94
}
95