CallableDefinition   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 51
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 51
ccs 19
cts 19
cp 1
rs 10
wmc 7

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A resolve() 0 16 2
A prepareClosure() 0 10 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Definitions;
6
7
use Closure;
8
use Psr\Container\ContainerInterface;
9
use ReflectionException;
10
use ReflectionFunction;
11
use ReflectionMethod;
12
use Yiisoft\Definitions\Contract\DefinitionInterface;
13
use Yiisoft\Definitions\Exception\NotInstantiableException;
14
use Yiisoft\Definitions\Helpers\DefinitionExtractor;
15
use Yiisoft\Definitions\Helpers\DefinitionResolver;
16
17
use function is_array;
18
use function is_object;
19
20
/**
21
 * Builds an object by executing a callable injecting
22
 * dependencies based on types used in its signature.
23
 */
24
final class CallableDefinition implements DefinitionInterface
25
{
26
    /**
27
     * @var array|callable
28
     * @psalm-var callable|array{0:class-string,1:string}
29
     */
30
    private $callable;
31
32
    /**
33
     * @param array|callable $callable Callable to be used for building
34
     * an object. Dependencies are determined and passed based
35
     * on the types of arguments in the callable signature.
36
     *
37
     * @psalm-param callable|array{0:class-string,1:string} $callable
38
     */
39 6
    public function __construct(array|callable $callable)
40
    {
41 6
        $this->callable = $callable;
42
    }
43
44 5
    public function resolve(ContainerInterface $container): mixed
45
    {
46
        try {
47 5
            $reflection = new ReflectionFunction(
48 5
                $this->prepareClosure($this->callable, $container)
49 5
            );
50 1
        } catch (ReflectionException) {
51 1
            throw new NotInstantiableException(
52 1
                'Can not instantiate callable definition. Got ' . var_export($this->callable, true)
53 1
            );
54
        }
55
56 4
        $dependencies = DefinitionExtractor::fromFunction($reflection);
57 4
        $arguments = DefinitionResolver::resolveArray($container, null, $dependencies);
58
59 4
        return $reflection->invokeArgs($arguments);
60
    }
61
62
    /**
63
     * @psalm-param callable|array{0:class-string,1:string} $callable
64
     */
65 5
    private function prepareClosure(array|callable $callable, ContainerInterface $container): Closure
66
    {
67 5
        if (is_array($callable) && !is_object($callable[0])) {
68 3
            $reflection = new ReflectionMethod($callable[0], $callable[1]);
69 2
            if (!$reflection->isStatic()) {
70 1
                $callable[0] = $container->get($callable[0]);
71
            }
72
        }
73
74 4
        return Closure::fromCallable($callable);
75
    }
76
}
77