Completed
Pull Request — master (#64)
by Augusto
02:29 queued 01:30
created

Instantiator::getMode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Respect\Config;
4
5
use ReflectionClass;
6
7
class Instantiator
8
{
9
    const MODE_DEPENDENCY = false;
10
    const MODE_FACTORY = 'new';
11
12
    protected $instance;
13
    protected $reflection;
14
    protected $constructor = array();
15
    protected $className;
16
    protected $params = array();
17
    protected $staticMethodCalls = array();
18
    protected $methodCalls = array();
19
    protected $propertySetters = array();
20
    protected $mode = self::MODE_DEPENDENCY;
21
22 34
    public function __construct($className)
23
    {
24 34
        if (false !== stripos($className, ' ')) {
25 1
            list($mode, $className) = explode(' ', $className, 2);
26 1
            $this->mode = $mode;
27 1
        }
28 34
        $this->reflection = new ReflectionClass($className);
29 34
        $this->constructor = $this->findConstructorParams($this->reflection);
30 34
        $this->className = $className;
31 34
    }
32
33 19
    public function getMode()
34
    {
35 19
        return $this->mode;
36
    }
37
38 20
    public function __invoke()
39
    {
40 20
        return call_user_func_array(array($this, 'getInstance'), func_get_args());
41
    }
42
43
    public function getClassName()
44
    {
45
        return $this->className;
46
    }
47
48 31
    public function getInstance($forceNew = false)
49
    {
50 31
        if ($this->mode == static::MODE_FACTORY) {
51 1
            $this->instance = null;
52 1
        }
53
54 31
        if ($this->instance && !$forceNew) {
55 2
            return $this->instance;
56
        }
57
58 31
        $className     = $this->className;
59 31
        $staticMethods = count($this->staticMethodCalls);
60 31
        foreach ($this->staticMethodCalls as $methodCalls) {
61 2
            $this->performMethodCalls(
62 2
                $className,
63 2
                $methodCalls,
64
                function ($result) use ($className, &$instance, $staticMethods) {
65 2
                    if ($result instanceof $className || ($staticMethods == 1 && is_object($result))) {
66 2
                        $instance = $result;
67 2
                    }
68 2
                }
69 2
            );
70 31
        }
71
72 31
        $constructor     = $this->reflection->getConstructor();
73 31
        $hasConstructor  = ($constructor) ? $constructor->isPublic() : false;
74 31
        if (empty($instance)) {
75 29
            if (empty($this->constructor) || !$hasConstructor) {
76 12
                $instance = new $className();
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $instance, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
77 12
            } else {
78 18
                $instance = $this->reflection->newInstanceArgs(
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $instance, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
79 18
                    $this->cleanupParams($this->constructor)
80 18
                );
81
            }
82 29
        }
83
84 31
        foreach ($this->propertySetters as $property => $value) {
85 9
            $instance->{$property} = $this->lazyLoad($value);
86 31
        }
87
88 31
        foreach ($this->methodCalls as $methodCalls) {
89 7
            $this->performMethodCalls($instance, $methodCalls);
90 31
        }
91
92 31
        return $this->instance = $instance;
93
    }
94
95 3
    public function getParam($name)
96
    {
97 3
        return $this->params[$name];
98
    }
99
100
    public function setInstance($instance)
101
    {
102
        $this->instance = $instance;
103
    }
104
105 30
    public function setParam($name, $value)
106
    {
107 30
        $value = $this->processValue($value);
108
109 30
        if ($this->matchStaticMethod($name)) {
110 2
            $this->staticMethodCalls[] = array($name, $value);
111 30
        } elseif ($this->matchConstructorParam($name)) {
112 8
            $this->constructor[$name] = $value;
113 28
        } elseif ($this->matchFullConstructor($name, $value)) {
114 4
            $this->constructor = $value;
115 22
        } elseif ($this->matchMethod($name)) {
116 7
            $this->methodCalls[] = array($name, $value);
117 7
        } else {
118 12
            $this->propertySetters[$name] = $value;
119
        }
120
121 30
        $this->params[$name] = $value;
122 30
    }
123
124
    public function getParams()
125
    {
126
        return $this->params;
127
    }
128
129 21
    protected function cleanupParams(array $params)
130
    {
131 21
        while (null === end($params)) {
132 11
            unset($params[key($params)]);
133 11
        }
134
135 21
        foreach ($params as &$p) {
136 16
            $p = $this->lazyLoad($p);
137 21
        }
138
139 21
        return $params;
140
    }
141
142 25
    protected function lazyLoad($value)
143
    {
144 25
        return $value instanceof self ? $value->getInstance() : $value;
145
    }
146
147 34
    protected function findConstructorParams(ReflectionClass $class)
148
    {
149 34
        $params = array();
150 34
        $constructor = $class->getConstructor();
151
152 34
        if (!$constructor) {
153 14
            return array();
154
        }
155
156 21
        foreach ($constructor->getParameters() as $param) {
157 20
            $params[$param->getName()] = $param->isDefaultValueAvailable() ?
158 20
                $param->getDefaultValue() : null;
159 21
        }
160
161 21
        return $params;
162
    }
163
164 30
    protected function processValue($value)
165
    {
166 30
        if (is_array($value)) {
167 15
            foreach ($value as $valueKey => $subValue) {
168 15
                $value[$valueKey] = $this->processValue($subValue);
169 15
            }
170 15
        }
171
172 30
        return $value;
173
    }
174
175 28
    protected function matchConstructorParam($name)
176
    {
177 28
        return array_key_exists($name, $this->constructor);
178
    }
179
180 22
    protected function matchFullConstructor($name, &$value)
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
181
    {
182
        return $name == '__construct'
183 22
        || ($name == $this->className && stripos($this->className, '\\'));
184
    }
185
186 18
    protected function matchMethod($name)
187
    {
188 18
        return $this->reflection->hasMethod($name);
189
    }
190
191 30
    protected function matchStaticMethod($name)
192
    {
193 30
        return $this->reflection->hasMethod($name)
194 30
        && $this->reflection->getMethod($name)->isStatic();
195
    }
196
197 9
    protected function performMethodCalls($class, array $methodCalls, $resultCallback = null)
198
    {
199 9
        list($methodName, $calls) = $methodCalls;
200 9
        $resultCallback = $resultCallback ?: function () {
201
202 9
        };
203
204 9
        foreach ($calls as $arguments) {
205 9
            if (is_array($arguments)) {
206 7
                $resultCallback(call_user_func_array(
207 7
                    array($class, $methodName),
208 7
                    $this->cleanUpParams($arguments)
209 7
                ));
210 9
            } elseif (!is_null($arguments)) {
211 2
                $resultCallback(call_user_func(array($class, $methodName), $this->lazyLoad($arguments)));
212 2
            } else {
213 1
                $resultCallback(call_user_func(array($class, $methodName)));
214
            }
215 9
        }
216 9
    }
217
}
218