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 | const MAGIC = 0x270a; |
||
31 | |||
32 | public $FileName; |
||
33 | |||
34 | private $SHPFile = null; |
||
35 | private $SHXFile = null; |
||
36 | private $DBFFile = null; |
||
37 | |||
38 | private $DBFHeader; |
||
39 | |||
40 | public $lastError = ''; |
||
41 | |||
42 | public $boundingBox = array('xmin' => 0.0, 'ymin' => 0.0, 'xmax' => 0.0, 'ymax' => 0.0); |
||
43 | private $fileLength = 0; |
||
44 | public $shapeType = 0; |
||
45 | |||
46 | public $records; |
||
47 | |||
48 | /** |
||
49 | * Checks whether dbase manipuations are supported. |
||
50 | * |
||
51 | * @return bool |
||
52 | */ |
||
53 | 21 | public static function supports_dbase() |
|
57 | |||
58 | /** |
||
59 | * @param integer $shapeType |
||
60 | */ |
||
61 | 24 | public function __construct($shapeType, $boundingBox = array('xmin' => 0.0, 'ymin' => 0.0, 'xmax' => 0.0, 'ymax' => 0.0), $FileName = null) { |
|
67 | |||
68 | /** |
||
69 | * @param string $FileName |
||
70 | */ |
||
71 | 22 | public function loadFromFile($FileName) { |
|
98 | |||
99 | /** |
||
100 | * @param string|null $FileName Name of file to open |
||
101 | */ |
||
102 | 13 | public function saveToFile($FileName = null) { |
|
117 | |||
118 | /** |
||
119 | * Generates filename with given extension |
||
120 | * |
||
121 | * @param string $extension Extension to use (including dot) |
||
122 | * |
||
123 | * @return string |
||
124 | */ |
||
125 | 23 | private function _getFilename($extension) |
|
129 | |||
130 | /** |
||
131 | * Updates bounding box based on SHPData |
||
132 | * |
||
133 | * @param string $type Type of box |
||
134 | * @param array $data ShapeRecord SHPData |
||
135 | * |
||
136 | * @return void |
||
137 | */ |
||
138 | 12 | private function updateBBox($type, $data) |
|
150 | |||
151 | /** |
||
152 | * @param ShapeRecord $record |
||
153 | */ |
||
154 | 12 | public function addRecord($record) { |
|
176 | |||
177 | /** |
||
178 | * @param integer $index |
||
179 | */ |
||
180 | public function deleteRecord($index) { |
||
191 | |||
192 | /** |
||
193 | * Returns array defining fields in DBF file |
||
194 | * |
||
195 | * @return array See setDBFHeader for more information. |
||
196 | */ |
||
197 | public function getDBFHeader() { |
||
200 | |||
201 | /** |
||
202 | * Changes array defining fields in DBF file, used in dbase_create call |
||
203 | * |
||
204 | * @param array $header An array of arrays, each array describing the |
||
205 | * format of one field of the database. Each |
||
206 | * field consists of a name, a character indicating |
||
207 | * the field type, and optionally, a length, |
||
208 | * a precision and a nullable flag. |
||
209 | */ |
||
210 | 12 | public function setDBFHeader($header) { |
|
218 | |||
219 | /** |
||
220 | * Lookups value in the DBF file and returs index |
||
221 | * |
||
222 | * @param string $field Field to match |
||
223 | * @param mixed $value Value to match |
||
224 | * |
||
225 | * @return integer |
||
226 | */ |
||
227 | 1 | public function getIndexFromDBFData($field, $value) { |
|
238 | |||
239 | private function _loadDBFHeader() { |
||
273 | |||
274 | private function _deleteRecordFromDBF($index) { |
||
279 | |||
280 | 20 | private function _loadHeaders() { |
|
281 | 20 | if (Util::loadData('N', $this->readSHP(4)) != ShapeFile::MAGIC) { |
|
282 | 1 | $this->setError('Not a SHP file (file code mismatch)'); |
|
283 | 1 | return false; |
|
284 | } |
||
285 | |||
286 | /* Skip 20 unused bytes */ |
||
287 | 19 | $this->readSHP(20); |
|
288 | |||
289 | 19 | $this->fileLength = Util::loadData('N', $this->readSHP(4)); |
|
290 | |||
291 | /* We currently ignore version */ |
||
292 | 19 | $this->readSHP(4); |
|
293 | |||
294 | 19 | $this->shapeType = Util::loadData('V', $this->readSHP(4)); |
|
295 | |||
296 | 19 | $this->boundingBox = array(); |
|
297 | 19 | $this->boundingBox['xmin'] = Util::loadData('d', $this->readSHP(8)); |
|
298 | 19 | $this->boundingBox['ymin'] = Util::loadData('d', $this->readSHP(8)); |
|
299 | 19 | $this->boundingBox['xmax'] = Util::loadData('d', $this->readSHP(8)); |
|
300 | 19 | $this->boundingBox['ymax'] = Util::loadData('d', $this->readSHP(8)); |
|
301 | 19 | $this->boundingBox['zmin'] = Util::loadData('d', $this->readSHP(8)); |
|
302 | 19 | $this->boundingBox['zmax'] = Util::loadData('d', $this->readSHP(8)); |
|
303 | 19 | $this->boundingBox['mmin'] = Util::loadData('d', $this->readSHP(8)); |
|
304 | 19 | $this->boundingBox['mmax'] = Util::loadData('d', $this->readSHP(8)); |
|
305 | |||
306 | 19 | if (ShapeFile::supports_dbase()) { |
|
307 | $this->DBFHeader = $this->_loadDBFHeader(); |
||
308 | } |
||
309 | 19 | return true; |
|
310 | } |
||
311 | |||
312 | 13 | private function _saveBBoxRecord($file, $type) { |
|
317 | |||
318 | 13 | private function _saveBBox($file) { |
|
328 | |||
329 | 13 | private function _saveHeaders() { |
|
330 | 13 | fwrite($this->SHPFile, pack('NNNNNN', ShapeFile::MAGIC, 0, 0, 0, 0, 0)); |
|
331 | 13 | fwrite($this->SHPFile, pack('N', $this->fileLength)); |
|
332 | 13 | fwrite($this->SHPFile, pack('V', 1000)); |
|
333 | 13 | fwrite($this->SHPFile, pack('V', $this->shapeType)); |
|
334 | 13 | $this->_saveBBox($this->SHPFile); |
|
335 | |||
336 | 13 | fwrite($this->SHXFile, pack('NNNNNN', ShapeFile::MAGIC, 0, 0, 0, 0, 0)); |
|
337 | 13 | fwrite($this->SHXFile, pack('N', 50 + 4 * count($this->records))); |
|
338 | 13 | fwrite($this->SHXFile, pack('V', 1000)); |
|
339 | 13 | fwrite($this->SHXFile, pack('V', $this->shapeType)); |
|
340 | 13 | $this->_saveBBox($this->SHXFile); |
|
341 | 13 | } |
|
342 | |||
343 | 19 | private function _loadRecords() { |
|
360 | |||
361 | 13 | private function _saveRecords() { |
|
375 | |||
376 | 23 | private function _openFile($toWrite, $extension, $name) { |
|
386 | |||
387 | 23 | private function _openSHPFile($toWrite = false) { |
|
394 | |||
395 | 21 | private function _closeSHPFile() { |
|
401 | |||
402 | 13 | private function _openSHXFile($toWrite = false) { |
|
409 | |||
410 | 13 | private function _closeSHXFile() { |
|
416 | |||
417 | /** |
||
418 | * Creates DBF file |
||
419 | * |
||
420 | * @return bool |
||
421 | */ |
||
422 | 13 | private function _createDBFFile() |
|
444 | |||
445 | /** |
||
446 | * Loads DBF file if supported |
||
447 | * |
||
448 | * @return bool |
||
449 | */ |
||
450 | 20 | private function _openDBFFile() { |
|
451 | 20 | if (!ShapeFile::supports_dbase()) { |
|
452 | 20 | $this->DBFFile = null; |
|
453 | 20 | return true; |
|
454 | } |
||
455 | $dbf_name = $this->_getFilename('.dbf'); |
||
456 | if (is_readable($dbf_name)) { |
||
457 | $this->DBFFile = @dbase_open($dbf_name, 0); |
||
458 | if (!$this->DBFFile) { |
||
459 | $this->setError(sprintf('It wasn\'t possible to open the DBase file "%s"', $dbf_name)); |
||
460 | return false; |
||
461 | } |
||
462 | } else { |
||
463 | $this->setError(sprintf('It wasn\'t possible to find the DBase file "%s"', $dbf_name)); |
||
464 | return false; |
||
465 | } |
||
466 | return true; |
||
467 | } |
||
468 | |||
469 | 21 | private function _closeDBFFile() { |
|
475 | |||
476 | /** |
||
477 | * Sets error message |
||
478 | * |
||
479 | * @param string $error |
||
480 | * |
||
481 | * @return void |
||
482 | */ |
||
483 | 3 | public function setError($error) { |
|
486 | |||
487 | /** |
||
488 | * Reads given number of bytes from SHP file |
||
489 | * |
||
490 | * @param integer $bytes |
||
491 | * |
||
492 | * @return string |
||
493 | */ |
||
494 | 20 | public function readSHP($bytes) |
|
498 | |||
499 | /** |
||
500 | * Checks whether file is at EOF |
||
501 | * |
||
502 | * @return bool |
||
503 | */ |
||
504 | 19 | public function eofSHP() |
|
508 | |||
509 | /** |
||
510 | * Returns shape name |
||
511 | * |
||
512 | * @return string |
||
513 | */ |
||
514 | 1 | public function getShapeName() |
|
518 | |||
519 | /** |
||
520 | * Check whether file contains measure data. |
||
521 | * |
||
522 | * For some reason this is distinguished by zero bouding box in the |
||
523 | * specification. |
||
524 | * |
||
525 | * @return bool |
||
526 | */ |
||
527 | 8 | public function hasMeasure() |
|
531 | } |
||
532 | |||
533 |