Complex classes like Names 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 Names, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | class Names implements RenderingInterface |
||
29 | { |
||
30 | use DelimiterTrait; |
||
31 | use AffixesTrait; |
||
32 | use FormattingTrait; |
||
33 | |||
34 | /** |
||
35 | * Variables (selected with the required variable attribute), each of which can contain multiple names (e.g. the |
||
36 | * “author” variable contains all the author names of the cited item). If multiple variables are selected |
||
37 | * (separated by single spaces, see example below), each variable is independently rendered in the order specified. |
||
38 | * |
||
39 | * @var ArrayList |
||
40 | */ |
||
41 | private $variables; |
||
42 | |||
43 | /** |
||
44 | * The Name element, an optional child element of Names, can be used to describe the formatting of individual |
||
45 | * names, and the separation of names within a name variable. |
||
46 | * |
||
47 | * @var Name |
||
48 | */ |
||
49 | private $name; |
||
50 | |||
51 | /** |
||
52 | * The optional Label element must be included after the Name and EtAl elements, but before |
||
53 | * the Substitute element. When used as a child element of Names, Label does not carry the variable |
||
54 | * attribute; it uses the variable(s) set on the parent Names element instead. |
||
55 | * |
||
56 | * @var Label |
||
57 | */ |
||
58 | private $label; |
||
59 | |||
60 | /** |
||
61 | * The optional Substitute element, which must be included as the last child element of Names, adds |
||
62 | * substitution in case the name variables specified in the parent cs:names element are empty. The substitutions |
||
63 | * are specified as child elements of Substitute, and must consist of one or more rendering elements (with the |
||
64 | * exception of Layout). A shorthand version of Names without child elements, which inherits the attributes |
||
65 | * values set on the cs:name and EtAl child elements of the original Names element, may also be used. If |
||
66 | * Substitute contains multiple child elements, the first element to return a non-empty result is used for |
||
67 | * substitution. Substituted variables are suppressed in the rest of the output to prevent duplication. An example, |
||
68 | * where an empty “author” name variable is substituted by the “editor” name variable, or, when no editors exist, |
||
69 | * by the “title” macro: |
||
70 | * |
||
71 | * <macro name="author"> |
||
72 | * <names variable="author"> |
||
73 | * <substitute> |
||
74 | * <names variable="editor"/> |
||
75 | * <text macro="title"/> |
||
76 | * </substitute> |
||
77 | * </names> |
||
78 | * </macro> |
||
79 | * |
||
80 | * @var Substitute |
||
81 | */ |
||
82 | private $substitute; |
||
83 | |||
84 | /** |
||
85 | * Et-al abbreviation, controlled via the et-al-... attributes (see Name), can be further customized with the |
||
86 | * optional cs:et-al element, which must follow the cs:name element (if present). The term attribute may be set to |
||
87 | * either “et-al” (the default) or to “and others” to use either term. The formatting attributes may also be used, |
||
88 | * for example to italicize the “et-al” term: |
||
89 | * |
||
90 | * @var EtAl |
||
91 | */ |
||
92 | private $etAl; |
||
93 | |||
94 | /** |
||
95 | * The delimiter attribute may be set on cs:names to separate the names of the different name variables (e.g. the |
||
96 | * semicolon in “Doe, Smith (editors); Johnson (translator)”). |
||
97 | * |
||
98 | * @var string |
||
99 | */ |
||
100 | private $delimiter = ", "; |
||
101 | |||
102 | /** |
||
103 | * Names constructor. |
||
104 | * @param \SimpleXMLElement $node |
||
105 | */ |
||
106 | public function __construct(\SimpleXMLElement $node) |
||
139 | |||
140 | /** |
||
141 | * This outputs the contents of one or more name variables (selected with the required variable attribute), each |
||
142 | * of which can contain multiple names (e.g. the “author” variable contains all the author names of the cited item). |
||
143 | * If multiple variables are selected (separated by single spaces), each variable is independently rendered in the |
||
144 | * order specified, with one exception: when the selection consists of “editor” and “translator”, and when the |
||
145 | * contents of these two name variables is identical, then the contents of only one name variable is rendered. In |
||
146 | * addition, the “editortranslator” term is used if the Names element contains a Label element, replacing the |
||
147 | * default “editor” and “translator” terms (e.g. resulting in “Doe (editor & translator)”). |
||
148 | * |
||
149 | * @param \stdClass $data |
||
150 | * @param int $citationNumber |
||
|
|||
151 | * @return string |
||
152 | */ |
||
153 | public function render($data, $citationNumber = null) |
||
214 | |||
215 | /** |
||
216 | * @return bool |
||
217 | */ |
||
218 | public function hasEtAl() |
||
222 | |||
223 | /** |
||
224 | * @return EtAl |
||
225 | */ |
||
226 | public function getEtAl() |
||
230 | |||
231 | /** |
||
232 | * @param EtAl $etAl |
||
233 | * @return $this |
||
234 | */ |
||
235 | public function setEtAl(EtAl $etAl) |
||
240 | |||
241 | /** |
||
242 | * @return bool |
||
243 | */ |
||
244 | public function hasName() |
||
248 | |||
249 | /** |
||
250 | * @return Name |
||
251 | */ |
||
252 | public function getName() |
||
256 | |||
257 | /** |
||
258 | * @param Name $name |
||
259 | * @return $this |
||
260 | */ |
||
261 | public function setName(Name $name) |
||
266 | |||
267 | public function getDelimiter() |
||
271 | |||
272 | public function getVariables() |
||
276 | |||
277 | public function hasLabel() |
||
281 | |||
282 | /** |
||
283 | * @return Label |
||
284 | */ |
||
285 | public function getLabel() |
||
289 | |||
290 | /** |
||
291 | * @param Label $label |
||
292 | */ |
||
293 | public function setLabel($label) |
||
297 | |||
298 | /** |
||
299 | * @param array $editor |
||
300 | * @param array $translator |
||
301 | * @return bool |
||
302 | */ |
||
303 | private function sameNames($editor, $translator) |
||
319 | } |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.