Complex classes like ViewHelperResolver 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 ViewHelperResolver, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | class ViewHelperResolver |
||
24 | { |
||
25 | |||
26 | /** |
||
27 | * @var array |
||
28 | */ |
||
29 | protected $resolvedViewHelperClassNames = []; |
||
30 | |||
31 | /** |
||
32 | * Namespaces requested by the template being rendered, |
||
33 | * in [shortname => phpnamespace] format. |
||
34 | * |
||
35 | * @var array |
||
36 | */ |
||
37 | protected $namespaces = [ |
||
38 | 'f' => ['TYPO3Fluid\\Fluid\\ViewHelpers'] |
||
39 | ]; |
||
40 | |||
41 | /** |
||
42 | * @return array |
||
43 | */ |
||
44 | public function getNamespaces() |
||
48 | |||
49 | /** |
||
50 | * Add a PHP namespace where ViewHelpers can be found and give |
||
51 | * it an alias/identifier. |
||
52 | * |
||
53 | * The provided namespace can be either a single namespace or |
||
54 | * an array of namespaces, as strings. The identifier/alias is |
||
55 | * always a single, alpha-numeric ASCII string. |
||
56 | * |
||
57 | * Calling this method multiple times with different PHP namespaces |
||
58 | * for the same alias causes that namespace to be *extended*, |
||
59 | * meaning that the PHP namespace you provide second, third etc. |
||
60 | * are also used in lookups and are used *first*, so that if any |
||
61 | * of the namespaces you add contains a class placed and named the |
||
62 | * same way as one that exists in an earlier namespace, then your |
||
63 | * class gets used instead of the earlier one. |
||
64 | * |
||
65 | * Example: |
||
66 | * |
||
67 | * $resolver->addNamespace('my', 'My\Package\ViewHelpers'); |
||
68 | * // Any ViewHelpers under this namespace can now be accessed using for example {my:example()} |
||
69 | * // Now, assuming you also have an ExampleViewHelper class in a different |
||
70 | * // namespace and wish to make that ExampleViewHelper override the other: |
||
71 | * $resolver->addNamespace('my', 'My\OtherPackage\ViewHelpers'); |
||
72 | * // Now, since ExampleViewHelper exists in both places but the |
||
73 | * // My\OtherPackage\ViewHelpers namespace was added *last*, Fluid |
||
74 | * // will find and use My\OtherPackage\ViewHelpers\ExampleViewHelper. |
||
75 | * |
||
76 | * Alternatively, setNamespaces() can be used to reset and redefine |
||
77 | * all previously added namespaces - which is great for cases where |
||
78 | * you need to remove or replace previously added namespaces. Be aware |
||
79 | * that setNamespaces() also removes the default "f" namespace, so |
||
80 | * when you use this method you should always include the "f" namespace. |
||
81 | * |
||
82 | * @param string $identifier |
||
83 | * @param string|array $phpNamespace |
||
84 | * @return void |
||
85 | */ |
||
86 | public function addNamespace($identifier, $phpNamespace) |
||
87 | { |
||
88 | if (!array_key_exists($identifier, $this->namespaces) || $this->namespaces[$identifier] === null) { |
||
89 | $this->namespaces[$identifier] = $phpNamespace === null ? null : (array) $phpNamespace; |
||
90 | } elseif (is_array($phpNamespace)) { |
||
91 | $this->namespaces[$identifier] = array_unique(array_merge($this->namespaces[$identifier], $phpNamespace)); |
||
92 | } elseif (isset($this->namespaces[$identifier]) && !in_array($phpNamespace, $this->namespaces[$identifier])) { |
||
93 | $this->namespaces[$identifier][] = $phpNamespace; |
||
94 | } |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Wrapper to allow adding namespaces in bulk *without* first |
||
99 | * clearing the already added namespaces. Utility method mainly |
||
100 | * used in compiled templates, where some namespaces can be added |
||
101 | * from outside and some can be added from compiled values. |
||
102 | * |
||
103 | * @param array $namespaces |
||
104 | * @return void |
||
105 | */ |
||
106 | public function addNamespaces(array $namespaces) |
||
112 | |||
113 | /** |
||
114 | * Resolves the PHP namespace based on the Fluid xmlns namespace, |
||
115 | * which can be either a URL matching the Patterns::NAMESPACEPREFIX |
||
116 | * and Patterns::NAMESPACESUFFIX rules, or a PHP namespace. When |
||
117 | * namespace is a PHP namespace it is optional to suffix it with |
||
118 | * the "\ViewHelpers" segment, e.g. "My\Package" is as valid to |
||
119 | * use as "My\Package\ViewHelpers" is. |
||
120 | * |
||
121 | * @param string $fluidNamespace |
||
122 | * @return string |
||
123 | */ |
||
124 | public function resolvePhpNamespaceFromFluidNamespace($fluidNamespace) |
||
140 | |||
141 | /** |
||
142 | * Set all namespaces as an array of ['identifier' => ['Php\Namespace1', 'Php\Namespace2']] |
||
143 | * namespace definitions. For convenience and legacy support, a |
||
144 | * format of ['identifier' => 'Only\Php\Namespace'] is allowed, |
||
145 | * but will internally convert the namespace to an array and |
||
146 | * allow it to be extended by addNamespace(). |
||
147 | * |
||
148 | * Note that when using this method the default "f" namespace is |
||
149 | * also removed and so must be included in $namespaces or added |
||
150 | * after using addNamespace(). Or, add the PHP namespaces that |
||
151 | * belonged to "f" as a new alias and use that in your templates. |
||
152 | * |
||
153 | * Use getNamespaces() to get an array of currently added namespaces. |
||
154 | * |
||
155 | * @param array $namespaces |
||
156 | * @return void |
||
157 | */ |
||
158 | public function setNamespaces(array $namespaces) |
||
165 | |||
166 | /** |
||
167 | * Validates the given namespaceIdentifier and returns FALSE |
||
168 | * if the namespace is unknown, causing the tag to be rendered |
||
169 | * without processing. |
||
170 | * |
||
171 | * @param string $namespaceIdentifier |
||
172 | * @return boolean TRUE if the given namespace is valid, otherwise FALSE |
||
173 | */ |
||
174 | public function isNamespaceValid($namespaceIdentifier) |
||
186 | |||
187 | /** |
||
188 | * Validates the given namespaceIdentifier and returns FALSE |
||
189 | * if the namespace is unknown and not ignored |
||
190 | * |
||
191 | * @param string $namespaceIdentifier |
||
192 | * @return boolean TRUE if the given namespace is valid, otherwise FALSE |
||
193 | */ |
||
194 | public function isNamespaceValidOrIgnored($namespaceIdentifier) |
||
210 | |||
211 | /** |
||
212 | * @param string $namespaceIdentifier |
||
213 | * @return boolean |
||
214 | */ |
||
215 | public function isNamespaceIgnored($namespaceIdentifier) |
||
231 | |||
232 | /** |
||
233 | * Resolves a ViewHelper class name by namespace alias and |
||
234 | * Fluid-format identity, e.g. "f" and "format.htmlspecialchars". |
||
235 | * |
||
236 | * Looks in all PHP namespaces which have been added for the |
||
237 | * provided alias, starting in the last added PHP namespace. If |
||
238 | * a ViewHelper class exists in multiple PHP namespaces Fluid |
||
239 | * will detect and use whichever one was added last. |
||
240 | * |
||
241 | * If no ViewHelper class can be detected in any of the added |
||
242 | * PHP namespaces a Fluid Parser Exception is thrown. |
||
243 | * |
||
244 | * @param string $namespaceIdentifier |
||
245 | * @param string $methodIdentifier |
||
246 | * @return string|NULL |
||
247 | * @throws ParserException |
||
248 | */ |
||
249 | public function resolveViewHelperClassName($namespaceIdentifier, $methodIdentifier) |
||
257 | |||
258 | /** |
||
259 | * Can be overridden by custom implementations to change the way |
||
260 | * classes are loaded when the class is a ViewHelper - for |
||
261 | * example making it possible to use a DI-aware class loader. |
||
262 | * |
||
263 | * @param string $namespace |
||
264 | * @param string $viewHelperShortName |
||
265 | * @return ViewHelperInterface |
||
266 | */ |
||
267 | public function createViewHelperInstance($namespace, $viewHelperShortName) |
||
272 | |||
273 | /** |
||
274 | * Wrapper to create a ViewHelper instance by class name. This is |
||
275 | * the final method called when creating ViewHelper classes - |
||
276 | * overriding this method allows custom constructors, dependency |
||
277 | * injections etc. to be performed on the ViewHelper instance. |
||
278 | * |
||
279 | * @param string $viewHelperClassName |
||
280 | * @return ViewHelperInterface |
||
281 | */ |
||
282 | public function createViewHelperInstanceFromClassName($viewHelperClassName) |
||
286 | |||
287 | /** |
||
288 | * Return an array of ArgumentDefinition instances which describe |
||
289 | * the arguments that the ViewHelper supports. By default, the |
||
290 | * arguments are simply fetched from the ViewHelper - but custom |
||
291 | * implementations can if necessary add/remove/replace arguments |
||
292 | * which will be passed to the ViewHelper. |
||
293 | * |
||
294 | * @param ViewHelperInterface $viewHelper |
||
295 | * @return ArgumentDefinition[] |
||
296 | */ |
||
297 | public function getArgumentDefinitionsForViewHelper(ViewHelperInterface $viewHelper) |
||
301 | |||
302 | /** |
||
303 | * Resolve a viewhelper name. |
||
304 | * |
||
305 | * @param string $namespaceIdentifier Namespace identifier for the view helper. |
||
306 | * @param string $methodIdentifier Method identifier, might be hierarchical like "link.url" |
||
307 | * @return string The fully qualified class name of the viewhelper |
||
308 | */ |
||
309 | protected function resolveViewHelperName($namespaceIdentifier, $methodIdentifier) |
||
356 | } |
||
357 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.