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 | public $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 | 20 | public static function supports_dbase() |
|
72 | |||
73 | /** |
||
74 | * @param integer $shapeType |
||
75 | */ |
||
76 | 23 | 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 | 21 | public function loadFromFile($FileName) { |
|
87 | 21 | if (!empty($FileName)) { |
|
88 | 21 | $this->FileName = $FileName; |
|
89 | 21 | $result = $this->_openSHPFile(); |
|
90 | 21 | } else { |
|
91 | /* We operate on buffer emulated by readSHP / eofSHP */ |
||
92 | $result = true; |
||
93 | } |
||
94 | |||
95 | 21 | if ($result && ($this->_openDBFFile())) { |
|
96 | 19 | if (!$this->_loadHeaders()) { |
|
97 | 1 | $this->_closeSHPFile(); |
|
98 | 1 | $this->_closeDBFFile(); |
|
99 | 1 | return false; |
|
100 | } |
||
101 | 18 | if (!$this->_loadRecords()) { |
|
102 | $this->_closeSHPFile(); |
||
103 | $this->_closeDBFFile(); |
||
104 | return false; |
||
105 | } |
||
106 | 18 | $this->_closeSHPFile(); |
|
107 | 18 | $this->_closeDBFFile(); |
|
108 | 18 | return true; |
|
109 | } else { |
||
110 | 2 | return false; |
|
111 | } |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * @param string|null $FileName Name of file to open |
||
116 | */ |
||
117 | 13 | 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 | 22 | 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 | 12 | private function updateBBox($type, $data) |
|
165 | |||
166 | /** |
||
167 | * @param ShapeRecord $record |
||
168 | */ |
||
169 | 12 | public function addRecord($record) { |
|
170 | 12 | if ((isset($this->DBFHeader)) && (is_array($this->DBFHeader))) { |
|
171 | 12 | $record->updateDBFInfo($this->DBFHeader); |
|
172 | 12 | } |
|
173 | |||
174 | 12 | $this->fileLength += ($record->getContentLength() + 4); |
|
175 | 12 | $this->records[] = $record; |
|
176 | 12 | $this->records[count($this->records) - 1]->recordNumber = count($this->records); |
|
177 | |||
178 | 12 | $this->updateBBox('x', $record->SHPData); |
|
179 | 12 | $this->updateBBox('y', $record->SHPData); |
|
180 | |||
181 | 12 | if (in_array($this->shapeType, array(11, 13, 15, 18, 21, 23, 25, 28))) { |
|
182 | 8 | $this->updateBBox('m', $record->SHPData); |
|
183 | 8 | } |
|
184 | |||
185 | 12 | if (in_array($this->shapeType, array(11, 13, 15, 18))) { |
|
186 | 4 | $this->updateBBox('z', $record->SHPData); |
|
187 | 4 | } |
|
188 | |||
189 | 12 | 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 | 12 | public function setDBFHeader($header) { |
|
219 | |||
220 | /** |
||
221 | * Lookups value in the DBF file and returs index |
||
222 | * |
||
223 | * @param string $field Field to match |
||
224 | * @param mixed $value Value to match |
||
225 | * |
||
226 | * @return integer |
||
227 | */ |
||
228 | public function getIndexFromDBFData($field, $value) { |
||
239 | |||
240 | private function _loadDBFHeader() { |
||
274 | |||
275 | private function _deleteRecordFromDBF($index) { |
||
280 | |||
281 | 19 | private function _loadHeaders() { |
|
312 | |||
313 | 13 | private function _saveHeaders() { |
|
340 | |||
341 | 18 | private function _loadRecords() { |
|
358 | |||
359 | 13 | private function _saveRecords() { |
|
389 | |||
390 | 22 | private function _openFile($toWrite, $extension, $name) { |
|
400 | |||
401 | 22 | private function _openSHPFile($toWrite = false) { |
|
408 | |||
409 | 20 | private function _closeSHPFile() { |
|
415 | |||
416 | 13 | private function _openSHXFile($toWrite = false) { |
|
423 | |||
424 | 13 | private function _closeSHXFile() { |
|
430 | |||
431 | /** |
||
432 | * Creates DBF file |
||
433 | * |
||
434 | * @return int|false |
||
435 | */ |
||
436 | private function _createDBFFile() |
||
450 | |||
451 | /** |
||
452 | * Loads DBF file if supported |
||
453 | * |
||
454 | * @return bool |
||
455 | */ |
||
456 | 20 | private function _openDBFFile($toWrite = false) { |
|
479 | |||
480 | 20 | private function _closeDBFFile() { |
|
486 | |||
487 | /** |
||
488 | * Sets error message |
||
489 | * |
||
490 | * @param string $error |
||
491 | * |
||
492 | * @return void |
||
493 | */ |
||
494 | 3 | public function setError($error) { |
|
497 | |||
498 | /** |
||
499 | * Reads given number of bytes from SHP file |
||
500 | * |
||
501 | * @param integer $bytes |
||
502 | * |
||
503 | * @return string |
||
504 | */ |
||
505 | 19 | public function readSHP($bytes) |
|
509 | |||
510 | /** |
||
511 | * Checks whether file is at EOF |
||
512 | * |
||
513 | * @return bool |
||
514 | */ |
||
515 | 18 | public function eofSHP() |
|
519 | |||
520 | /** |
||
521 | * Returns shape name |
||
522 | * |
||
523 | * @return string |
||
524 | */ |
||
525 | 1 | public function getShapeName() |
|
529 | |||
530 | /** |
||
531 | * Returns shape name |
||
532 | * |
||
533 | * @param integer $type |
||
534 | * |
||
535 | * @return string |
||
536 | */ |
||
537 | 1 | public static function nameShape($type) |
|
544 | |||
545 | /** |
||
546 | * Check whether file contains measure data. |
||
547 | * |
||
548 | * For some reason this is distinguished by zero bouding box in the |
||
549 | * specification. |
||
550 | * |
||
551 | * @return bool |
||
552 | */ |
||
553 | 8 | public function hasMeasure() |
|
557 | } |
||
558 | |||
559 |