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 ShapeFile 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 ShapeFile, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
29 | class ShapeFile { |
||
30 | public $FileName; |
||
31 | |||
32 | private $SHPFile = null; |
||
33 | private $SHXFile = null; |
||
34 | private $DBFFile = null; |
||
35 | |||
36 | private $DBFHeader; |
||
37 | |||
38 | public $lastError = ''; |
||
39 | |||
40 | public $boundingBox = array('xmin' => 0.0, 'ymin' => 0.0, 'xmax' => 0.0, 'ymax' => 0.0); |
||
41 | private $fileLength = 0; |
||
42 | public $shapeType = 0; |
||
43 | |||
44 | public $records; |
||
45 | |||
46 | private static $shape_names = array( |
||
47 | 0 => 'Null Shape', |
||
48 | 1 => 'Point', |
||
49 | 3 => 'PolyLine', |
||
50 | 5 => 'Polygon', |
||
51 | 8 => 'MultiPoint', |
||
52 | 11 => 'PointZ', |
||
53 | 13 => 'PolyLineZ', |
||
54 | 15 => 'PolygonZ', |
||
55 | 18 => 'MultiPointZ', |
||
56 | 21 => 'PointM', |
||
57 | 23 => 'PolyLineM', |
||
58 | 25 => 'PolygonM', |
||
59 | 28 => 'MultiPointM', |
||
60 | 31 => 'MultiPatch', |
||
61 | ); |
||
62 | |||
63 | /** |
||
64 | * Checks whether dbase manipuations are supported. |
||
65 | * |
||
66 | * @return bool |
||
67 | */ |
||
68 | public static function supports_dbase() |
||
72 | |||
73 | /** |
||
74 | * @param integer $shapeType |
||
75 | */ |
||
76 | public function __construct($shapeType, $boundingBox = array('xmin' => 0.0, 'ymin' => 0.0, 'xmax' => 0.0, 'ymax' => 0.0), $FileName = null) { |
||
82 | |||
83 | /** |
||
84 | * @param string $FileName |
||
85 | */ |
||
86 | public function loadFromFile($FileName) { |
||
113 | |||
114 | /** |
||
115 | * @param string|null $FileName Name of file to open |
||
116 | */ |
||
117 | public function saveToFile($FileName = null) { |
||
132 | |||
133 | /** |
||
134 | * Generates filename with given extension |
||
135 | * |
||
136 | * @param string $extension Extension to use (including dot) |
||
137 | * |
||
138 | * @return string |
||
139 | */ |
||
140 | private function _getFilename($extension) |
||
144 | |||
145 | /** |
||
146 | * Updates bounding box based on SHPData |
||
147 | * |
||
148 | * @param string $type Type of box |
||
149 | * @param array $data ShapeRecord SHPData |
||
150 | * |
||
151 | * @return void |
||
152 | */ |
||
153 | private function updateBBox($type, $data) |
||
154 | { |
||
155 | $min = $type.'min'; |
||
156 | $max = $type.'max'; |
||
157 | |||
158 | View Code Duplication | if (!isset($this->boundingBox[$min]) || $this->boundingBox[$min] == 0.0 || ($this->boundingBox[$min] > $data[$min])) { |
|
1 ignored issue
–
show
|
|||
159 | $this->boundingBox[$min] = $data[$min]; |
||
160 | } |
||
161 | View Code Duplication | if (!isset($this->boundingBox[$max]) || $this->boundingBox[$max] == 0.0 || ($this->boundingBox[$max] < $data[$max])) { |
|
162 | $this->boundingBox[$max] = $data[$max]; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * @param ShapeRecord $record |
||
168 | */ |
||
169 | public function addRecord($record) { |
||
170 | if ((isset($this->DBFHeader)) && (is_array($this->DBFHeader))) { |
||
171 | $record->updateDBFInfo($this->DBFHeader); |
||
172 | } |
||
173 | |||
174 | $this->fileLength += ($record->getContentLength() + 4); |
||
175 | $this->records[] = $record; |
||
176 | $this->records[count($this->records) - 1]->recordNumber = count($this->records); |
||
177 | |||
178 | $this->updateBBox('x', $record->SHPData); |
||
179 | $this->updateBBox('y', $record->SHPData); |
||
180 | |||
181 | if (in_array($this->shapeType, array(11, 13, 15, 18, 21, 23, 25, 28))) { |
||
182 | $this->updateBBox('m', $record->SHPData); |
||
183 | } |
||
184 | |||
185 | if (in_array($this->shapeType, array(11, 13, 15, 18))) { |
||
186 | $this->updateBBox('z', $record->SHPData); |
||
187 | } |
||
188 | |||
189 | return (count($this->records) - 1); |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * @param integer $index |
||
194 | */ |
||
195 | public function deleteRecord($index) { |
||
206 | |||
207 | public function getDBFHeader() { |
||
210 | |||
211 | public function setDBFHeader($header) { |
||
219 | |||
220 | public function getIndexFromDBFData($field, $value) { |
||
231 | |||
232 | private function _loadDBFHeader() { |
||
266 | |||
267 | private function _deleteRecordFromDBF($index) { |
||
272 | |||
273 | private function _loadHeaders() { |
||
304 | |||
305 | private function _saveHeaders() { |
||
332 | |||
333 | private function _loadRecords() { |
||
350 | |||
351 | private function _saveRecords() { |
||
352 | if (!ShapeFile::supports_dbase()) { |
||
378 | |||
379 | private function _openFile($toWrite, $extension, $name) { |
||
389 | |||
390 | private function _openSHPFile($toWrite = false) { |
||
397 | |||
398 | private function _closeSHPFile() { |
||
404 | |||
405 | private function _openSHXFile($toWrite = false) { |
||
412 | |||
413 | private function _closeSHXFile() { |
||
419 | |||
420 | /** |
||
421 | * Loads DBF file if supported |
||
422 | * |
||
423 | * @return bool |
||
424 | */ |
||
425 | private function _openDBFFile($toWrite = false) { |
||
449 | |||
450 | private function _closeDBFFile() { |
||
456 | |||
457 | /** |
||
458 | * Sets error message |
||
459 | * |
||
460 | * @param string $error |
||
461 | * |
||
462 | * @return void |
||
463 | */ |
||
464 | public function setError($error) { |
||
467 | |||
468 | /** |
||
469 | * Reads given number of bytes from SHP file |
||
470 | * |
||
471 | * @param integer $bytes |
||
472 | * @return string |
||
473 | */ |
||
474 | public function readSHP($bytes) |
||
478 | |||
479 | /** |
||
480 | * Checks whether file is at EOF |
||
481 | * |
||
482 | * @return bool |
||
483 | */ |
||
484 | public function eofSHP() |
||
488 | |||
489 | /** |
||
490 | * Returns shape name |
||
491 | * |
||
492 | * @return string |
||
493 | */ |
||
494 | public function getShapeName() |
||
498 | |||
499 | /** |
||
500 | * @param integer $type |
||
501 | */ |
||
502 | public static function nameShape($type) |
||
509 | } |
||
510 | |||
511 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.