Complex classes like Simple 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 Simple, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
55 | class Simple implements ApplicationInterface |
||
56 | { |
||
57 | |||
58 | /** |
||
59 | * The default style to write messages to the symfony console. |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | const DEFAULT_STYLE = 'info'; |
||
64 | |||
65 | /** |
||
66 | * The TechDivision company name as ANSI art. |
||
67 | * |
||
68 | * @var string |
||
69 | */ |
||
70 | protected $ansiArt = ' _______ _ _____ _ _ _ |
||
71 | |__ __| | | | __ \(_) (_) (_) |
||
72 | | | ___ ___| |__ | | | |___ ___ ___ _ ___ _ __ |
||
73 | | |/ _ \/ __| \'_ \| | | | \ \ / / / __| |/ _ \| \'_ \ |
||
74 | | | __/ (__| | | | |__| | |\ V /| \__ \ | (_) | | | | |
||
75 | |_|\___|\___|_| |_|_____/|_| \_/ |_|___/_|\___/|_| |_| |
||
76 | '; |
||
77 | |||
78 | /** |
||
79 | * The log level => console style mapping. |
||
80 | * |
||
81 | * @var array |
||
82 | */ |
||
83 | protected $logLevelStyleMapping = array( |
||
84 | LogLevel::INFO => 'info', |
||
85 | LogLevel::DEBUG => 'comment', |
||
86 | LogLevel::ERROR => 'error', |
||
87 | LogLevel::ALERT => 'error', |
||
88 | LogLevel::CRITICAL => 'error', |
||
89 | LogLevel::EMERGENCY => 'error', |
||
90 | LogLevel::WARNING => 'error', |
||
91 | LogLevel::NOTICE => 'info' |
||
92 | ); |
||
93 | |||
94 | /** |
||
95 | * The PID for the running processes. |
||
96 | * |
||
97 | * @var array |
||
98 | */ |
||
99 | protected $pid; |
||
100 | |||
101 | /** |
||
102 | * The actions unique serial. |
||
103 | * |
||
104 | * @var string |
||
105 | */ |
||
106 | protected $serial; |
||
107 | |||
108 | /** |
||
109 | * The array with the system logger instances. |
||
110 | * |
||
111 | * @var \Doctrine\Common\Collections\Collection |
||
112 | */ |
||
113 | protected $systemLoggers; |
||
114 | |||
115 | /** |
||
116 | * The RegistryProcessor instance to handle running threads. |
||
117 | * |
||
118 | * @var \TechDivision\Import\Services\RegistryProcessorInterface |
||
119 | */ |
||
120 | protected $registryProcessor; |
||
121 | |||
122 | /** |
||
123 | * The processor to read/write the necessary import data. |
||
124 | * |
||
125 | * @var \TechDivision\Import\Services\ImportProcessorInterface |
||
126 | */ |
||
127 | protected $importProcessor; |
||
128 | |||
129 | /** |
||
130 | * The DI container builder instance. |
||
131 | * |
||
132 | * @var \Symfony\Component\DependencyInjection\TaggedContainerInterface |
||
133 | */ |
||
134 | protected $container; |
||
135 | |||
136 | /** |
||
137 | * The system configuration. |
||
138 | * |
||
139 | * @var \TechDivision\Import\ConfigurationInterface |
||
140 | */ |
||
141 | protected $configuration; |
||
142 | |||
143 | /** |
||
144 | * The output stream to write console information to. |
||
145 | * |
||
146 | * @var \Symfony\Component\Console\Output\OutputInterface |
||
147 | */ |
||
148 | protected $output; |
||
149 | |||
150 | /** |
||
151 | * The plugins to be processed. |
||
152 | * |
||
153 | * @var array |
||
154 | */ |
||
155 | protected $plugins = array(); |
||
156 | |||
157 | /** |
||
158 | * The flag that stop's processing the operation. |
||
159 | * |
||
160 | * @var boolean |
||
161 | */ |
||
162 | protected $stopped = false; |
||
163 | |||
164 | /** |
||
165 | * The filehandle for the PID file. |
||
166 | * |
||
167 | * @var resource |
||
168 | */ |
||
169 | protected $fh; |
||
170 | |||
171 | /** |
||
172 | * The plugin factory instance. |
||
173 | * |
||
174 | * @var \TechDivision\Import\Plugins\PluginFactoryInterface |
||
175 | */ |
||
176 | protected $pluginFactory; |
||
177 | |||
178 | /** |
||
179 | * The event emitter instance. |
||
180 | * |
||
181 | * @var \League\Event\EmitterInterface |
||
182 | */ |
||
183 | protected $emitter; |
||
184 | |||
185 | /** |
||
186 | * The constructor to initialize the instance. |
||
187 | * |
||
188 | * @param \Symfony\Component\DependencyInjection\TaggedContainerInterface $container The DI container instance |
||
189 | * @param \TechDivision\Import\Services\RegistryProcessorInterface $registryProcessor The registry processor instance |
||
190 | * @param \TechDivision\Import\Services\ImportProcessorInterface $importProcessor The import processor instance |
||
191 | * @param \TechDivision\Import\ConfigurationInterface $configuration The system configuration |
||
192 | * @param \TechDivision\Import\Plugins\PluginFactoryInterface $pluginFactory The plugin factory instance |
||
193 | * @param \Symfony\Component\Console\Output\OutputInterface $output The output instance |
||
194 | * @param \Doctrine\Common\Collections\Collection $systemLoggers The array with the system logger instances |
||
195 | * @param \League\Event\EmitterInterface $emitter The event emitter instance |
||
196 | */ |
||
197 | public function __construct( |
||
221 | |||
222 | /** |
||
223 | * Set's the event emitter instance. |
||
224 | * |
||
225 | * @param \League\Event\EmitterInterface $emitter The event emitter instance |
||
226 | * |
||
227 | * @return void |
||
228 | */ |
||
229 | public function setEmitter(EmitterInterface $emitter) |
||
233 | |||
234 | /** |
||
235 | * Return's the event emitter instance. |
||
236 | * |
||
237 | * @return \League\Event\EmitterInterface The event emitter instance |
||
238 | */ |
||
239 | public function getEmitter() |
||
243 | |||
244 | /** |
||
245 | * Set's the container instance. |
||
246 | * |
||
247 | * @param \Symfony\Component\DependencyInjection\TaggedContainerInterface $container The container instance |
||
248 | * |
||
249 | * @return void |
||
250 | */ |
||
251 | public function setContainer(TaggedContainerInterface $container) |
||
255 | |||
256 | /** |
||
257 | * Return's the container instance. |
||
258 | * |
||
259 | * @return \Symfony\Component\DependencyInjection\TaggedContainerInterface The container instance |
||
260 | */ |
||
261 | public function getContainer() |
||
265 | |||
266 | /** |
||
267 | * Set's the output stream to write console information to. |
||
268 | * |
||
269 | * @param \Symfony\Component\Console\Output\OutputInterface $output The output stream |
||
270 | * |
||
271 | * @return void |
||
272 | */ |
||
273 | public function setOutput(OutputInterface $output) |
||
277 | |||
278 | /** |
||
279 | * Return's the output stream to write console information to. |
||
280 | * |
||
281 | * @return \Symfony\Component\Console\Output\OutputInterface The output stream |
||
282 | */ |
||
283 | public function getOutput() |
||
287 | |||
288 | /** |
||
289 | * Set's the system configuration. |
||
290 | * |
||
291 | * @param \TechDivision\Import\ConfigurationInterface $configuration The system configuration |
||
292 | * |
||
293 | * @return void |
||
294 | */ |
||
295 | public function setConfiguration(ConfigurationInterface $configuration) |
||
299 | |||
300 | /** |
||
301 | * Return's the system configuration. |
||
302 | * |
||
303 | * @return \TechDivision\Import\ConfigurationInterface The system configuration |
||
304 | */ |
||
305 | public function getConfiguration() |
||
309 | |||
310 | /** |
||
311 | * Set's the RegistryProcessor instance to handle the running threads. |
||
312 | * |
||
313 | * @param \TechDivision\Import\Services\RegistryProcessor $registryProcessor The registry processor instance |
||
314 | * |
||
315 | * @return void |
||
316 | */ |
||
317 | public function setRegistryProcessor(RegistryProcessorInterface $registryProcessor) |
||
321 | |||
322 | /** |
||
323 | * Return's the RegistryProcessor instance to handle the running threads. |
||
324 | * |
||
325 | * @return \TechDivision\Import\Services\RegistryProcessor The registry processor instance |
||
326 | */ |
||
327 | public function getRegistryProcessor() |
||
331 | |||
332 | /** |
||
333 | * Set's the import processor instance. |
||
334 | * |
||
335 | * @param \TechDivision\Import\Services\ImportProcessorInterface $importProcessor The import processor instance |
||
336 | * |
||
337 | * @return void |
||
338 | */ |
||
339 | public function setImportProcessor(ImportProcessorInterface $importProcessor) |
||
343 | |||
344 | /** |
||
345 | * Return's the import processor instance. |
||
346 | * |
||
347 | * @return \TechDivision\Import\Services\ImportProcessorInterface The import processor instance |
||
348 | */ |
||
349 | public function getImportProcessor() |
||
353 | |||
354 | /** |
||
355 | * The array with the system loggers. |
||
356 | * |
||
357 | * @param \Doctrine\Common\Collections\Collection $systemLoggers The system logger instances |
||
358 | * |
||
359 | * @return void |
||
360 | */ |
||
361 | public function setSystemLoggers(Collection $systemLoggers) |
||
365 | |||
366 | /** |
||
367 | * Set's the plugin factory instance. |
||
368 | * |
||
369 | * @param \TechDivision\Import\Plugins\PluginFactoryInterface $pluginFactory The plugin factory instance |
||
370 | * |
||
371 | * @return void |
||
372 | */ |
||
373 | public function setPluginFactory(PluginFactoryInterface $pluginFactory) |
||
377 | |||
378 | /** |
||
379 | * Return's the plugin factory instance. |
||
380 | * |
||
381 | * @return \TechDivision\Import\Plugins\PluginFactoryInterface The plugin factory instance |
||
382 | */ |
||
383 | public function getPluginFactory() |
||
387 | |||
388 | /** |
||
389 | * Return's the logger with the passed name, by default the system logger. |
||
390 | * |
||
391 | * @param string $name The name of the requested system logger |
||
392 | * |
||
393 | * @return \Psr\Log\LoggerInterface The logger instance |
||
394 | * @throws \Exception Is thrown, if the requested logger is NOT available |
||
395 | */ |
||
396 | public function getSystemLogger($name = LoggerKeys::SYSTEM) |
||
412 | |||
413 | /** |
||
414 | * Query whether or not the system logger with the passed name is available. |
||
415 | * |
||
416 | * @param string $name The name of the requested system logger |
||
417 | * |
||
418 | * @return boolean TRUE if the logger with the passed name exists, else FALSE |
||
419 | */ |
||
420 | public function hasSystemLogger($name = LoggerKeys::SYSTEM) |
||
424 | |||
425 | /** |
||
426 | * Return's the array with the system logger instances. |
||
427 | * |
||
428 | * @return \Doctrine\Common\Collections\Collection The logger instance |
||
429 | */ |
||
430 | public function getSystemLoggers() |
||
434 | |||
435 | /** |
||
436 | * Return's the unique serial for this import process. |
||
437 | * |
||
438 | * @return string The unique serial |
||
439 | */ |
||
440 | public function getSerial() |
||
444 | |||
445 | /** |
||
446 | * The shutdown handler to catch fatal errors. |
||
447 | * |
||
448 | * This method is need to make sure, that an existing PID file will be removed |
||
449 | * if a fatal error has been triggered. |
||
450 | * |
||
451 | * @return void |
||
452 | */ |
||
453 | public function shutdown() |
||
472 | |||
473 | /** |
||
474 | * Persist the UUID of the actual import process to the PID file. |
||
475 | * |
||
476 | * @return void |
||
477 | * @throws \Exception Is thrown, if the PID can not be locked or the PID can not be added |
||
478 | * @throws \TechDivision\Import\Exceptions\ImportAlreadyRunningException Is thrown, if a import process is already running |
||
479 | */ |
||
480 | public function lock() |
||
504 | |||
505 | /** |
||
506 | * Remove's the UUID of the actual import process from the PID file. |
||
507 | * |
||
508 | * @return void |
||
509 | * @throws \Exception Is thrown, if the PID can not be removed |
||
510 | */ |
||
511 | public function unlock() |
||
537 | |||
538 | /** |
||
539 | * Remove's the passed line from the file with the passed name. |
||
540 | * |
||
541 | * @param string $line The line to be removed |
||
542 | * @param resource $fh The file handle of the file the line has to be removed |
||
543 | * |
||
544 | * @return void |
||
545 | * @throws \Exception Is thrown, if the file doesn't exists, the line is not found or can not be removed |
||
546 | */ |
||
547 | public function removeLineFromFile($line, $fh) |
||
589 | |||
590 | /** |
||
591 | * Process the given operation. |
||
592 | * |
||
593 | * @return void |
||
594 | * @throws \Exception Is thrown if the operation can't be finished successfully |
||
595 | */ |
||
596 | public function process() |
||
724 | |||
725 | /** |
||
726 | * Stop processing the operation. |
||
727 | * |
||
728 | * @param string $reason The reason why the operation has been stopped |
||
729 | * |
||
730 | * @return void |
||
731 | */ |
||
732 | public function stop($reason) |
||
741 | |||
742 | /** |
||
743 | * Return's TRUE if the operation has been stopped, else FALSE. |
||
744 | * |
||
745 | * @return boolean TRUE if the process has been stopped, else FALSE |
||
746 | */ |
||
747 | public function isStopped() |
||
751 | |||
752 | /** |
||
753 | * Gets a service. |
||
754 | * |
||
755 | * @param string $id The service identifier |
||
756 | * |
||
757 | * @return object The associated service |
||
758 | * |
||
759 | * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException When a circular reference is detected |
||
760 | * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException When the service is not defined |
||
761 | */ |
||
762 | public function get($id) |
||
766 | |||
767 | /** |
||
768 | * Returns true if the container can return an entry for the given identifier. |
||
769 | * Returns false otherwise. |
||
770 | * |
||
771 | * `has($id)` returning true does not mean that `get($id)` will not throw an exception. |
||
772 | * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`. |
||
773 | * |
||
774 | * @param string $id Identifier of the entry to look for. |
||
775 | * |
||
776 | * @return bool |
||
777 | */ |
||
778 | public function has($id) |
||
782 | |||
783 | /** |
||
784 | * Lifecycle callback that will be inovked before the |
||
785 | * import process has been started. |
||
786 | * |
||
787 | * @return void |
||
788 | */ |
||
789 | protected function setUp() |
||
838 | |||
839 | /** |
||
840 | * Lifecycle callback that will be inovked after the |
||
841 | * import process has been finished. |
||
842 | * |
||
843 | * @return void |
||
844 | */ |
||
845 | protected function tearDown() |
||
849 | |||
850 | /** |
||
851 | * Simple method that writes the passed method the the console and the |
||
852 | * system logger, if configured and a log level has been passed. |
||
853 | * |
||
854 | * @param string $msg The message to log |
||
855 | * @param string $logLevel The log level to use |
||
856 | * |
||
857 | * @return void |
||
858 | */ |
||
859 | protected function log($msg, $logLevel = null) |
||
876 | |||
877 | /** |
||
878 | * Map's the passed log level to a valid symfony console style. |
||
879 | * |
||
880 | * @param string $logLevel The log level to map |
||
881 | * |
||
882 | * @return string The apropriate symfony console style |
||
883 | */ |
||
884 | protected function mapLogLevelToStyle($logLevel) |
||
895 | |||
896 | /** |
||
897 | * Return's the PID filename to use. |
||
898 | * |
||
899 | * @return string The PID filename |
||
900 | */ |
||
901 | protected function getPidFilename() |
||
905 | } |
||
906 |
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.