Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Generator 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 Generator, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | abstract class Generator |
||
10 | { |
||
11 | /** |
||
12 | * The filesystem instance. |
||
13 | * |
||
14 | * @var \Illuminate\Filesystem\Filesystem |
||
15 | */ |
||
16 | protected $filesystem; |
||
17 | |||
18 | /** |
||
19 | * The array of options. |
||
20 | * |
||
21 | * @var array |
||
22 | */ |
||
23 | protected $options; |
||
24 | |||
25 | /** |
||
26 | * The shortname of stub. |
||
27 | * |
||
28 | * @var string |
||
29 | */ |
||
30 | protected $stub; |
||
31 | |||
32 | /** |
||
33 | * Create new instance of this class. |
||
34 | * |
||
35 | * @param array $options |
||
36 | */ |
||
37 | public function __construct(array $options = []) |
||
42 | |||
43 | /** |
||
44 | * Get the filesystem instance. |
||
45 | * |
||
46 | * @return \Illuminate\Filesystem\Filesystem |
||
47 | */ |
||
48 | public function getFilesystem() |
||
52 | |||
53 | /** |
||
54 | * Set the filesystem instance. |
||
55 | * |
||
56 | * @param \Illuminate\Filesystem\Filesystem $filesystem |
||
57 | * |
||
58 | * @return $this |
||
59 | */ |
||
60 | public function setFilesystem(Filesystem $filesystem) |
||
66 | |||
67 | /** |
||
68 | * Get stub template for generated file. |
||
69 | * |
||
70 | * @return string |
||
71 | */ |
||
72 | public function getStub() |
||
82 | |||
83 | /** |
||
84 | * Get template replacements. |
||
85 | * |
||
86 | * @return array |
||
87 | */ |
||
88 | public function getReplacements() |
||
96 | |||
97 | /** |
||
98 | * Get base path of destination file. |
||
99 | * |
||
100 | * @return string |
||
101 | */ |
||
102 | public function getBasePath() |
||
106 | |||
107 | /** |
||
108 | * Get destination path for generated file. |
||
109 | * |
||
110 | * @return string |
||
111 | */ |
||
112 | public function getPath() |
||
116 | |||
117 | /** |
||
118 | * Get name input. |
||
119 | * |
||
120 | * @return string |
||
121 | */ |
||
122 | public function getName() |
||
134 | |||
135 | /** |
||
136 | * Get application namespace. |
||
137 | * |
||
138 | * @return string |
||
139 | */ |
||
140 | public function getAppNamespace() |
||
144 | |||
145 | /** |
||
146 | * Get class name. |
||
147 | * |
||
148 | * @return string |
||
149 | */ |
||
150 | public function getClass() |
||
154 | |||
155 | /** |
||
156 | * Get paths of namespace. |
||
157 | * |
||
158 | * @return array |
||
159 | */ |
||
160 | public function getSegments() |
||
164 | |||
165 | /** |
||
166 | * Get root namespace. |
||
167 | * |
||
168 | * @return string |
||
169 | */ |
||
170 | public function getRootNamespace() |
||
174 | |||
175 | /** |
||
176 | * Get class-specific output paths. |
||
177 | * |
||
178 | * @param string $class |
||
179 | * |
||
180 | * @return string |
||
181 | */ |
||
182 | public function getConfigGeneratorClassPath($class, $directoryPath = false) |
||
230 | |||
231 | abstract public function getPathConfigNode(); |
||
232 | |||
233 | /** |
||
234 | * Get class namespace. |
||
235 | * |
||
236 | * @return string |
||
237 | */ |
||
238 | public function getNamespace() |
||
249 | |||
250 | /** |
||
251 | * Setup some hook. |
||
252 | * |
||
253 | * @return void |
||
254 | */ |
||
255 | public function setUp() |
||
259 | |||
260 | /** |
||
261 | * Run the generator. |
||
262 | * |
||
263 | * @return int |
||
264 | * @throws FileAlreadyExistsException |
||
265 | */ |
||
266 | public function run() |
||
267 | { |
||
268 | $this->setUp(); |
||
269 | if ($this->filesystem->exists($path = $this->getPath()) && ! $this->force) { |
||
270 | throw new FileAlreadyExistsException($path); |
||
271 | } |
||
272 | View Code Duplication | if (! $this->filesystem->isDirectory($dir = dirname($path))) { |
|
273 | $this->filesystem->makeDirectory($dir, 0777, true, true); |
||
274 | } |
||
275 | |||
276 | return $this->filesystem->put($path, $this->getStub()); |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * Get options. |
||
281 | * |
||
282 | * @return string |
||
283 | */ |
||
284 | public function getOptions() |
||
288 | |||
289 | /** |
||
290 | * Determinte whether the given key exist in options array. |
||
291 | * |
||
292 | * @param string $key |
||
293 | * |
||
294 | * @return bool |
||
295 | */ |
||
296 | public function hasOption($key) |
||
300 | |||
301 | /** |
||
302 | * Get value from options by given key. |
||
303 | * |
||
304 | * @param string $key |
||
305 | * @param string|null $default |
||
306 | * |
||
307 | * @return string |
||
308 | */ |
||
309 | public function getOption($key, $default = null) |
||
317 | |||
318 | /** |
||
319 | * Helper method for "getOption". |
||
320 | * |
||
321 | * @param string $key |
||
322 | * @param string|null $default |
||
323 | * |
||
324 | * @return string |
||
325 | */ |
||
326 | public function option($key, $default = null) |
||
330 | |||
331 | /** |
||
332 | * Handle call to __get method. |
||
333 | * |
||
334 | * @param string $key |
||
335 | * |
||
336 | * @return string|mixed |
||
337 | */ |
||
338 | public function __get($key) |
||
346 | } |
||
347 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: