Complex classes like Configuration 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 Configuration, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
42 | class Configuration implements ConfigurationInterface |
||
43 | { |
||
44 | |||
45 | /** |
||
46 | * Mapping for boolean values passed on the console. |
||
47 | * |
||
48 | * @var array |
||
49 | */ |
||
50 | protected $booleanMapping = array( |
||
51 | 'true' => true, |
||
52 | 'false' => false, |
||
53 | '1' => true, |
||
54 | '0' => false, |
||
55 | 'on' => true, |
||
56 | 'off' => false |
||
57 | ); |
||
58 | |||
59 | /** |
||
60 | * The operation name to use. |
||
61 | * |
||
62 | * @var string |
||
63 | * @Type("string") |
||
64 | * @SerializedName("operation-name") |
||
65 | */ |
||
66 | protected $operationName; |
||
67 | |||
68 | /** |
||
69 | * The Magento edition, EE or CE. |
||
70 | * |
||
71 | * @var string |
||
72 | * @Type("string") |
||
73 | * @SerializedName("magento-edition") |
||
74 | */ |
||
75 | protected $magentoEdition = 'CE'; |
||
76 | |||
77 | /** |
||
78 | * The Magento version, e. g. 2.1.0. |
||
79 | * |
||
80 | * @var string |
||
81 | * @Type("string") |
||
82 | * @SerializedName("magento-version") |
||
83 | */ |
||
84 | protected $magentoVersion = '2.1.2'; |
||
85 | |||
86 | /** |
||
87 | * The Magento installation directory. |
||
88 | * |
||
89 | * @var string |
||
90 | * @Type("string") |
||
91 | * @SerializedName("installation-dir") |
||
92 | */ |
||
93 | protected $installationDir; |
||
94 | |||
95 | /** |
||
96 | * The source directory that has to be watched for new files. |
||
97 | * |
||
98 | * @var string |
||
99 | * @Type("string") |
||
100 | * @SerializedName("source-dir") |
||
101 | */ |
||
102 | protected $sourceDir; |
||
103 | |||
104 | /** |
||
105 | * The target directory with the files that has been imported. |
||
106 | * |
||
107 | * @var string |
||
108 | * @Type("string") |
||
109 | * @SerializedName("target-dir") |
||
110 | */ |
||
111 | protected $targetDir; |
||
112 | |||
113 | /** |
||
114 | * The database configuration. |
||
115 | * |
||
116 | * @var TechDivision\Import\Configuration\Database |
||
117 | * @Type("TechDivision\Import\Cli\Configuration\Database") |
||
118 | */ |
||
119 | protected $database; |
||
120 | |||
121 | /** |
||
122 | * ArrayCollection with the information of the configured operations. |
||
123 | * |
||
124 | * @var \Doctrine\Common\Collections\ArrayCollection |
||
125 | * @Type("ArrayCollection<TechDivision\Import\Cli\Configuration\Operation>") |
||
126 | */ |
||
127 | protected $operations; |
||
128 | |||
129 | /** |
||
130 | * The subject's utility class with the SQL statements to use. |
||
131 | * |
||
132 | * @var string |
||
133 | * @Type("string") |
||
134 | * @SerializedName("utility-class-name") |
||
135 | */ |
||
136 | protected $utilityClassName; |
||
137 | |||
138 | /** |
||
139 | * The source date format to use in the subject. |
||
140 | * |
||
141 | * @var string |
||
142 | * @Type("string") |
||
143 | * @SerializedName("source-date-format") |
||
144 | */ |
||
145 | protected $sourceDateFormat = 'n/d/y, g:i A'; |
||
146 | |||
147 | /** |
||
148 | * The subject's multiple field delimiter character for fields with multiple values, defaults to (,). |
||
149 | * |
||
150 | * @var string |
||
151 | * @Type("string") |
||
152 | * @SerializedName("multiple-field-delimiter") |
||
153 | */ |
||
154 | protected $multipleFieldDelimiter = ','; |
||
155 | |||
156 | /** |
||
157 | * The subject's delimiter character for CSV files. |
||
158 | * |
||
159 | * @var string |
||
160 | * @Type("string") |
||
161 | */ |
||
162 | protected $delimiter; |
||
163 | |||
164 | /** |
||
165 | * The subject's enclosure character for CSV files. |
||
166 | * |
||
167 | * @var string |
||
168 | * @Type("string") |
||
169 | */ |
||
170 | protected $enclosure; |
||
171 | |||
172 | /** |
||
173 | * The subject's escape character for CSV files. |
||
174 | * |
||
175 | * @var string |
||
176 | * @Type("string") |
||
177 | */ |
||
178 | protected $escape; |
||
179 | |||
180 | /** |
||
181 | * The subject's source charset for the CSV file. |
||
182 | * |
||
183 | * @var string |
||
184 | * @Type("string") |
||
185 | * @SerializedName("from-charset") |
||
186 | */ |
||
187 | protected $fromCharset; |
||
188 | |||
189 | /** |
||
190 | * The subject's target charset for a CSV file. |
||
191 | * |
||
192 | * @var string |
||
193 | * @Type("string") |
||
194 | * @SerializedName("to-charset") |
||
195 | */ |
||
196 | protected $toCharset; |
||
197 | |||
198 | /** |
||
199 | * The subject's file mode for a CSV target file. |
||
200 | * |
||
201 | * @var string |
||
202 | * @Type("string") |
||
203 | * @SerializedName("file-mode") |
||
204 | */ |
||
205 | protected $fileMode; |
||
206 | |||
207 | /** |
||
208 | * The flag to signal that the subject has to use the strict mode or not. |
||
209 | * |
||
210 | * @var boolean |
||
211 | * @Type("boolean") |
||
212 | * @SerializedName("strict-mode") |
||
213 | */ |
||
214 | protected $strictMode; |
||
215 | |||
216 | /** |
||
217 | * The flag whether or not the import artefacts have to be archived. |
||
218 | * |
||
219 | * @var boolean |
||
220 | * @Type("boolean") |
||
221 | * @SerializedName("archive-artefacts") |
||
222 | */ |
||
223 | protected $archiveArtefacts; |
||
224 | |||
225 | /** |
||
226 | * The directory where the archives will be stored. |
||
227 | * |
||
228 | * @var string |
||
229 | * @Type("string") |
||
230 | * @SerializedName("archive-dir") |
||
231 | */ |
||
232 | protected $archiveDir; |
||
233 | |||
234 | /** |
||
235 | * The flag to signal that the subject has to use the debug mode or not. |
||
236 | * |
||
237 | * @var boolean |
||
238 | * @Type("boolean") |
||
239 | * @SerializedName("debug-mode") |
||
240 | */ |
||
241 | protected $debugMode = false; |
||
242 | |||
243 | /** |
||
244 | * The log level to use (see Monolog documentation). |
||
245 | * |
||
246 | * @var string |
||
247 | * @Type("string") |
||
248 | * @SerializedName("log-level") |
||
249 | */ |
||
250 | protected $logLevel = LogLevel::INFO; |
||
251 | |||
252 | /** |
||
253 | * Factory implementation to create a new initialized configuration instance. |
||
254 | * |
||
255 | * If command line options are specified, they will always override the |
||
256 | * values found in the configuration file. |
||
257 | * |
||
258 | * @param \Symfony\Component\Console\Input\InputInterface $input The Symfony console input instance |
||
259 | * |
||
260 | * @return \TechDivision\Import\Cli\Configuration The configuration instance |
||
261 | * @throws \Exception Is thrown, if the specified configuration file doesn't exist |
||
262 | */ |
||
263 | public static function factory(InputInterface $input) |
||
361 | |||
362 | /** |
||
363 | * Return's the array with the subjects of the operation to use. |
||
364 | * |
||
365 | * @return \Doctrine\Common\Collections\ArrayCollection The ArrayCollection with the subjects |
||
366 | * @throws \Exception Is thrown, if no subjects are available for the actual operation |
||
367 | */ |
||
368 | public function getSubjects() |
||
382 | |||
383 | /** |
||
384 | * Map's the passed value to a boolean. |
||
385 | * |
||
386 | * @param string $value The value to map |
||
387 | * |
||
388 | * @return boolean The mapped value |
||
389 | * @throws \Exception Is thrown, if the value can't be mapped |
||
390 | */ |
||
391 | public function mapBoolean($value) |
||
402 | |||
403 | /** |
||
404 | * Return's the operation, initialize from the actual operation name. |
||
405 | * |
||
406 | * @return \TechDivision\Import\Configuration\OperationInterface The operation instance |
||
407 | */ |
||
408 | protected function getOperation() |
||
412 | |||
413 | /** |
||
414 | * Return's the operation name that has to be used. |
||
415 | * |
||
416 | * @param string $operationName The operation name that has to be used |
||
417 | * |
||
418 | * @return void |
||
419 | */ |
||
420 | public function setOperationName($operationName) |
||
424 | |||
425 | /** |
||
426 | * Return's the operation name that has to be used. |
||
427 | * |
||
428 | * @return string The operation name that has to be used |
||
429 | */ |
||
430 | public function getOperationName() |
||
434 | |||
435 | /** |
||
436 | * Set's the Magento installation directory. |
||
437 | * |
||
438 | * @param string $installationDir The Magento installation directory |
||
439 | * |
||
440 | * @return void |
||
441 | */ |
||
442 | public function setInstallationDir($installationDir) |
||
446 | |||
447 | /** |
||
448 | * Return's the Magento installation directory. |
||
449 | * |
||
450 | * @return string The Magento installation directory |
||
451 | */ |
||
452 | public function getInstallationDir() |
||
456 | |||
457 | /** |
||
458 | * Set's the source directory that has to be watched for new files. |
||
459 | * |
||
460 | * @param string $sourceDir The source directory |
||
461 | * |
||
462 | * @return void |
||
463 | */ |
||
464 | public function setSourceDir($sourceDir) |
||
468 | |||
469 | /** |
||
470 | * Return's the source directory that has to be watched for new files. |
||
471 | * |
||
472 | * @return string The source directory |
||
473 | */ |
||
474 | public function getSourceDir() |
||
478 | |||
479 | /** |
||
480 | * Return's the target directory with the files that has been imported. |
||
481 | * |
||
482 | * @return string The target directory |
||
483 | */ |
||
484 | public function getTargetDir() |
||
488 | |||
489 | /** |
||
490 | * Set's the target directory with the files that has been imported. |
||
491 | * |
||
492 | * @param string $targetDir The target directory |
||
493 | * |
||
494 | * @return void |
||
495 | */ |
||
496 | public function setTargetDir($targetDir) |
||
500 | |||
501 | /** |
||
502 | * Return's the utility class with the SQL statements to use. |
||
503 | * |
||
504 | * @param string $utilityClassName The utility class name |
||
505 | * |
||
506 | * @return void |
||
507 | */ |
||
508 | public function setUtilityClassName($utilityClassName) |
||
512 | |||
513 | /** |
||
514 | * Return's the utility class with the SQL statements to use. |
||
515 | * |
||
516 | * @return string The utility class name |
||
517 | */ |
||
518 | public function getUtilityClassName() |
||
522 | |||
523 | /** |
||
524 | * Set's the Magento edition, EE or CE. |
||
525 | * |
||
526 | * @param string $magentoEdition The Magento edition |
||
527 | * |
||
528 | * @return void |
||
529 | */ |
||
530 | public function setMagentoEdition($magentoEdition) |
||
534 | |||
535 | /** |
||
536 | * Return's the Magento edition, EE or CE. |
||
537 | * |
||
538 | * @return string The Magento edition |
||
539 | */ |
||
540 | public function getMagentoEdition() |
||
544 | |||
545 | /** |
||
546 | * Return's the Magento version, e. g. 2.1.0. |
||
547 | * |
||
548 | * @param string $magentoVersion The Magento version |
||
549 | * |
||
550 | * @return void |
||
551 | */ |
||
552 | public function setMagentoVersion($magentoVersion) |
||
556 | |||
557 | /** |
||
558 | * Return's the Magento version, e. g. 2.1.0. |
||
559 | * |
||
560 | * @return string The Magento version |
||
561 | */ |
||
562 | public function getMagentoVersion() |
||
566 | |||
567 | /** |
||
568 | * Return's the subject's source date format to use. |
||
569 | * |
||
570 | * @return string The source date format |
||
571 | */ |
||
572 | public function getSourceDateFormat() |
||
576 | |||
577 | /** |
||
578 | * Set's the subject's source date format to use. |
||
579 | * |
||
580 | * @param string $sourceDateFormat The source date format |
||
581 | * |
||
582 | * @return void |
||
583 | */ |
||
584 | public function setSourceDateFormat($sourceDateFormat) |
||
588 | |||
589 | /** |
||
590 | * Return's the multiple field delimiter character to use, default value is comma (,). |
||
591 | * |
||
592 | * @return string The multiple field delimiter character |
||
593 | */ |
||
594 | public function getMultipleFieldDelimiter() |
||
598 | |||
599 | /** |
||
600 | * Return's the delimiter character to use, default value is comma (,). |
||
601 | * |
||
602 | * @return string The delimiter character |
||
603 | */ |
||
604 | public function getDelimiter() |
||
608 | |||
609 | /** |
||
610 | * The enclosure character to use, default value is double quotation ("). |
||
611 | * |
||
612 | * @return string The enclosure character |
||
613 | */ |
||
614 | public function getEnclosure() |
||
618 | |||
619 | /** |
||
620 | * The escape character to use, default value is backslash (\). |
||
621 | * |
||
622 | * @return string The escape character |
||
623 | */ |
||
624 | public function getEscape() |
||
628 | |||
629 | /** |
||
630 | * The file encoding of the CSV source file, default value is UTF-8. |
||
631 | * |
||
632 | * @return string The charset used by the CSV source file |
||
633 | */ |
||
634 | public function getFromCharset() |
||
638 | |||
639 | /** |
||
640 | * The file encoding of the CSV targetfile, default value is UTF-8. |
||
641 | * |
||
642 | * @return string The charset used by the CSV target file |
||
643 | */ |
||
644 | public function getToCharset() |
||
648 | |||
649 | /** |
||
650 | * The file mode of the CSV target file, either one of write or append, default is write. |
||
651 | * |
||
652 | * @return string The file mode of the CSV target file |
||
653 | */ |
||
654 | public function getFileMode() |
||
658 | |||
659 | /** |
||
660 | * Queries whether or not strict mode is enabled or not, default is TRUE. |
||
661 | * |
||
662 | * @return boolean TRUE if strict mode is enabled, else FALSE |
||
663 | */ |
||
664 | public function isStrictMode() |
||
668 | |||
669 | /** |
||
670 | * Return's the database configuration. |
||
671 | * |
||
672 | * @return \TechDivision\Import\Cli\Configuration\Database The database configuration |
||
673 | */ |
||
674 | public function getDatabase() |
||
678 | |||
679 | /** |
||
680 | * Return's the ArrayCollection with the configured operations. |
||
681 | * |
||
682 | * @return \Doctrine\Common\Collections\ArrayCollection The ArrayCollection with the operations |
||
683 | */ |
||
684 | public function getOperations() |
||
688 | |||
689 | /** |
||
690 | * Return's the TRUE if the import artefacts have to be archived. |
||
691 | * |
||
692 | * @return boolean TRUE if the import artefacts have to be archived |
||
693 | */ |
||
694 | public function haveArchiveArtefacts() |
||
698 | |||
699 | /** |
||
700 | * The directory where the archives will be stored. |
||
701 | * |
||
702 | * @return string The archive directory |
||
703 | */ |
||
704 | public function getArchiveDir() |
||
708 | |||
709 | /** |
||
710 | * Set's the debug mode. |
||
711 | * |
||
712 | * @param boolean $debugMode TRUE if debug mode is enabled, else FALSE |
||
713 | * |
||
714 | * @return void |
||
715 | */ |
||
716 | public function setDebugMode($debugMode) |
||
720 | |||
721 | /** |
||
722 | * Queries whether or not debug mode is enabled or not, default is TRUE. |
||
723 | * |
||
724 | * @return boolean TRUE if debug mode is enabled, else FALSE |
||
725 | */ |
||
726 | public function isDebugMode() |
||
730 | |||
731 | /** |
||
732 | * Set's the log level to use. |
||
733 | * |
||
734 | * @param string $logLevel The log level to use |
||
735 | * |
||
736 | * @return void |
||
737 | */ |
||
738 | public function setLogLevel($logLevel) |
||
742 | |||
743 | /** |
||
744 | * Return's the log level to use. |
||
745 | * |
||
746 | * @return string The log level to use |
||
747 | */ |
||
748 | public function getLogLevel() |
||
752 | } |
||
753 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.