Injector   B
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 221
c 0
b 0
f 0
wmc 40
lcom 1
cbo 0
rs 8.2608

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 3
A build() 0 4 1
A param() 0 4 2
A addRequirement() 0 8 2
A get() 0 16 4
C loadInjection() 0 45 14
B buildParams() 0 15 5
B buildCalls() 0 22 6
A makeObject() 0 15 3

How to fix   Complexity   

Complex Class

Complex classes like Injector often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Injector, and based on these observations, apply Extract Interface, too.

1
<?php /** MicroInjector */
2
3
namespace Micro\Base;
4
5
6
/**
7
 * Class Injector
8
 *
9
 * @author Oleg Lunegov <[email protected]>
10
 * @link https://github.com/linpax/microphp-framework
11
 * @copyright Copyright (c) 2013 Oleg Lunegov
12
 * @license https://github.com/linpax/microphp-framework/blob/master/LICENSE
13
 * @package Micro
14
 * @subpackage Base
15
 * @version 1.0
16
 * @since 1.0
17
 */
18
class Injector implements InjectorInterface
19
{
20
    /** @var array $CONFIG Configuration */
21
    private static $CONFIG = [];
22
    /** @var array $INJECTS Configured injects */
23
    private static $INJECTS = [];
24
25
    /**
26
     * Injector constructor.
27
     *
28
     * @access public
29
     * @param string $configPath
30
     * @result void
31
     */
32
    public function __construct($configPath = '')
33
    {
34
        if ($configPath !== '' && file_exists($configPath)) {
35
            /** @noinspection PhpIncludeInspection */
36
            self::$CONFIG = array_merge_recursive(self::$CONFIG, require $configPath);
37
        }
38
    }
39
40
    /**
41
     * @return null
42
     */
43
    public function build()
44
    {
45
        return null; // Replace this in your code
46
    }
47
48
    /**
49
     * @param string $name
50
     * @return string
51
     */
52
    public function param($name)
53
    {
54
        return array_key_exists($name, self::$CONFIG) ? self::$CONFIG[$name] : null;
55
    }
56
57
    /**
58
     * Add requirement to injector
59
     *
60
     * @access public
61
     * @param string $name
62
     * @param mixed $component
63
     * @return void
64
     */
65
    public function addRequirement($name, $component)
66
    {
67
        if (is_object($component)) {
68
            self::$INJECTS[$name] = $component;
69
        } else {
70
            self::$CONFIG[$name] = $component;
71
        }
72
    }
73
74
    /**
75
     * Build object with injector
76
     *
77
     * class LogInject extends Injector {
78
     *  public function build() {
79
     *   return $this->get('logger');
80
     *  }
81
     * }
82
     * $log = (new LogInject())->build();
83
     *
84
     * @access protected
85
     * @param string $name
86
     * @return boolean|mixed
87
     */
88
    protected function get($name)
89
    {
90
        if (!empty(self::$CONFIG[$name])) {
91
            return self::$CONFIG[$name];
92
        }
93
94
        if (!empty(self::$INJECTS[$name])) {
95
            return self::$INJECTS[$name];
96
        }
97
98
        if (!empty(self::$CONFIG['components'][$name])) {
99
            return $this->loadInjection($name);
100
        }
101
102
        return false;
103
    }
104
105
    /**
106
     * Load injection
107
     *
108
     * @access public
109
     *
110
     * @param string $name Name injection
111
     *
112
     * @return boolean|mixed
113
     */
114
    private function loadInjection($name)
115
    {
116
        $options = self::$CONFIG['components'][$name];
117
118
        if (empty($options['class']) || !class_exists($options['class'])) {
119
            return false;
120
        }
121
122
        $className = $options['class'];
123
124
        $options['arguments'] = !empty($options['arguments']) ? $this->buildParams($options['arguments']) : [];
125
        $options['property'] = !empty($options['property']) ? $this->buildParams($options['property']) : [];
126
        $options['calls'] = !empty($options['calls']) ? $this->buildCalls($options['calls']) : [];
127
128
        /** Depends via construction */
129
        self::$INJECTS[$name] = $this->makeObject($className, $options['arguments']);
130
        if (!self::$INJECTS[$name]) {
131
            return false;
132
        }
133
134
        /** Depends via property */
135
        if (!empty($options['property'])) { // load properties
136
            foreach ($options['property'] as $property => $value) {
137
                if (property_exists(self::$INJECTS[$name], $property)) {
138
                    self::$INJECTS[$name]->$property = $value;
139
                }
140
            }
141
        }
142
143
        /** Depends via calls */
144
        if (!empty($options['calls'])) { // run methods
145
            foreach ($options['calls'] as $method => $arguments) {
146
                if (method_exists(self::$INJECTS[$name], $method)) {
147
                    $reflectionMethod = new \ReflectionMethod($className, $method);
148
                    if ($reflectionMethod->getNumberOfParameters() === 0) {
149
                        self::$INJECTS[$name]->$method();
150
                    } else {
151
                        call_user_func_array([self::$INJECTS[$name], $method], $arguments);
152
                    }
153
                }
154
            }
155
        }
156
157
        return self::$INJECTS[$name];
158
    }
159
160
    /**
161
     * Build params from array
162
     *
163
     * @access private
164
     * @param array $params
165
     * @return array
166
     */
167
    private function buildParams(array $params)
168
    {
169
        /** @noinspection AlterInForeachInspection */
170
        foreach ($params AS $key => &$val) { // IoC Constructor
171
            if (is_string($params[$key]) && (0 === strpos($val, '@'))) {
172
                if ($val === '@this') {
173
                    $val = $this;
174
                } else {
175
                    $val = $this->get(substr($val, 1));
176
                }
177
            }
178
        }
179
180
        return $params;
181
    }
182
183
    /**
184
     * Build calls arguments
185
     *
186
     * @access private
187
     * @param array $params
188
     * @return array
189
     */
190
    private function buildCalls(array $params)
191
    {
192
        $callers = [];
193
194
        if (!is_array($params[0])) {
195
            $params = [
196
                $params
197
            ];
198
        }
199
200
        foreach ($params as $arguments) {
201
            if (is_string($arguments[0])) {
202
                if (!empty($arguments[1]) && is_array($arguments[1])) {
203
                    $callers[$arguments[0]] = $this->buildParams($arguments[1]);
204
                } else {
205
                    $callers[$arguments[0]] = null;
206
                }
207
            }
208
        }
209
210
        return $callers;
211
    }
212
213
    /**
214
     * Make object with arguments
215
     *
216
     * @access private
217
     *
218
     * @param string $className
219
     * @param array $arguments
220
     *
221
     * @return mixed
222
     */
223
    private function makeObject($className, array $arguments = [])
224
    {
225
        try {
226
            $reflection = new \ReflectionClass($className);
227
            $reflectionMethod = new \ReflectionMethod($className, '__construct');
228
229
            if ($reflectionMethod->getNumberOfParameters() === 0) {
230
                return new $className;
231
            } else {
232
                return $reflection->newInstanceArgs($arguments);
233
            }
234
        } catch (Exception $e) {
235
            return false;
236
        }
237
    }
238
}