Complex classes like Structure 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 Structure, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | abstract class Structure extends Element implements |
||
16 | \Countable, |
||
17 | \IteratorAggregate |
||
18 | { |
||
19 | use UniversalClass; |
||
20 | |||
21 | /** |
||
22 | * Array of elements in the structure. |
||
23 | * |
||
24 | * @var Element[] $_elements |
||
25 | */ |
||
26 | protected $_elements; |
||
27 | |||
28 | /** |
||
29 | * Lookup table for the tagged elements. |
||
30 | * |
||
31 | * @var TaggedType[]|null $_taggedMap |
||
32 | */ |
||
33 | private $_taggedMap; |
||
34 | |||
35 | /** |
||
36 | * Cache variable of elements wrapped into UnspecifiedType objects. |
||
37 | * |
||
38 | * @var UnspecifiedType[]|null $_unspecifiedTypes |
||
39 | */ |
||
40 | private $_unspecifiedTypes; |
||
41 | |||
42 | /** |
||
43 | * Constructor. |
||
44 | * |
||
45 | * @param ElementBase ...$elements Any number of elements |
||
46 | */ |
||
47 | 51 | public function __construct(ElementBase ...$elements) |
|
54 | |||
55 | /** |
||
56 | * Clone magic method. |
||
57 | */ |
||
58 | 15 | public function __clone() |
|
64 | |||
65 | /** |
||
66 | * |
||
67 | * @see \ASN1\Element::isConstructed() |
||
68 | * @return bool |
||
69 | */ |
||
70 | 15 | public function isConstructed(): bool |
|
74 | |||
75 | /** |
||
76 | * |
||
77 | * @see \ASN1\Element::_encodedContentDER() |
||
78 | * @return string |
||
79 | */ |
||
80 | 14 | protected function _encodedContentDER(): string |
|
88 | |||
89 | /** |
||
90 | * |
||
91 | * {@inheritdoc} |
||
92 | * @see \ASN1\Element::_decodeFromDER() |
||
93 | * @return self |
||
94 | */ |
||
95 | 21 | protected static function _decodeFromDER(Identifier $identifier, |
|
113 | |||
114 | /** |
||
115 | * Decode elements for a definite length. |
||
116 | * |
||
117 | * @param string $data DER data |
||
118 | * @param int $offset Offset to data |
||
119 | * @param int $length Number of bytes to decode |
||
120 | * @throws DecodeException |
||
121 | * @return ElementBase |
||
122 | */ |
||
123 | 14 | private static function _decodeDefiniteLength(string $data, int &$offset, |
|
141 | |||
142 | /** |
||
143 | * Decode elements for an indefinite length. |
||
144 | * |
||
145 | * @param string $data DER data |
||
146 | * @param int $offset Offset to data |
||
147 | * @throws DecodeException |
||
148 | * @return ElementBase |
||
149 | */ |
||
150 | 4 | private static function _decodeIndefiniteLength(string $data, int &$offset): ElementBase |
|
171 | |||
172 | /** |
||
173 | * Explode DER structure to DER encoded components that it contains. |
||
174 | * |
||
175 | * @param string $data |
||
176 | * @throws DecodeException |
||
177 | * @return string[] |
||
178 | */ |
||
179 | 2 | public static function explodeDER(string $data): array |
|
207 | |||
208 | /** |
||
209 | * Get self with an element at the given index replaced by another. |
||
210 | * |
||
211 | * @param int $idx Element index |
||
212 | * @param Element $el New element to insert into the structure |
||
213 | * @throws \OutOfBoundsException |
||
214 | * @return self |
||
215 | */ |
||
216 | 2 | public function withReplaced(int $idx, Element $el): self |
|
226 | |||
227 | /** |
||
228 | * Get self with an element inserted before the given index. |
||
229 | * |
||
230 | * @param int $idx Element index |
||
231 | * @param Element $el New element to insert into the structure |
||
232 | * @throws \OutOfBoundsException |
||
233 | * @return self |
||
234 | */ |
||
235 | 4 | public function withInserted(int $idx, Element $el): self |
|
244 | |||
245 | /** |
||
246 | * Get self with an element appended to the end. |
||
247 | * |
||
248 | * @param Element $el Element to insert into the structure |
||
249 | * @return self |
||
250 | */ |
||
251 | 2 | public function withAppended(Element $el): self |
|
257 | |||
258 | /** |
||
259 | * Get self with an element prepended in the beginning. |
||
260 | * |
||
261 | * @param Element $el Element to insert into the structure |
||
262 | * @return self |
||
263 | */ |
||
264 | 1 | public function withPrepended(Element $el): self |
|
270 | |||
271 | /** |
||
272 | * Get self with an element at the given index removed. |
||
273 | * |
||
274 | * @param int $idx Element index |
||
275 | * @throws \OutOfBoundsException |
||
276 | * @return self |
||
277 | */ |
||
278 | 4 | public function withoutElement(int $idx): self |
|
288 | |||
289 | /** |
||
290 | * Get elements in the structure. |
||
291 | * |
||
292 | * @return UnspecifiedType[] |
||
293 | */ |
||
294 | 2 | public function elements(): array |
|
304 | |||
305 | /** |
||
306 | * Check whether the structure has an element at the given index, optionally |
||
307 | * satisfying given tag expectation. |
||
308 | * |
||
309 | * @param int $idx Index 0..n |
||
310 | * @param int|null $expectedTag Optional type tag expectation |
||
311 | * @return bool |
||
312 | */ |
||
313 | 8 | public function has(int $idx, $expectedTag = null): bool |
|
325 | |||
326 | /** |
||
327 | * Get the element at the given index, optionally checking that the element |
||
328 | * has a given tag. |
||
329 | * |
||
330 | * <strong>NOTE!</strong> Expectation checking is deprecated and should be |
||
331 | * done with <code>UnspecifiedType</code>. |
||
332 | * |
||
333 | * @param int $idx Index 0..n |
||
334 | * @param int|null $expectedTag Optional type tag expectation |
||
335 | * @throws \OutOfBoundsException If element doesn't exists |
||
336 | * @throws \UnexpectedValueException If expectation fails |
||
337 | * @return UnspecifiedType |
||
338 | */ |
||
339 | 6 | public function at(int $idx, $expectedTag = null): UnspecifiedType |
|
351 | |||
352 | /** |
||
353 | * Check whether the structure contains a context specific element with a |
||
354 | * given tag. |
||
355 | * |
||
356 | * @param int $tag Tag number |
||
357 | * @return bool |
||
358 | */ |
||
359 | 6 | public function hasTagged(int $tag): bool |
|
372 | |||
373 | /** |
||
374 | * Get a context specific element tagged with a given tag. |
||
375 | * |
||
376 | * @param int $tag |
||
377 | * @throws \LogicException If tag doesn't exists |
||
378 | * @return TaggedType |
||
379 | */ |
||
380 | 3 | public function getTagged(int $tag): TaggedType |
|
387 | |||
388 | /** |
||
389 | * |
||
390 | * @see \Countable::count() |
||
391 | * @return int |
||
392 | */ |
||
393 | 4 | public function count(): int |
|
397 | |||
398 | /** |
||
399 | * Get an iterator for the UnspecifiedElement objects. |
||
400 | * |
||
401 | * @see \IteratorAggregate::getIterator() |
||
402 | * @return \ArrayIterator |
||
403 | */ |
||
404 | 1 | public function getIterator(): \ArrayIterator |
|
408 | } |
||
409 |