Complex classes like Context 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 Context, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
32 | class Context |
||
33 | { |
||
34 | private $parent; |
||
35 | /*private $repository;*/ |
||
36 | private $registry = []; |
||
37 | private $variables = []; |
||
38 | private $contexts = []; |
||
39 | private $types = []; |
||
40 | private $wrappers = []; |
||
41 | |||
42 | public function __construct($parent) |
||
46 | |||
47 | public function willUse($preference) |
||
58 | |||
59 | /** |
||
60 | * @param string $name |
||
61 | */ |
||
62 | public function forVariable($name) |
||
66 | |||
67 | /** |
||
68 | * @param string $type |
||
69 | */ |
||
70 | public function whenCreating($type) |
||
78 | |||
79 | /** |
||
80 | * @param string $type |
||
81 | */ |
||
82 | public function forType($type) |
||
90 | |||
91 | public function wrapWith($type) |
||
95 | |||
96 | public function create($type, $nesting = []) |
||
97 | { |
||
98 | $lifecycle = $this->pickFactory($type, $this->repository()->candidatesFor($type)); |
||
99 | $context = $this->determineContext($lifecycle->class); |
||
100 | $wrapper = $context->hasWrapper($type, $nesting); |
||
101 | |||
102 | if ($wrapper) { |
||
103 | return $this->create($wrapper, $this->cons($wrapper, $nesting)); |
||
104 | } |
||
105 | |||
106 | $instance = $lifecycle->instantiate( |
||
107 | $context->createDependencies( |
||
108 | $this->repository()->getConstructorParameters($lifecycle->class), |
||
109 | $this->cons($lifecycle->class, $nesting) |
||
110 | ) |
||
111 | ); |
||
112 | |||
113 | $this->invokeSetters($context, $nesting, $lifecycle->class, $instance); |
||
114 | |||
115 | return $instance; |
||
116 | } |
||
117 | |||
118 | public function pickFactory($type, $candidates) |
||
135 | |||
136 | public function hasWrapper($type, $already_applied) |
||
147 | |||
148 | private function invokeSetters($context, $nesting, $class, $instance) |
||
161 | |||
162 | private function settersFor($class) |
||
168 | |||
169 | public function wrappersFor($type) |
||
173 | |||
174 | public function createDependencies($parameters, $nesting) |
||
190 | |||
191 | private function instantiateParameter($parameter, $nesting) |
||
212 | |||
213 | private function determineContext($class) |
||
223 | |||
224 | private function invoke($instance, $method, $arguments) |
||
228 | |||
229 | private function preferFrom($candidates) |
||
239 | |||
240 | private function cons($head, $tail) |
||
246 | |||
247 | public function repository() |
||
251 | } |
||
252 |
Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a
@return
annotation as described here.