Complex classes like AbstractObject 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 AbstractObject, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
58 | abstract class AbstractObject implements ObjectInterface |
||
59 | { |
||
60 | /** |
||
61 | * Clean state |
||
62 | * |
||
63 | * @var int |
||
64 | */ |
||
65 | const STATE_CLEAN = 0; |
||
66 | /** |
||
67 | * Dirty state |
||
68 | * |
||
69 | * @var int |
||
70 | */ |
||
71 | const STATE_DIRTY = 1; |
||
72 | /** |
||
73 | * Mutated state |
||
74 | * |
||
75 | * @var int |
||
76 | */ |
||
77 | const STATE_MUTATED = 2; |
||
78 | /** |
||
79 | * System properties |
||
80 | * |
||
81 | * @var SystemProperties |
||
82 | */ |
||
83 | protected $systemProperties; |
||
84 | /** |
||
85 | * Meta properties |
||
86 | * |
||
87 | * @var MetaProperties |
||
88 | */ |
||
89 | protected $metaProperties; |
||
90 | /** |
||
91 | * Domain properties |
||
92 | * |
||
93 | * @var AbstractDomainProperties |
||
94 | */ |
||
95 | protected $domainProperties; |
||
96 | /** |
||
97 | * Object payload |
||
98 | * |
||
99 | * @var string |
||
100 | */ |
||
101 | protected $payload; |
||
102 | /** |
||
103 | * Repository path |
||
104 | * |
||
105 | * @var RepositoryPathInterface |
||
106 | */ |
||
107 | protected $path; |
||
108 | /** |
||
109 | * Domain property collection class |
||
110 | * |
||
111 | * @var string |
||
112 | */ |
||
113 | protected $domainPropertyCClass = AbstractDomainProperties::class; |
||
114 | /** |
||
115 | * Object relations |
||
116 | * |
||
117 | * @var Relations |
||
118 | */ |
||
119 | protected $relations; |
||
120 | /** |
||
121 | * Processing instructions |
||
122 | * |
||
123 | * @var ProcessingInstructions |
||
124 | */ |
||
125 | protected $processingInstructions; |
||
126 | /** |
||
127 | * Latest revision index |
||
128 | * |
||
129 | * @var Revision |
||
130 | */ |
||
131 | protected $latestRevision; |
||
132 | /** |
||
133 | * Object state |
||
134 | * |
||
135 | * @var int |
||
136 | */ |
||
137 | protected $state = self::STATE_CLEAN; |
||
138 | /** |
||
139 | * Property collection states |
||
140 | * |
||
141 | * @var array |
||
142 | */ |
||
143 | protected $collectionStates = []; |
||
144 | |||
145 | /** |
||
146 | * Object constructor |
||
147 | * |
||
148 | * @param string $payload Object payload |
||
149 | * @param array $propertyData Property data |
||
150 | * @param RepositoryPathInterface $path Object repository path |
||
151 | */ |
||
152 | 21 | public function __construct($payload = '', array $propertyData = [], RepositoryPathInterface $path = null) |
|
176 | |||
177 | /** |
||
178 | * Load object revision data |
||
179 | * |
||
180 | * @param string $payload Object payload |
||
181 | * @param array $propertyData Property data |
||
182 | */ |
||
183 | 20 | protected function loadRevisionData($payload = '', array $propertyData = []) |
|
233 | |||
234 | /** |
||
235 | * Set the meta properties collection |
||
236 | * |
||
237 | * @param MetaProperties $metaProperties Meta property collection |
||
238 | * @param bool $overwrite Overwrite the existing collection (if present) |
||
239 | */ |
||
240 | 18 | protected function setMetaProperties(MetaProperties $metaProperties, $overwrite = false) |
|
256 | |||
257 | /** |
||
258 | * Set the object state to mutated |
||
259 | */ |
||
260 | 2 | protected function setMutatedState() |
|
292 | |||
293 | /** |
||
294 | * Return the object draft mode |
||
295 | * |
||
296 | * @return boolean Object draft mode |
||
297 | */ |
||
298 | 3 | public function isDraft() |
|
302 | |||
303 | /** |
||
304 | * Set the domain properties collection |
||
305 | * |
||
306 | * @param GenericPropertiesInterface $domainProperties Domain property collection |
||
307 | * @param bool $overwrite Overwrite the existing collection (if present) |
||
308 | */ |
||
309 | 18 | protected function setDomainProperties(GenericPropertiesInterface $domainProperties, $overwrite = false) |
|
325 | |||
326 | /** |
||
327 | * Set the processing instruction collection |
||
328 | * |
||
329 | * @param GenericPropertiesInterface $processingInstructions Processing instruction collection |
||
330 | * @param bool $overwrite Overwrite the existing collection (if present) |
||
331 | */ |
||
332 | 18 | protected function setProcessingInstructions(GenericPropertiesInterface $processingInstructions, $overwrite = false) |
|
348 | |||
349 | /** |
||
350 | * Set the object state to dirty |
||
351 | */ |
||
352 | 1 | protected function setDirtyState() |
|
362 | |||
363 | /** |
||
364 | * Set the relations collection |
||
365 | * |
||
366 | * @param Relations $relations Relations collection |
||
367 | * @param bool $overwrite Overwrite the existing collection (if present) |
||
368 | */ |
||
369 | 18 | protected function setRelations(Relations $relations, $overwrite = false) |
|
385 | |||
386 | /** |
||
387 | * Return the object revision |
||
388 | * |
||
389 | * @return Revision Object revision |
||
390 | */ |
||
391 | 18 | public function getRevision() |
|
395 | |||
396 | /** |
||
397 | * Return whether the object is in mutated state |
||
398 | * |
||
399 | * @return boolean Mutated state |
||
400 | */ |
||
401 | 3 | public function isMutated() |
|
405 | |||
406 | /** |
||
407 | * Use a specific object revision |
||
408 | * |
||
409 | * @param Revision $revision Revision to be used |
||
410 | * @return ObjectInterface Object |
||
411 | * @throws OutOfBoundsException If the requested revision is invalid |
||
412 | */ |
||
413 | 17 | public function useRevision(Revision $revision) |
|
453 | |||
454 | /** |
||
455 | * Return the object ID |
||
456 | * |
||
457 | * @return Id Object ID |
||
458 | */ |
||
459 | 5 | public function getId() |
|
463 | |||
464 | /** |
||
465 | * Return the object type |
||
466 | * |
||
467 | * @return Type Object type |
||
468 | */ |
||
469 | 1 | public function getType() |
|
473 | |||
474 | /** |
||
475 | * Return the creation date & time |
||
476 | * |
||
477 | * @return \DateTimeImmutable Creation date & time |
||
478 | */ |
||
479 | 1 | public function getCreated() |
|
483 | |||
484 | /** |
||
485 | * Return the publication date & time |
||
486 | * |
||
487 | * @return \DateTimeImmutable Publication date & time |
||
488 | */ |
||
489 | 1 | public function getPublished() |
|
493 | |||
494 | /** |
||
495 | * Return the object hash |
||
496 | * |
||
497 | * @return string Object hash |
||
498 | */ |
||
499 | 1 | public function getHash() |
|
503 | |||
504 | /** |
||
505 | * Return the object description |
||
506 | * |
||
507 | * @return string Object description |
||
508 | */ |
||
509 | 2 | public function getDescription() |
|
513 | |||
514 | /** |
||
515 | * Set the description |
||
516 | * |
||
517 | * @param string $description Description |
||
518 | * @return ObjectInterface Self reference |
||
519 | */ |
||
520 | 1 | public function setDescription($description) |
|
525 | |||
526 | /** |
||
527 | * Return the object abstract |
||
528 | * |
||
529 | * @return string Object abstract |
||
530 | */ |
||
531 | 2 | public function getAbstract() |
|
535 | |||
536 | /** |
||
537 | * Set the abstract |
||
538 | * |
||
539 | * @param string $abstract Abstract |
||
540 | * @return ObjectInterface Self reference |
||
541 | */ |
||
542 | 1 | public function setAbstract($abstract) |
|
547 | |||
548 | /** |
||
549 | * Return all object keywords |
||
550 | * |
||
551 | * @return array Object keywords |
||
552 | */ |
||
553 | 2 | public function getKeywords() |
|
557 | |||
558 | /** |
||
559 | * Set the keywords |
||
560 | * |
||
561 | * @param array $keywords Keywords |
||
562 | * @return ObjectInterface Self reference |
||
563 | */ |
||
564 | 1 | public function setKeywords(array $keywords) |
|
569 | |||
570 | /** |
||
571 | * Return all object categories |
||
572 | * |
||
573 | * @return array Object categories |
||
574 | */ |
||
575 | 2 | public function getCategories() |
|
579 | |||
580 | /** |
||
581 | * Set the categories |
||
582 | * |
||
583 | * @param array $categories Categories |
||
584 | * @return ObjectInterface Self reference |
||
585 | */ |
||
586 | 1 | public function setCategories(array $categories) |
|
591 | |||
592 | /** |
||
593 | * Return all object authors |
||
594 | * |
||
595 | * @return AuthorInterface[] Authors |
||
596 | */ |
||
597 | 2 | public function getAuthors() |
|
601 | |||
602 | /** |
||
603 | * Add an object author |
||
604 | * |
||
605 | * @param AuthorInterface $author Author |
||
606 | * @return ObjectInterface Self reference |
||
607 | */ |
||
608 | 1 | public function addAuthor(AuthorInterface $author) |
|
615 | |||
616 | /** |
||
617 | * Return the object repository path |
||
618 | * |
||
619 | * @return RepositoryPathInterface Object repository path |
||
620 | */ |
||
621 | 18 | public function getRepositoryPath() |
|
625 | |||
626 | /** |
||
627 | * Return the object property data |
||
628 | * |
||
629 | * @return array Object property data |
||
630 | */ |
||
631 | 5 | public function getPropertyData() |
|
645 | |||
646 | /** |
||
647 | * Return the object payload |
||
648 | * |
||
649 | * @return string Object payload |
||
650 | */ |
||
651 | 2 | public function getPayload() |
|
655 | |||
656 | /** |
||
657 | * Set the payload |
||
658 | * |
||
659 | * @param string $payload Payload |
||
660 | * @return ObjectInterface Self reference |
||
661 | */ |
||
662 | public function setPayload($payload) |
||
672 | |||
673 | /** |
||
674 | * Return the absolute object URL |
||
675 | * |
||
676 | * @return string |
||
677 | */ |
||
678 | 4 | public function getAbsoluteUrl() |
|
682 | |||
683 | /** |
||
684 | * Get a domain property value |
||
685 | * |
||
686 | * Multi-level properties might be traversed by property name paths separated with colons (":"). |
||
687 | * |
||
688 | * @param string $property Property name |
||
689 | * @return mixed Property value |
||
690 | */ |
||
691 | 2 | public function getDomainProperty($property) |
|
695 | |||
696 | /** |
||
697 | * Set a domain property value |
||
698 | * |
||
699 | * @param string $property Property name |
||
700 | * @param mixed $value Property value |
||
701 | * @return ObjectInterface Self reference |
||
702 | */ |
||
703 | 1 | public function setDomainProperty($property, $value) |
|
708 | |||
709 | /** |
||
710 | * Get a processing instruction |
||
711 | * |
||
712 | * @param string $procInst Processing instruction name |
||
713 | * @return mixed Processing instruction |
||
714 | */ |
||
715 | public function getProcessingInstruction($procInst) |
||
719 | |||
720 | /** |
||
721 | * Set a processing instruction |
||
722 | * |
||
723 | * @param string $procInst Processing instruction name |
||
724 | * @param mixed $value Processing instruction |
||
725 | * @return ObjectInterface Self reference |
||
726 | */ |
||
727 | 1 | public function setProcessingInstruction($procInst, $value) |
|
732 | |||
733 | /** |
||
734 | * Persist the current object revision |
||
735 | * |
||
736 | * @return ObjectInterface Object |
||
737 | */ |
||
738 | public function persist() |
||
760 | |||
761 | /** |
||
762 | * Return whether the object is in dirty state |
||
763 | * |
||
764 | * @return boolean Dirty state |
||
765 | */ |
||
766 | 3 | public function isDirty() |
|
770 | } |
||
771 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.
Either this assignment is in error or an instanceof check should be added for that assignment.