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 |
||
| 37 | trait ReflectionClassLikeTrait |
||
| 38 | { |
||
| 39 | use InitializationTrait; |
||
| 40 | |||
| 41 | /** |
||
| 42 | * @var ClassLike |
||
| 43 | */ |
||
| 44 | protected $classLikeNode; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Short name of the class, without namespace |
||
| 48 | * |
||
| 49 | * @var string |
||
| 50 | */ |
||
| 51 | protected $className; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * List of all constants from the class |
||
| 55 | * |
||
| 56 | * @var array |
||
| 57 | */ |
||
| 58 | protected $constants; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Interfaces, empty array or null if not initialized yet |
||
| 62 | * |
||
| 63 | * @var \ReflectionClass[]|array|null |
||
| 64 | */ |
||
| 65 | protected $interfaceClasses; |
||
| 66 | |||
| 67 | /** |
||
| 68 | * List of traits, empty array or null if not initialized yet |
||
| 69 | * |
||
| 70 | * @var \ReflectionClass[]|array|null |
||
| 71 | */ |
||
| 72 | protected $traits; |
||
| 73 | |||
| 74 | /** |
||
| 75 | * Additional list of trait adaptations |
||
| 76 | * |
||
| 77 | * @var TraitUseAdaptation[]|array |
||
| 78 | */ |
||
| 79 | protected $traitAdaptations; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * @var array|ReflectionMethod[] |
||
| 83 | */ |
||
| 84 | protected $methods; |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Namespace name |
||
| 88 | * |
||
| 89 | * @var string |
||
| 90 | */ |
||
| 91 | protected $namespaceName = ''; |
||
| 92 | |||
| 93 | /** |
||
| 94 | * Parent class, or false if not present, null if uninitialized yet |
||
| 95 | * |
||
| 96 | * @var \ReflectionClass|false|null |
||
| 97 | */ |
||
| 98 | protected $parentClass; |
||
| 99 | |||
| 100 | /** |
||
| 101 | * @var array|ReflectionProperty[] |
||
| 102 | */ |
||
| 103 | protected $properties; |
||
| 104 | |||
| 105 | /** |
||
| 106 | * @var array|ReflectionClassConstant[] |
||
| 107 | */ |
||
| 108 | protected $classConstants; |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Returns the string representation of the ReflectionClass object. |
||
| 112 | * |
||
| 113 | * @return string |
||
| 114 | */ |
||
| 115 | public function __toString() |
||
| 207 | |||
| 208 | |||
| 209 | /** |
||
| 210 | * {@inheritDoc} |
||
| 211 | */ |
||
| 212 | 10 | public function getConstant($name) |
|
| 220 | |||
| 221 | /** |
||
| 222 | * {@inheritDoc} |
||
| 223 | */ |
||
| 224 | 38 | public function getConstants() |
|
| 237 | |||
| 238 | /** |
||
| 239 | * {@inheritDoc} |
||
| 240 | */ |
||
| 241 | 19 | public function getConstructor() |
|
| 250 | |||
| 251 | /** |
||
| 252 | * Gets default properties from a class (including inherited properties). |
||
| 253 | * |
||
| 254 | * @link http://php.net/manual/en/reflectionclass.getdefaultproperties.php |
||
| 255 | * |
||
| 256 | * @return array An array of default properties, with the key being the name of the property and the value being |
||
| 257 | * the default value of the property or NULL if the property doesn't have a default value |
||
| 258 | */ |
||
| 259 | 29 | public function getDefaultProperties() |
|
| 288 | |||
| 289 | /** |
||
| 290 | * {@inheritDoc} |
||
| 291 | */ |
||
| 292 | 29 | public function getDocComment() |
|
| 298 | |||
| 299 | 29 | public function getEndLine() |
|
| 303 | |||
| 304 | 29 | public function getExtension() |
|
| 308 | |||
| 309 | 29 | public function getExtensionName() |
|
| 313 | |||
| 314 | 21 | public function getFileName() |
|
| 318 | |||
| 319 | /** |
||
| 320 | * {@inheritDoc} |
||
| 321 | */ |
||
| 322 | 30 | public function getInterfaceNames() |
|
| 326 | |||
| 327 | /** |
||
| 328 | * {@inheritDoc} |
||
| 329 | */ |
||
| 330 | 59 | public function getInterfaces() |
|
| 345 | |||
| 346 | /** |
||
| 347 | * {@inheritdoc} |
||
| 348 | * @param string $name |
||
| 349 | */ |
||
| 350 | 2047 | public function getMethod($name) |
|
| 361 | |||
| 362 | /** |
||
| 363 | * Returns list of reflection methods |
||
| 364 | * |
||
| 365 | * @param null|int $filter Optional filter |
||
| 366 | * |
||
| 367 | * @return array|\ReflectionMethod[] |
||
| 368 | */ |
||
| 369 | 2073 | public function getMethods($filter = null) |
|
| 402 | |||
| 403 | /** |
||
| 404 | * Returns a bitfield of the access modifiers for this class. |
||
| 405 | * |
||
| 406 | * @link http://php.net/manual/en/reflectionclass.getmodifiers.php |
||
| 407 | * |
||
| 408 | * NB: this method is not fully compatible with original value because of hidden internal constants |
||
| 409 | * |
||
| 410 | * @return int |
||
| 411 | */ |
||
| 412 | public function getModifiers() |
||
| 439 | |||
| 440 | /** |
||
| 441 | * {@inheritDoc} |
||
| 442 | */ |
||
| 443 | 3001 | public function getName() |
|
| 449 | |||
| 450 | /** |
||
| 451 | * {@inheritDoc} |
||
| 452 | */ |
||
| 453 | 50 | public function getNamespaceName() |
|
| 457 | |||
| 458 | /** |
||
| 459 | * {@inheritDoc} |
||
| 460 | */ |
||
| 461 | 235 | public function getParentClass() |
|
| 478 | |||
| 479 | /** |
||
| 480 | * Retrieves reflected properties. |
||
| 481 | * |
||
| 482 | * @param int $filter The optional filter, for filtering desired property types. |
||
| 483 | * It's configured using the ReflectionProperty constants, and defaults to all property types. |
||
| 484 | * |
||
| 485 | * @return ReflectionProperty[] |
||
| 486 | */ |
||
| 487 | 318 | public function getProperties($filter = null) |
|
| 522 | |||
| 523 | /** |
||
| 524 | * {@inheritdoc} |
||
| 525 | */ |
||
| 526 | 255 | public function getProperty($name) |
|
| 537 | |||
| 538 | /** |
||
| 539 | * @inheritDoc |
||
| 540 | */ |
||
| 541 | 3 | public function getReflectionConstant($name) |
|
| 552 | |||
| 553 | /** |
||
| 554 | * @inheritDoc |
||
| 555 | */ |
||
| 556 | 8 | public function getReflectionConstants() |
|
| 581 | |||
| 582 | /** |
||
| 583 | * {@inheritDoc} |
||
| 584 | */ |
||
| 585 | 3001 | public function getShortName() |
|
| 589 | |||
| 590 | 29 | public function getStartLine() |
|
| 594 | |||
| 595 | /** |
||
| 596 | * Returns an array of trait aliases |
||
| 597 | * |
||
| 598 | * @link http://php.net/manual/en/reflectionclass.gettraitaliases.php |
||
| 599 | * |
||
| 600 | * @return array|null an array with new method names in keys and original names (in the format |
||
| 601 | * "TraitName::original") in values. |
||
| 602 | */ |
||
| 603 | 33 | public function getTraitAliases() |
|
| 623 | |||
| 624 | /** |
||
| 625 | * Returns an array of names of traits used by this class |
||
| 626 | * |
||
| 627 | * @link http://php.net/manual/en/reflectionclass.gettraitnames.php |
||
| 628 | * |
||
| 629 | * @return array |
||
| 630 | */ |
||
| 631 | 29 | public function getTraitNames() |
|
| 635 | |||
| 636 | /** |
||
| 637 | * Returns an array of traits used by this class |
||
| 638 | * |
||
| 639 | * @link http://php.net/manual/en/reflectionclass.gettraits.php |
||
| 640 | * |
||
| 641 | * @return array|\ReflectionClass[] |
||
| 642 | */ |
||
| 643 | 230 | public function getTraits() |
|
| 656 | |||
| 657 | /** |
||
| 658 | * {@inheritDoc} |
||
| 659 | */ |
||
| 660 | 11 | public function hasConstant($name) |
|
| 667 | |||
| 668 | /** |
||
| 669 | * {@inheritdoc} |
||
| 670 | * @param string $name |
||
| 671 | */ |
||
| 672 | 20 | public function hasMethod($name) |
|
| 683 | |||
| 684 | /** |
||
| 685 | * {@inheritdoc} |
||
| 686 | */ |
||
| 687 | public function hasProperty($name) |
||
| 698 | |||
| 699 | /** |
||
| 700 | * {@inheritDoc} |
||
| 701 | * @param string $interfaceName |
||
| 702 | */ |
||
| 703 | 29 | public function implementsInterface($interfaceName) |
|
| 709 | |||
| 710 | /** |
||
| 711 | * {@inheritDoc} |
||
| 712 | */ |
||
| 713 | 29 | public function inNamespace() |
|
| 717 | |||
| 718 | /** |
||
| 719 | * {@inheritDoc} |
||
| 720 | */ |
||
| 721 | 75 | public function isAbstract() |
|
| 733 | |||
| 734 | /** |
||
| 735 | * Currently, anonymous classes aren't supported for parsed reflection |
||
| 736 | */ |
||
| 737 | public function isAnonymous() |
||
| 741 | |||
| 742 | /** |
||
| 743 | * {@inheritDoc} |
||
| 744 | */ |
||
| 745 | 29 | public function isCloneable() |
|
| 759 | |||
| 760 | /** |
||
| 761 | * {@inheritDoc} |
||
| 762 | */ |
||
| 763 | 29 | public function isFinal() |
|
| 769 | |||
| 770 | /** |
||
| 771 | * {@inheritDoc} |
||
| 772 | */ |
||
| 773 | public function isInstance($object) |
||
| 783 | |||
| 784 | /** |
||
| 785 | * {@inheritDoc} |
||
| 786 | */ |
||
| 787 | 29 | public function isInstantiable() |
|
| 799 | |||
| 800 | /** |
||
| 801 | * {@inheritDoc} |
||
| 802 | */ |
||
| 803 | 242 | public function isInterface() |
|
| 807 | |||
| 808 | /** |
||
| 809 | * {@inheritDoc} |
||
| 810 | */ |
||
| 811 | 29 | public function isInternal() |
|
| 816 | |||
| 817 | /** |
||
| 818 | * {@inheritDoc} |
||
| 819 | */ |
||
| 820 | 29 | public function isIterateable() |
|
| 824 | |||
| 825 | /** |
||
| 826 | * {@inheritDoc} |
||
| 827 | */ |
||
| 828 | public function isSubclassOf($class) |
||
| 853 | |||
| 854 | /** |
||
| 855 | * {@inheritDoc} |
||
| 856 | */ |
||
| 857 | 83 | public function isTrait() |
|
| 861 | |||
| 862 | /** |
||
| 863 | * {@inheritDoc} |
||
| 864 | */ |
||
| 865 | 29 | public function isUserDefined() |
|
| 870 | |||
| 871 | /** |
||
| 872 | * Gets static properties |
||
| 873 | * |
||
| 874 | * @link http://php.net/manual/en/reflectionclass.getstaticproperties.php |
||
| 875 | * |
||
| 876 | * @return array |
||
| 877 | */ |
||
| 878 | 30 | public function getStaticProperties() |
|
| 897 | |||
| 898 | /** |
||
| 899 | * Gets static property value |
||
| 900 | * |
||
| 901 | * @param string $name The name of the static property for which to return a value. |
||
| 902 | * @param mixed $default A default value to return in case the class does not declare |
||
| 903 | * a static property with the given name |
||
| 904 | * |
||
| 905 | * @return mixed |
||
| 906 | * @throws ReflectionException If there is no such property and no default value was given |
||
| 907 | */ |
||
| 908 | 1 | public function getStaticPropertyValue($name, $default = null) |
|
| 919 | |||
| 920 | |||
| 921 | /** |
||
| 922 | * Creates a new class instance from given arguments. |
||
| 923 | * |
||
| 924 | * @link http://php.net/manual/en/reflectionclass.newinstance.php |
||
| 925 | * |
||
| 926 | * Signature was hacked to support both 5.6, 7.1.x and 7.2.0 versions |
||
| 927 | * @see https://3v4l.org/hW9O9 |
||
| 928 | * @see https://3v4l.org/sWT3j |
||
| 929 | * @see https://3v4l.org/eeVf8 |
||
| 930 | * |
||
| 931 | * @param mixed $arg First argument |
||
| 932 | * @param mixed $args Accepts a variable number of arguments which are passed to the class constructor |
||
| 933 | * |
||
| 934 | * @return object |
||
| 935 | */ |
||
| 936 | 1 | public function newInstance($arg = null, ...$args) |
|
| 943 | |||
| 944 | /** |
||
| 945 | * Creates a new class instance from given arguments. |
||
| 946 | * |
||
| 947 | * @link http://php.net/manual/en/reflectionclass.newinstanceargs.php |
||
| 948 | * |
||
| 949 | * @param array $args The parameters to be passed to the class constructor as an array. |
||
| 950 | * |
||
| 951 | * @return object |
||
| 952 | */ |
||
| 953 | 1 | public function newInstanceArgs(array $args = []) |
|
| 960 | |||
| 961 | /** |
||
| 962 | * Creates a new class instance without invoking the constructor. |
||
| 963 | * |
||
| 964 | * @link http://php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php |
||
| 965 | * |
||
| 966 | * @return object |
||
| 967 | */ |
||
| 968 | 1 | public function newInstanceWithoutConstructor($args = null) |
|
| 975 | |||
| 976 | /** |
||
| 977 | * Sets static property value |
||
| 978 | * |
||
| 979 | * @link http://php.net/manual/en/reflectionclass.setstaticpropertyvalue.php |
||
| 980 | * |
||
| 981 | * @param string $name Property name |
||
| 982 | * @param mixed $value New property value |
||
| 983 | */ |
||
| 984 | 1 | public function setStaticPropertyValue($name, $value) |
|
| 990 | |||
| 991 | 172 | private function recursiveCollect(Closure $collector) |
|
| 1013 | |||
| 1014 | /** |
||
| 1015 | * Collects list of constants from the class itself |
||
| 1016 | */ |
||
| 1017 | 38 | private function collectSelfConstants() |
|
| 1037 | |||
| 1038 | /** |
||
| 1039 | * Create a ReflectionClass for a given class name. |
||
| 1040 | * |
||
| 1041 | * @param string $className |
||
| 1042 | * The name of the class to create a reflection for. |
||
| 1043 | * |
||
| 1044 | * @return ReflectionClass |
||
| 1045 | * The appropriate reflection object. |
||
| 1046 | */ |
||
| 1047 | abstract protected function createReflectionForClass(string $className); |
||
| 1048 | } |
||
| 1049 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: