Complex classes like ReflectionClassLikeTrait 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 ReflectionClassLikeTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
29 | trait ReflectionClassLikeTrait |
||
30 | { |
||
31 | use InitializationTrait; |
||
32 | |||
33 | /** |
||
34 | * @var ClassLike |
||
35 | */ |
||
36 | protected $classLikeNode; |
||
37 | |||
38 | /** |
||
39 | * Short name of the class, without namespace |
||
40 | * |
||
41 | * @var string |
||
42 | */ |
||
43 | protected $className; |
||
44 | |||
45 | /** |
||
46 | * List of all constants from the class |
||
47 | * |
||
48 | * @var array |
||
49 | */ |
||
50 | protected $constants; |
||
51 | |||
52 | /** |
||
53 | * Interfaces, empty array or null if not initialized yet |
||
54 | * |
||
55 | * @var \ReflectionClass[]|array|null |
||
56 | */ |
||
57 | protected $interfaceClasses; |
||
58 | |||
59 | /** |
||
60 | * List of traits, empty array or null if not initialized yet |
||
61 | * |
||
62 | * @var \ReflectionClass[]|array|null |
||
63 | */ |
||
64 | protected $traits; |
||
65 | |||
66 | /** |
||
67 | * Additional list of trait adaptations |
||
68 | * |
||
69 | * @var TraitUseAdaptation[]|array |
||
70 | */ |
||
71 | protected $traitAdaptations; |
||
72 | |||
73 | /** |
||
74 | * @var array|ReflectionMethod[] |
||
75 | */ |
||
76 | protected $methods; |
||
77 | |||
78 | /** |
||
79 | * Namespace name |
||
80 | * |
||
81 | * @var string |
||
82 | */ |
||
83 | protected $namespaceName = ''; |
||
84 | |||
85 | /** |
||
86 | * Parent class, or false if not present, null if uninitialized yet |
||
87 | * |
||
88 | * @var \ReflectionClass|false|null |
||
89 | */ |
||
90 | protected $parentClass; |
||
91 | |||
92 | /** |
||
93 | * @var array|ReflectionProperty[] |
||
94 | */ |
||
95 | protected $properties; |
||
96 | |||
97 | /** |
||
98 | * Returns the string representation of the ReflectionClass object. |
||
99 | * |
||
100 | * @return string |
||
101 | */ |
||
102 | public function __toString() |
||
103 | { |
||
104 | $isObject = $this instanceof \ReflectionObject; |
||
105 | |||
106 | $staticProperties = $staticMethods = $defaultProperties = $dynamicProperties = $methods = []; |
||
107 | |||
108 | $format = "%s [ <user> %sclass %s%s%s ] {\n"; |
||
109 | $format .= " @@ %s %d-%d\n\n"; |
||
110 | $format .= " - Constants [%d] {%s\n }\n\n"; |
||
111 | $format .= " - Static properties [%d] {%s\n }\n\n"; |
||
112 | $format .= " - Static methods [%d] {%s\n }\n\n"; |
||
113 | $format .= " - Properties [%d] {%s\n }\n\n"; |
||
114 | $format .= ($isObject ? " - Dynamic properties [%d] {%s\n }\n\n" : '%s%s'); |
||
115 | $format .= " - Methods [%d] {%s\n }\n"; |
||
116 | $format .= "}\n"; |
||
117 | |||
118 | foreach ($this->getProperties() as $property) { |
||
119 | if ($property->isStatic()) { |
||
120 | $staticProperties[] = $property; |
||
121 | } elseif ($property->isDefault()) { |
||
122 | $defaultProperties[] = $property; |
||
123 | } else { |
||
124 | $dynamicProperties[] = $property; |
||
125 | } |
||
126 | } |
||
127 | |||
128 | foreach ($this->getMethods() as $method) { |
||
129 | if ($method->isStatic()) { |
||
130 | $staticMethods[] = $method; |
||
131 | } else { |
||
132 | $methods[] = $method; |
||
133 | } |
||
134 | } |
||
135 | |||
136 | $buildString = function (array $items, $indentLevel = 4) { |
||
137 | if (!count($items)) { |
||
138 | return ''; |
||
139 | } |
||
140 | $indent = "\n" . str_repeat(' ', $indentLevel); |
||
141 | return $indent . implode($indent, explode("\n", implode("\n", $items))); |
||
142 | }; |
||
143 | $buildConstants = function (array $items, $indentLevel = 4) { |
||
144 | $str = ''; |
||
145 | foreach ($items as $name => $value) { |
||
146 | $str .= "\n" . str_repeat(' ', $indentLevel); |
||
147 | $str .= sprintf( |
||
148 | 'Constant [ %s %s ] { %s }', |
||
149 | gettype($value), |
||
150 | $name, |
||
151 | $value |
||
152 | ); |
||
153 | } |
||
154 | return $str; |
||
155 | }; |
||
156 | $interfaceNames = $this->getInterfaceNames(); |
||
157 | $parentClass = $this->getParentClass(); |
||
158 | $modifiers = ''; |
||
159 | if ($this->isAbstract()) { |
||
160 | $modifiers = 'abstract '; |
||
161 | } elseif ($this->isFinal()) { |
||
162 | $modifiers = 'final '; |
||
163 | }; |
||
164 | |||
165 | $string = sprintf( |
||
166 | $format, |
||
167 | ($isObject ? 'Object of class' : 'Class'), |
||
168 | $modifiers, |
||
169 | $this->getName(), |
||
170 | false !== $parentClass ? (' extends ' . $parentClass->getName()) : '', |
||
171 | $interfaceNames ? (' implements ' . implode(', ', $interfaceNames)) : '', |
||
172 | $this->getFileName(), |
||
173 | $this->getStartLine(), |
||
174 | $this->getEndLine(), |
||
175 | count($this->getConstants()), |
||
176 | $buildConstants($this->getConstants()), |
||
177 | count($staticProperties), |
||
178 | $buildString($staticProperties), |
||
179 | count($staticMethods), |
||
180 | $buildString($staticMethods), |
||
181 | count($defaultProperties), |
||
182 | $buildString($defaultProperties), |
||
183 | $isObject ? count($dynamicProperties) : '', |
||
184 | $isObject ? $buildString($dynamicProperties) : '', |
||
185 | count($methods), |
||
186 | $buildString($methods) |
||
187 | ); |
||
188 | |||
189 | return $string; |
||
190 | } |
||
191 | |||
192 | |||
193 | /** |
||
194 | * {@inheritDoc} |
||
195 | */ |
||
196 | 6 | public function getConstant($name) |
|
204 | |||
205 | /** |
||
206 | * {@inheritDoc} |
||
207 | */ |
||
208 | 26 | public function getConstants() |
|
219 | |||
220 | /** |
||
221 | * {@inheritDoc} |
||
222 | */ |
||
223 | 13 | public function getConstructor() |
|
232 | |||
233 | /** |
||
234 | * Gets default properties from a class (including inherited properties). |
||
235 | * |
||
236 | * @link http://php.net/manual/en/reflectionclass.getdefaultproperties.php |
||
237 | * |
||
238 | * @return array An array of default properties, with the key being the name of the property and the value being |
||
239 | * the default value of the property or NULL if the property doesn't have a default value |
||
240 | */ |
||
241 | 22 | public function getDefaultProperties() |
|
267 | |||
268 | /** |
||
269 | * {@inheritDoc} |
||
270 | */ |
||
271 | 22 | public function getDocComment() |
|
277 | |||
278 | 22 | public function getEndLine() |
|
282 | |||
283 | 22 | public function getExtension() |
|
287 | |||
288 | 22 | public function getExtensionName() |
|
292 | |||
293 | 11 | public function getFileName() |
|
297 | |||
298 | /** |
||
299 | * {@inheritDoc} |
||
300 | */ |
||
301 | 22 | public function getInterfaceNames() |
|
305 | |||
306 | /** |
||
307 | * {@inheritDoc} |
||
308 | */ |
||
309 | 22 | public function getInterfaces() |
|
322 | |||
323 | /** |
||
324 | * {@inheritdoc} |
||
325 | */ |
||
326 | 25 | public function getMethod($name) |
|
337 | |||
338 | /** |
||
339 | * Returns list of reflection methods |
||
340 | * |
||
341 | * @param null|integer $filter Optional filter |
||
342 | * |
||
343 | * @return array|\ReflectionMethod[] |
||
344 | */ |
||
345 | 70 | public function getMethods($filter = null) |
|
376 | |||
377 | /** |
||
378 | * Returns a bitfield of the access modifiers for this class. |
||
379 | * |
||
380 | * @link http://php.net/manual/en/reflectionclass.getmodifiers.php |
||
381 | * |
||
382 | * NB: this method is not fully compatible with original value because of hidden internal constants |
||
383 | * |
||
384 | * @return int |
||
385 | */ |
||
386 | 21 | public function getModifiers() |
|
413 | |||
414 | /** |
||
415 | * {@inheritDoc} |
||
416 | */ |
||
417 | 80 | public function getName() |
|
423 | |||
424 | /** |
||
425 | * {@inheritDoc} |
||
426 | */ |
||
427 | 29 | public function getNamespaceName() |
|
431 | |||
432 | /** |
||
433 | * {@inheritDoc} |
||
434 | */ |
||
435 | 102 | public function getParentClass() |
|
452 | |||
453 | /** |
||
454 | * Retrieves reflected properties. |
||
455 | * |
||
456 | * @param int $filter The optional filter, for filtering desired property types. |
||
457 | * It's configured using the ReflectionProperty constants, and defaults to all property types. |
||
458 | * |
||
459 | * @return array|\Go\ParserReflection\ReflectionProperty[] |
||
460 | */ |
||
461 | 46 | public function getProperties($filter = null) |
|
494 | |||
495 | /** |
||
496 | * {@inheritdoc} |
||
497 | */ |
||
498 | 3 | public function getProperty($name) |
|
509 | |||
510 | /** |
||
511 | * {@inheritDoc} |
||
512 | */ |
||
513 | 80 | public function getShortName() |
|
517 | |||
518 | 22 | public function getStartLine() |
|
522 | |||
523 | /** |
||
524 | * Returns an array of trait aliases |
||
525 | * |
||
526 | * @link http://php.net/manual/en/reflectionclass.gettraitaliases.php |
||
527 | * |
||
528 | * @return array|null an array with new method names in keys and original names (in the format "TraitName::original") in |
||
529 | * values. |
||
530 | */ |
||
531 | 41 | public function getTraitAliases() |
|
551 | |||
552 | /** |
||
553 | * Returns an array of names of traits used by this class |
||
554 | * |
||
555 | * @link http://php.net/manual/en/reflectionclass.gettraitnames.php |
||
556 | * |
||
557 | * @return array |
||
558 | */ |
||
559 | 22 | public function getTraitNames() |
|
563 | |||
564 | /** |
||
565 | * Returns an array of traits used by this class |
||
566 | * |
||
567 | * @link http://php.net/manual/en/reflectionclass.gettraits.php |
||
568 | * |
||
569 | * @return array|\ReflectionClass[] |
||
570 | */ |
||
571 | 102 | public function getTraits() |
|
581 | |||
582 | /** |
||
583 | * {@inheritDoc} |
||
584 | */ |
||
585 | 7 | public function hasConstant($name) |
|
592 | |||
593 | /** |
||
594 | * {@inheritdoc} |
||
595 | */ |
||
596 | 15 | public function hasMethod($name) |
|
607 | |||
608 | /** |
||
609 | * {@inheritdoc} |
||
610 | */ |
||
611 | public function hasProperty($name) |
||
622 | |||
623 | /** |
||
624 | * {@inheritDoc} |
||
625 | */ |
||
626 | 22 | public function implementsInterface($interfaceName) |
|
632 | |||
633 | /** |
||
634 | * {@inheritDoc} |
||
635 | */ |
||
636 | 22 | public function inNamespace() |
|
640 | |||
641 | /** |
||
642 | * {@inheritDoc} |
||
643 | */ |
||
644 | 22 | public function isAbstract() |
|
656 | |||
657 | /** |
||
658 | * Currently, anonymous classes aren't supported for parsed reflection |
||
659 | */ |
||
660 | public function isAnonymous() |
||
664 | |||
665 | /** |
||
666 | * {@inheritDoc} |
||
667 | */ |
||
668 | 22 | public function isCloneable() |
|
680 | |||
681 | /** |
||
682 | * {@inheritDoc} |
||
683 | */ |
||
684 | 43 | public function isFinal() |
|
690 | |||
691 | /** |
||
692 | * {@inheritDoc} |
||
693 | */ |
||
694 | public function isInstance($object) |
||
704 | |||
705 | /** |
||
706 | * {@inheritDoc} |
||
707 | */ |
||
708 | 22 | public function isInstantiable() |
|
720 | |||
721 | /** |
||
722 | * {@inheritDoc} |
||
723 | */ |
||
724 | 43 | public function isInterface() |
|
728 | |||
729 | /** |
||
730 | * {@inheritDoc} |
||
731 | */ |
||
732 | 22 | public function isInternal() |
|
737 | |||
738 | /** |
||
739 | * {@inheritDoc} |
||
740 | */ |
||
741 | 22 | public function isIterateable() |
|
745 | |||
746 | /** |
||
747 | * {@inheritDoc} |
||
748 | */ |
||
749 | public function isSubclassOf($class) |
||
772 | |||
773 | /** |
||
774 | * {@inheritDoc} |
||
775 | */ |
||
776 | 22 | public function isTrait() |
|
780 | |||
781 | /** |
||
782 | * {@inheritDoc} |
||
783 | */ |
||
784 | 22 | public function isUserDefined() |
|
789 | |||
790 | /** |
||
791 | * Gets static properties |
||
792 | * |
||
793 | * @link http://php.net/manual/en/reflectionclass.getstaticproperties.php |
||
794 | * |
||
795 | * @return array |
||
796 | */ |
||
797 | 23 | public function getStaticProperties() |
|
818 | |||
819 | /** |
||
820 | * Gets static property value |
||
821 | * |
||
822 | * @param string $name The name of the static property for which to return a value. |
||
823 | * @param mixed $default A default value to return in case the class does not declare |
||
824 | * a static property with the given name |
||
825 | * |
||
826 | * @return mixed |
||
827 | * @throws ReflectionException If there is no such property and no default value was given |
||
828 | */ |
||
829 | 1 | public function getStaticPropertyValue($name, $default = null) |
|
840 | |||
841 | |||
842 | /** |
||
843 | * Creates a new class instance from given arguments. |
||
844 | * |
||
845 | * @link http://php.net/manual/en/reflectionclass.newinstance.php |
||
846 | * @param mixed $args Accepts a variable number of arguments which are passed to the class constructor |
||
847 | * |
||
848 | * @return object |
||
849 | */ |
||
850 | 1 | public function newInstance($args = null) |
|
856 | |||
857 | /** |
||
858 | * Creates a new class instance from given arguments. |
||
859 | * |
||
860 | * @link http://php.net/manual/en/reflectionclass.newinstanceargs.php |
||
861 | * |
||
862 | * @param array $args The parameters to be passed to the class constructor as an array. |
||
863 | * |
||
864 | * @return object |
||
865 | */ |
||
866 | 1 | public function newInstanceArgs(array $args = []) |
|
873 | |||
874 | /** |
||
875 | * Creates a new class instance without invoking the constructor. |
||
876 | * |
||
877 | * @link http://php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php |
||
878 | * |
||
879 | * @return object |
||
880 | */ |
||
881 | 1 | public function newInstanceWithoutConstructor($args = null) |
|
888 | |||
889 | /** |
||
890 | * Sets static property value |
||
891 | * |
||
892 | * @link http://php.net/manual/en/reflectionclass.setstaticpropertyvalue.php |
||
893 | * |
||
894 | * @param string $name Property name |
||
895 | * @param mixed $value New property value |
||
896 | */ |
||
897 | 1 | public function setStaticPropertyValue($name, $value) |
|
903 | |||
904 | 102 | private function recursiveCollect(\Closure $collector) |
|
926 | |||
927 | /** |
||
928 | * Collects list of constants from the class itself |
||
929 | */ |
||
930 | 26 | private function collectSelfConstants() |
|
949 | } |
||
950 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.