Complex classes like Container 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 Container, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
39 | class Container extends Component implements ContainerInterface, FactoryInterface, ResolverInterface |
||
40 | { |
||
41 | /** |
||
42 | * Outer container responsible for low level dependency configuration (i.e. config based). |
||
43 | * |
||
44 | * @var ContainerInterface |
||
45 | */ |
||
46 | private $outerContainer = null; |
||
47 | |||
48 | /** |
||
49 | * IoC bindings. |
||
50 | * |
||
51 | * @what-if private |
||
52 | * @invisible |
||
53 | * |
||
54 | * @var array |
||
55 | */ |
||
56 | protected $bindings = [ |
||
57 | ContainerInterface::class => self::class, |
||
58 | FactoryInterface::class => self::class, |
||
59 | ResolverInterface::class => self::class |
||
60 | ]; |
||
61 | |||
62 | /** |
||
63 | * List of classes responsible for handling specific instance or interface. Provides ability to |
||
64 | * delegate container functionality. |
||
65 | * |
||
66 | * @what-if private |
||
67 | * @invisible |
||
68 | * |
||
69 | * @var array |
||
70 | */ |
||
71 | protected $injectors = []; |
||
72 | |||
73 | /** |
||
74 | * Provide outer container in order to proxy get and has requests. |
||
75 | * |
||
76 | * @param ContainerInterface|null $outerContainer |
||
77 | */ |
||
78 | 61 | public function __construct(ContainerInterface $outerContainer = null) |
|
84 | |||
85 | /** |
||
86 | * Container can not be cloned. |
||
87 | */ |
||
88 | 1 | public function __clone() |
|
92 | |||
93 | /** |
||
94 | * {@inheritdoc} |
||
95 | */ |
||
96 | 6 | public function has($alias) |
|
104 | |||
105 | /** |
||
106 | * {@inheritdoc} |
||
107 | * |
||
108 | * Context parameter will be passed to class injectors, which makes possible to use this method |
||
109 | * as: |
||
110 | * $this->container->get(DatabaseInterface::class, 'default'); |
||
111 | * |
||
112 | * Attention, context ignored when outer container has instance by alias. |
||
113 | * |
||
114 | * @param string|null $context Call context. |
||
115 | * |
||
116 | * @throws ContainerException |
||
117 | */ |
||
118 | 35 | public function get($alias, string $context = null) |
|
131 | |||
132 | /** |
||
133 | 49 | * {@inheritdoc} |
|
134 | * |
||
135 | 49 | * @param string|null $context Related to parameter caused injection if any. |
|
136 | */ |
||
137 | 39 | final public function make(string $alias, $parameters = [], string $context = null) |
|
163 | |||
164 | /** |
||
165 | 4 | * {@inheritdoc} |
|
166 | 4 | * |
|
167 | 4 | * @param string $context |
|
168 | */ |
||
169 | final public function resolveArguments( |
||
234 | 9 | ||
235 | /** |
||
236 | 8 | * Bind value resolver to container alias. Resolver can be class name (will be constructed |
|
237 | 8 | * for each method call), function array or Closure (executed every call). Only object resolvers |
|
238 | * supported by this method. |
||
239 | * |
||
240 | * @param string $alias |
||
241 | 1 | * @param string|array|callable $resolver |
|
242 | * |
||
243 | * @return self |
||
244 | */ |
||
245 | final public function bind(string $alias, $resolver): Container |
||
258 | |||
259 | /** |
||
260 | 21 | * Bind value resolver to container alias to be executed as cached. Resolver can be class name |
|
261 | * (will be constructed only once), function array or Closure (executed only once call). |
||
262 | * |
||
263 | * @param string $alias |
||
264 | * @param string|array|callable $resolver |
||
265 | * |
||
266 | * @return self |
||
267 | */ |
||
268 | final public function bindSingleton(string $alias, $resolver): Container |
||
281 | |||
282 | 19 | /** |
|
283 | * Specify binding which has to be used for class injection. |
||
284 | 19 | * |
|
285 | * @param string $class |
||
286 | * @param string|object $injector |
||
287 | * |
||
288 | * @return self |
||
289 | */ |
||
290 | public function bindInjector(string $class, $injector): Container |
||
300 | 4 | ||
301 | /** |
||
302 | 4 | * Check if given class has associated injector. |
|
303 | * |
||
304 | * @param \ReflectionClass $reflection |
||
305 | 5 | * |
|
306 | * @return bool |
||
307 | 5 | */ |
|
308 | public function hasInjector(\ReflectionClass $reflection): bool |
||
317 | |||
318 | 5 | /** |
|
319 | * Check if alias points to constructed instance (singleton). |
||
320 | 5 | * |
|
321 | 1 | * @param string $alias |
|
322 | * |
||
323 | * @return bool |
||
324 | 4 | */ |
|
325 | final public function hasInstance(string $alias): bool |
||
338 | 25 | ||
339 | 3 | /** |
|
340 | * @param string $alias |
||
341 | */ |
||
342 | final public function removeBinding(string $alias) |
||
346 | |||
347 | /** |
||
348 | * @param string $class |
||
349 | */ |
||
350 | final public function removeInjector(string $class) |
||
354 | |||
355 | 2 | /** |
|
356 | 2 | * Every declared Container binding. Must not be used in production code due container format is |
|
357 | * vary. |
||
358 | * |
||
359 | 2 | * @return array |
|
360 | */ |
||
361 | 1 | final public function getBindings(): array |
|
365 | |||
366 | /** |
||
367 | * Every binded injector. |
||
368 | * |
||
369 | * @return array |
||
370 | 1 | */ |
|
371 | final public function getInjectors(): array |
||
375 | |||
376 | /** |
||
377 | * Automatically create class. |
||
378 | 1 | * |
|
379 | * @param string $class |
||
380 | 1 | * @param array $parameters |
|
381 | 1 | * @param string $context |
|
382 | * |
||
383 | * @return object |
||
384 | * |
||
385 | * @throws AutowireException |
||
386 | */ |
||
387 | final protected function autowire(string $class, array $parameters, string $context = null) |
||
404 | |||
405 | /** |
||
406 | * Register instance in container, might perform methods like auto-singletons, log populations |
||
407 | * and etc. Can be extended. |
||
408 | * |
||
409 | * @param object $instance Created object. |
||
410 | * @param array $parameters Parameters which been passed with created instance. |
||
411 | * |
||
412 | * @return object |
||
413 | */ |
||
414 | protected function registerInstance($instance, array $parameters) |
||
429 | |||
430 | 25 | /** |
|
431 | * @param string $alias |
||
432 | * @param mixed $target Value binded by user. |
||
433 | * @param array $parameters |
||
434 | * @param string|null $context |
||
435 | * |
||
436 | * @return mixed|null|object |
||
437 | * |
||
438 | * @throws \Spiral\Core\Exceptions\Container\ContainerException |
||
439 | */ |
||
440 | private function evaluateBinding( |
||
482 | |||
483 | /** |
||
484 | 28 | * Create instance of desired class. |
|
485 | 1 | * |
|
486 | * @param string $class |
||
487 | * @param array $parameters Constructor parameters. |
||
488 | 27 | * @param string|null $context |
|
489 | * |
||
490 | 21 | * @return object |
|
491 | 21 | * |
|
492 | * @throws ContainerException |
||
493 | */ |
||
494 | private function createInstance(string $class, array $parameters, string $context = null) |
||
525 | |||
526 | /** |
||
527 | * Get injector associated with given class. |
||
528 | * |
||
529 | * @param \ReflectionClass $reflection |
||
530 | * |
||
531 | * @return InjectorInterface |
||
532 | */ |
||
533 | private function getInjector(\ReflectionClass $reflection): InjectorInterface |
||
551 | 16 | ||
552 | 1 | /** |
|
553 | * Assert that given value are matched parameter type. |
||
554 | * |
||
555 | 16 | * @param \ReflectionParameter $parameter |
|
556 | 2 | * @param \ReflectionFunctionAbstract $context |
|
557 | * @param mixed $value |
||
558 | * |
||
559 | 16 | * @throws ArgumentException |
|
560 | 1 | */ |
|
561 | private function assertType( |
||
591 | } |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.