Di::createInstance()   B
last analyzed

Complexity

Conditions 4
Paths 5

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 27
rs 8.5806
cc 4
eloc 17
nc 5
nop 2
1
<?php
2
/*
3
 * This file is part of the Borobudur-DependencyInjection package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Borobudur\DependencyInjection;
12
13
use Borobudur\DependencyInjection\Exception\InvalidArgumentException;
14
use Borobudur\DependencyInjection\ParameterBag\Resolver;
15
use Closure;
16
use ReflectionClass;
17
use ReflectionFunction;
18
use ReflectionMethod;
19
use ReflectionParameter;
20
21
/**
22
 * @author      Iqbal Maulana <[email protected]>
23
 * @created     8/8/15
24
 */
25
class Di
26
{
27
    /**
28
     * @var ContainerInterface
29
     */
30
    private $container;
31
32
    /**
33
     * @var Resolver
34
     */
35
    private $resolver;
36
37
    /**
38
     * @var Injector
39
     */
40
    private $injector;
41
42
    /**
43
     * Constructor.
44
     *
45
     * @param ContainerInterface $container
46
     */
47
    public function __construct(ContainerInterface $container = null)
48
    {
49
        $this->container = $container ?: new Container(null, $this);
50
        $this->resolver = $this->container->getParameterBag()->getResolver();
51
        $this->injector = new Injector($this->container);
52
    }
53
54
    /**
55
     * Get container.
56
     *
57
     * @return Container|ContainerInterface
58
     */
59
    public function getContainer()
60
    {
61
        return $this->container;
62
    }
63
64
    /**
65
     * Get dependency injector.
66
     *
67
     * @return Injector
68
     */
69
    public function getInjector()
70
    {
71
        return $this->injector;
72
    }
73
74
    /**
75
     * Create and automatic resolve class to object.
76
     *
77
     * @param string $class
78
     * @param array  $arguments
79
     *
80
     * @return InstanceManager
81
     */
82
    public function createInstance($class, array $arguments = array())
83
    {
84
        if (!is_string($class)) {
85
            throw new InvalidArgumentException(sprintf('Class should be string, "%s" given.', gettype($class)));
86
        }
87
88
        $resolver = $this->resolver;
89
        $reflection = new ReflectionClass($resolver->resolveString($class));
90
91
        if (null !== $constructor = $reflection->getConstructor()) {
92
            $arguments = $resolver->unescapeValue($resolver->resolveValue($arguments));
93
            $parameters = $constructor->getParameters();
94
            $service = $reflection->newInstanceArgs($this->injector->replaceArguments(
95
                $parameters,
96
                $this->injector->resolveParameters($parameters),
97
                array_map(array($this->injector, 'getParameterValue'), $arguments)
98
            ));
99
        } else {
100
            $service = $reflection->newInstance();
101
        }
102
103
        if ($service instanceof ContainerAwareInterface) {
104
            $service->setContainer($this->container);
105
        }
106
107
        return $this->create($service);
108
    }
109
110
    /**
111
     * Create instance manager.
112
     *
113
     * @param object $service
114
     *
115
     * @return InstanceManager
116
     */
117
    public function create($service)
118
    {
119
        return new InstanceManager($this, $service);
120
    }
121
122
    /**
123
     * Call service.
124
     *
125
     * @param mixed $service
126
     * @param array $args
127
     *
128
     * @return mixed
129
     */
130
    public function call($service, array $args = array())
131
    {
132
        if (!is_callable($service)) {
133
            throw new InvalidArgumentException(sprintf('Service should be callable, "%s" given.', gettype($service)));
134
        }
135
136
        $parameters = $this->getServiceParameter($service);
137
138
        return call_user_func_array($service, $this->injector->replaceArguments(
139
            $parameters,
140
            $this->injector->resolveParameters($parameters),
141
            array_map(array($this->injector, 'getParameterValue'), $args)
142
        ));
143
    }
144
145
    /**
146
     * Get service parameter.
147
     *
148
     * @param mixed $service
149
     *
150
     * @return ReflectionParameter[]
151
     */
152
    private function getServiceParameter($service)
153
    {
154
        if ($service instanceof Closure) {
155
            $reflection = new ReflectionFunction($service);
156
            return $reflection->getParameters();
157
        }
158
159
        $reflection = new ReflectionMethod($service[0], $service[1]);
160
161
        return $reflection->getParameters();
162
    }
163
}
164