Complex classes like MethodDescriptor 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 MethodDescriptor, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
24 | class MethodDescriptor extends DescriptorAbstract implements Interfaces\MethodInterface, Interfaces\VisibilityInterface |
||
25 | { |
||
26 | /** @var ClassDescriptor|InterfaceDescriptor|TraitDescriptor $parent */ |
||
27 | protected $parent; |
||
28 | |||
29 | /** @var bool $abstract */ |
||
30 | protected $abstract = false; |
||
31 | |||
32 | /** @var bool $final */ |
||
33 | protected $final = false; |
||
34 | |||
35 | /** @var bool $static */ |
||
36 | protected $static = false; |
||
37 | |||
38 | /** @var string $visibility */ |
||
39 | protected $visibility = 'public'; |
||
40 | |||
41 | /** @var Collection */ |
||
42 | protected $arguments; |
||
43 | |||
44 | /** @var Type */ |
||
45 | private $returnType; |
||
46 | |||
47 | /** |
||
48 | * Initializes the all properties representing a collection with a new Collection object. |
||
49 | */ |
||
50 | 1 | public function __construct() |
|
56 | |||
57 | /** |
||
58 | * @param ClassDescriptor|InterfaceDescriptor|TraitDescriptor $parent |
||
59 | */ |
||
60 | 1 | public function setParent($parent) |
|
61 | { |
||
62 | 1 | $this->setFullyQualifiedStructuralElementName( |
|
63 | 1 | $parent->getFullyQualifiedStructuralElementName() . '::' . $this->getName() . '()' |
|
64 | ); |
||
65 | |||
66 | // reset cached inherited element so that it can be re-detected. |
||
67 | 1 | $this->inheritedElement = null; |
|
68 | |||
69 | 1 | $this->parent = $parent; |
|
70 | 1 | } |
|
71 | |||
72 | /** |
||
73 | * @return ClassDescriptor|InterfaceDescriptor|TraitDescriptor |
||
74 | */ |
||
75 | 1 | public function getParent() |
|
76 | { |
||
77 | 1 | return $this->parent; |
|
78 | } |
||
79 | |||
80 | /** |
||
81 | * {@inheritDoc} |
||
82 | */ |
||
83 | 1 | public function setAbstract($abstract) |
|
87 | |||
88 | /** |
||
89 | * {@inheritDoc} |
||
90 | */ |
||
91 | 1 | public function isAbstract() |
|
95 | |||
96 | /** |
||
97 | * {@inheritDoc} |
||
98 | */ |
||
99 | 1 | public function setFinal($final) |
|
103 | |||
104 | /** |
||
105 | * {@inheritDoc} |
||
106 | */ |
||
107 | 1 | public function isFinal() |
|
111 | |||
112 | /** |
||
113 | * {@inheritDoc} |
||
114 | */ |
||
115 | 1 | public function setStatic($static) |
|
119 | |||
120 | /** |
||
121 | * {@inheritDoc} |
||
122 | */ |
||
123 | 1 | public function isStatic() |
|
127 | |||
128 | /** |
||
129 | * {@inheritDoc} |
||
130 | */ |
||
131 | 1 | public function setVisibility($visibility) |
|
135 | |||
136 | /** |
||
137 | * {@inheritDoc} |
||
138 | */ |
||
139 | 1 | public function getVisibility() |
|
143 | |||
144 | /** |
||
145 | * {@inheritDoc} |
||
146 | */ |
||
147 | 1 | public function setArguments(Collection $arguments) |
|
156 | |||
157 | /** |
||
158 | * @param string $name |
||
159 | */ |
||
160 | 1 | public function addArgument($name, ArgumentDescriptor $argument) |
|
165 | |||
166 | /** |
||
167 | * {@inheritDoc} |
||
168 | */ |
||
169 | 1 | public function getArguments() |
|
173 | |||
174 | 2 | public function getResponse(): ReturnDescriptor |
|
189 | |||
190 | /** |
||
191 | * Returns the file associated with the parent class, interface or trait. |
||
192 | * |
||
193 | * @return FileDescriptor |
||
194 | */ |
||
195 | 1 | public function getFile() |
|
199 | |||
200 | /** |
||
201 | * @return Collection |
||
202 | */ |
||
203 | 1 | public function getReturn() |
|
218 | |||
219 | /** |
||
220 | * @return Collection |
||
221 | */ |
||
222 | 1 | public function getParam() |
|
237 | |||
238 | /** |
||
239 | * Returns the Method from which this method should inherit its information, if any. |
||
240 | * |
||
241 | * The inheritance scheme for a method is more complicated than for most elements; the following business rules |
||
242 | * apply: |
||
243 | * |
||
244 | * 1. if the parent class/interface extends another class or other interfaces (interfaces have multiple |
||
245 | * inheritance!) then: |
||
246 | * 1. Check each parent class/interface's parent if they have a method with the exact same name |
||
247 | * 2. if a method is found with the same name; return the first one encountered. |
||
248 | * 2. if the parent is a class and implements interfaces, check each interface for a method with the exact same |
||
249 | * name. If such a method is found, return the first hit. |
||
250 | * |
||
251 | * @return MethodDescriptor|null |
||
252 | */ |
||
253 | public function getInheritedElement() |
||
303 | |||
304 | /** |
||
305 | * Sets return type of this method. |
||
306 | */ |
||
307 | 1 | public function setReturnType(Type $returnType) |
|
311 | } |
||
312 |
If you implement
__call
and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.This is often the case, when
__call
is implemented by a parent class and only the child class knows which methods exist: