Completed
Push — 4.x ( 8fa263...613328 )
by Phil
03:02
created

ReflectionContainer::call()   B

Complexity

Conditions 8
Paths 16

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 17
cts 17
cp 1
rs 8.1315
c 0
b 0
f 0
cc 8
nc 16
nop 2
crap 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Container;
6
7
use League\Container\Argument\{ArgumentResolverInterface, ArgumentResolverTrait};
8
use League\Container\Exception\ContainerException;
9
use League\Container\Exception\NotFoundException;
10
use Psr\Container\ContainerInterface;
11
use ReflectionClass;
12
use ReflectionFunction;
13
use ReflectionMethod;
14
15
class ReflectionContainer implements ArgumentResolverInterface, ContainerInterface
16
{
17
    use ArgumentResolverTrait;
18
    use ContainerAwareTrait;
19
20
    /**
21
     * @var boolean
22
     */
23
    protected $cacheResolutions;
24
25
    /**
26
     * @var array
27
     */
28
    protected $cache = [];
29
30 48
    public function __construct(bool $cacheResolutions = false)
31
    {
32 48
        $this->cacheResolutions = $cacheResolutions;
33 48
    }
34
35 39
    public function get($id, array $args = [])
36
    {
37 39
        if ($this->cacheResolutions === true && array_key_exists($id, $this->cache)) {
38 6
            return $this->cache[$id];
39
        }
40
41 39
        if (! $this->has($id)) {
42 3
            throw new NotFoundException(
43 3
                sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $id)
44
            );
45
        }
46
47 36
        $reflector = new ReflectionClass($id);
48 36
        $construct = $reflector->getConstructor();
49
50 36
        $resolution = $construct === null
51 30
            ? new $id()
52 36
            : $resolution = $reflector->newInstanceArgs($this->reflectArguments($construct, $args))
53
        ;
54
55 36
        if ($this->cacheResolutions === true) {
56 6
            $this->cache[$id] = $resolution;
57
        }
58
59 36
        return $resolution;
60
    }
61
62 45
    public function has($id): bool
63
    {
64 45
        return class_exists($id);
65
    }
66
67 18
    public function call(callable $callable, array $args = [])
68
    {
69 18
        if (is_string($callable) && strpos($callable, '::') !== false) {
70 3
            $callable = explode('::', $callable);
71
        }
72
73 18
        if (is_array($callable)) {
74 9
            if (is_string($callable[0])) {
75
                // if we have a definition container, try that first, otherwise, reflect
76
                try {
77 3
                    $callable[0] = $this->getContainer()->get($callable[0]);
78 3
                } catch (ContainerException $e) {
79 3
                    $callable[0] = $this->get($callable[0]);
80
                }
81
            }
82
83 9
            $reflection = new ReflectionMethod($callable[0], $callable[1]);
84
85 9
            if ($reflection->isStatic()) {
86 3
                $callable[0] = null;
87
            }
88
89 9
            return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args));
90
        }
91
92 9
        if (is_object($callable)) {
93 6
            $reflection = new ReflectionMethod($callable, '__invoke');
94 6
            return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args));
95
        }
96
97 3
        $reflection = new ReflectionFunction(\Closure::fromCallable($callable));
98
99 3
        return $reflection->invokeArgs($this->reflectArguments($reflection, $args));
100
    }
101
}
102