Completed
Push — master ( a9358c...b17107 )
by Phil
01:46
created

ReflectionContainer::get()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 14
cts 14
cp 1
rs 8.8817
c 0
b 0
f 0
cc 6
nc 6
nop 2
crap 6
1
<?php declare(strict_types=1);
2
3
namespace League\Container;
4
5
use League\Container\Argument\{ArgumentResolverInterface, ArgumentResolverTrait};
6
use League\Container\Exception\NotFoundException;
7
use Psr\Container\ContainerInterface;
8
use ReflectionClass;
9
use ReflectionFunction;
10
use ReflectionMethod;
11
12
class ReflectionContainer implements ArgumentResolverInterface, ContainerInterface
13
{
14
    use ArgumentResolverTrait;
15
    use ContainerAwareTrait;
16
17
    /**
18
     * @var boolean
19
     */
20
    protected $cacheResolutions = false;
21
22
    /**
23
     * Cache of reslutions.
24
     *
25
     * @var array
26
     */
27
    protected $cache = [];
28
29
    /**
30
     * {@inheritdoc}
31
     */
32 36
    public function get($id, array $args = [])
33
    {
34 36
        if ($this->cacheResolutions === true && array_key_exists($id, $this->cache)) {
35 6
            return $this->cache[$id];
36
        }
37
38 36
        if (! $this->has($id)) {
39 3
            throw new NotFoundException(
40 3
                sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $id)
41
            );
42
        }
43
44 33
        $reflector = new ReflectionClass($id);
45 33
        $construct = $reflector->getConstructor();
46
47 33
        $resolution = (is_null($construct))
48 27
            ? new $id
49 33
            : $resolution = $reflector->newInstanceArgs($this->reflectArguments($construct, $args))
50
        ;
51
52 33
        if ($this->cacheResolutions === true) {
53 6
            $this->cache[$id] = $resolution;
54
        }
55
56 33
        return $resolution;
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 42
    public function has($id) : bool
63
    {
64 42
        return class_exists($id);
65
    }
66
67
    /**
68
     * Invoke a callable via the container.
69
     *
70
     * @param callable $callable
71
     * @param array    $args
72
     *
73
     * @return mixed
74
     */
75 15
    public function call(callable $callable, array $args = [])
76
    {
77 15
        if (is_string($callable) && strpos($callable, '::') !== false) {
78 3
            $callable = explode('::', $callable);
79
        }
80
81 15
        if (is_array($callable)) {
82 9
            if (is_string($callable[0])) {
83 3
                $callable[0] = $this->getContainer()->get($callable[0]);
84
            }
85
86 9
            $reflection = new ReflectionMethod($callable[0], $callable[1]);
87
88 9
            if ($reflection->isStatic()) {
89 3
                $callable[0] = null;
90
            }
91
92 9
            return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args));
93
        }
94
95 6
        if (is_object($callable)) {
96 6
            $reflection = new ReflectionMethod($callable, '__invoke');
97
98 6
            return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args));
99
        }
100
101
        $reflection = new ReflectionFunction($callable);
102
103
        return $reflection->invokeArgs($this->reflectArguments($reflection, $args));
104
    }
105
106
    /**
107
     * Whether the container should default to caching resolutions and returning
108
     * the cache on following calls.
109
     *
110
     * @param boolean $option
111
     *
112
     * @return self
113
     */
114 6
    public function cacheResolutions(bool $option = true) : ContainerInterface
115
    {
116 6
        $this->cacheResolutions = $option;
117
118 6
        return $this;
119
    }
120
}
121