Test Failed
Pull Request — master (#952)
by Maxim
16:49 queued 07:48
created

Invoker::invoke()   B

Complexity

Conditions 9
Paths 10

Size

Total Lines 42
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9.4867

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 42
ccs 18
cts 22
cp 0.8182
rs 8.0555
c 0
b 0
f 0
cc 9
nc 10
nop 2
crap 9.4867
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\ResolverInterface;
14
15
/**
16
 * @psalm-type TResolver = class-string|non-empty-string|callable|array{class-string, non-empty-string}
17
 *
18
 * @internal
19
 */
20
final class Invoker implements InvokerInterface
21
{
22
    use DestructorTrait;
23
24
    private ContainerInterface $container;
25
    private ResolverInterface $resolver;
26
27 1126
    public function __construct(Registry $constructor)
28
    {
29 1126
        $constructor->set('invoker', $this);
30
31 1126
        $this->container = $constructor->get('container', ContainerInterface::class);
32 1126
        $this->resolver = $constructor->get('resolver', ResolverInterface::class);
33
    }
34
35
    /**
36
     * @psalm-param TResolver $target
37
     */
38 585
    public function invoke(mixed $target, array $parameters = []): mixed
39
    {
40 585
        if (\is_array($target) && isset($target[1])) {
41
            // In a form of resolver and method
42 410
            [$resolver, $method] = $target;
43
44
            // Resolver instance (i.e. [ClassName::class, 'method'])
45 410
            if (\is_string($resolver)) {
46 373
                $resolver = $this->container->get($resolver);
47
            }
48
49
            try {
50 409
                $method = new \ReflectionMethod($resolver, $method);
51
            } catch (\ReflectionException $e) {
52
                throw new ContainerException($e->getMessage(), $e->getCode(), $e);
53
            }
54
55
            // Invoking factory method with resolved arguments
56 409
            return $method->invokeArgs(
57 409
                $resolver,
58 409
                $this->resolver->resolveArguments($method, $parameters),
59 409
            );
60
        }
61
62 542
        if (\is_string($target) && \is_callable($target)) {
63 2
            $target = $target(...);
64
        }
65
66 542
        if ($target instanceof \Closure) {
67
            try {
68 540
                $reflection = new \ReflectionFunction($target);
69
            } catch (\ReflectionException $e) {
70
                throw new ContainerException($e->getMessage(), $e->getCode(), $e);
71
            }
72
73
            // Invoking Closure with resolved arguments
74 540
            return $reflection->invokeArgs(
75 540
                $this->resolver->resolveArguments($reflection, $parameters)
76 540
            );
77
        }
78
79 2
        throw new NotCallableException('Unsupported callable.');
80
    }
81
}
82