| Total Complexity | 45 |
| Total Lines | 241 |
| Duplicated Lines | 0 % |
| Changes | 5 | ||
| Bugs | 1 | Features | 1 |
Complex classes like Table 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.
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 Table, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 13 | class Table { |
||
| 14 | private $headers = null; |
||
| 15 | private $columns = null; |
||
| 16 | public $error = false; |
||
| 17 | public $error_info = null; |
||
| 18 | |||
| 19 | private $db, $fp; |
||
| 20 | |||
| 21 | private $versions = [ |
||
| 22 | 2 => ["FoxBase"], |
||
| 23 | 3 => ["dBASE III", "dBASE IV", "dBASE 5", "FoxPro", "FoxBASE+"], |
||
| 24 | 4 => ["dBASE 7"], |
||
| 25 | 48 => ["Visual FoxPro"], |
||
| 26 | 49 => ["Visual FoxPro"], |
||
| 27 | 50 => ["Visual FoxPro"], |
||
| 28 | 67 => ["dBASE IV", "dBASE 5"], |
||
| 29 | 99 => ["dBASE IV", "dBASE 5"], |
||
| 30 | 131 => ["dBASE III", "FoxBASE+", "FoxPro"], |
||
| 31 | 139 => ["dBASE IV", "dBASE 5"], |
||
| 32 | 140 => ["dBASE 7"], |
||
| 33 | 203 => ["dBASE IV", "dBASE 5"], |
||
| 34 | 229 => ["SMT"], |
||
| 35 | 235 => ["dBASE IV", "dBASE 5"], |
||
| 36 | 245 => ["FoxPro"], |
||
| 37 | 251 => ["FoxBASE"] |
||
| 38 | ]; |
||
| 39 | private $memo = [ |
||
| 40 | "versions" => [131, 139, 140, 203, 229, 235, 245, 251], |
||
| 41 | "formats" => [ |
||
| 42 | "dbt" => [131, 139, 140, 203, 235, 251], |
||
| 43 | "fpt" => [245, 48, 49, 50], |
||
| 44 | "smt" => [229] |
||
| 45 | ] |
||
| 46 | ]; |
||
| 47 | |||
| 48 | private $charsets = [ |
||
| 49 | 0 => 866, //If charset not defined |
||
| 50 | 1 => 437, 2 => 850, 3 => 1252, 4 => 10000, 8 => 865, |
||
| 51 | 9 => 437, 10 => 850, 11 => 437, 13 => 437, 14 => 850, |
||
| 52 | 15 => 437, 16 => 850, 17 => 437, 18 => 850, 19 => 932, |
||
| 53 | 20 => 850, 21 => 850, 22 => 437, 23 => 850, 24 => 437, |
||
| 54 | 25 => 437, 26 => 850, 27 => 437, 28 => 863, 29 => 850, |
||
| 55 | 31 => 852, 34 => 852, 35 => 852, 36 => 860, 37 => 850, |
||
| 56 | 38 => 866, 55 => 850, 64 => 852, 77 => 936, 78 => 949, |
||
| 57 | 79 => 950, 80 => 874, 88 => 1252, 89 => 1252, 100 => 852, |
||
| 58 | 101 => 866, 102 => 865, 103 => 861, 104 => 895, 105 => 866, |
||
| 59 | 106 => 737, 107 => 857, 108 => 863, 120 => 950, 121 => 949, |
||
| 60 | 122 => 936, 123 => 932, 124 => 874, 134 => 737, 135 => 852, |
||
| 61 | 136 => 857, 150 => 10007, 151 => 10029, 152 => 10006, 200 => 1250, |
||
| 62 | 201 => 1251, 202 => 1254, 203 => 1253, 204 => 1257 |
||
| 63 | ]; |
||
| 64 | private $dbase7 = false, $v_foxpro = false; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * @throws Exception |
||
| 68 | */ |
||
| 69 | public function __construct($dbPath, $charset = null){ |
||
| 70 | $this->db = $dbPath; |
||
| 71 | if (!is_null($charset)) { |
||
| 72 | if (!is_numeric($charset)) { |
||
| 73 | throw new Exception("Set not correct charset. Allows only digits."); |
||
| 74 | } |
||
| 75 | $this->charsets[0] = $charset; |
||
| 76 | } |
||
| 77 | $this->open(); |
||
| 78 | } |
||
| 79 | |||
| 80 | public function __destruct() { |
||
| 81 | $this->close(); |
||
| 82 | } |
||
| 83 | |||
| 84 | /** |
||
| 85 | * @throws Exception |
||
| 86 | */ |
||
| 87 | private function open() { |
||
| 88 | if (!file_exists($this->db)) { |
||
| 89 | throw new Exception(sprintf('File %s cannot be found', $this->db)); |
||
| 90 | } |
||
| 91 | $this->fp = fopen($this->db, "rb"); |
||
| 92 | } |
||
| 93 | |||
| 94 | public function getHeaders() { |
||
| 95 | if (!$this->error && is_null($this->headers)) { |
||
| 96 | $this->readHeaders(); |
||
| 97 | } |
||
| 98 | return $this->headers; |
||
| 99 | } |
||
| 100 | |||
| 101 | public function getColumns() { |
||
| 102 | $this->getHeaders(); |
||
| 103 | if (!$this->error && is_null($this->columns)) { |
||
| 104 | $this->readTableHeaders(); |
||
| 105 | } |
||
| 106 | return $this->columns; |
||
| 107 | } |
||
| 108 | |||
| 109 | public function getData() { |
||
| 110 | $this->getColumns(); |
||
| 111 | return $this->fp; |
||
| 112 | } |
||
| 113 | |||
| 114 | public function close() { |
||
| 115 | if (get_resource_type($this->fp) === "file") { |
||
| 116 | fclose($this->fp); |
||
| 117 | } |
||
| 118 | } |
||
| 119 | |||
| 120 | private function readHeaders() { |
||
| 168 | } |
||
| 169 | |||
| 170 | private function readTableHeaders() { |
||
| 171 | if (!$this->error && is_null($this->headers)) { |
||
| 172 | $this->readHeaders(); |
||
| 173 | } |
||
| 174 | if (!$this->error) { |
||
| 175 | for ($i = 0; $i < $this->headers["columns"]; $i++) { |
||
| 176 | $data = fread($this->fp, ($this->dbase7) ? 48 : 32); |
||
| 177 | if ($this->dbase7) { |
||
| 178 | $this->columns[$i] = [ |
||
| 179 | "name" => strtolower(trim(substr($data, 0, 32))), |
||
| 180 | "type" => $data[32], |
||
| 181 | "length" => unpack("C", $data[33])[1], |
||
| 182 | "decimal" => unpack("C", $data[34])[1], |
||
| 183 | "mdx_flag" => unpack("C", $data[37])[1], |
||
| 184 | "auto_increment" => unpack("L", substr($data, 40, 4))[1] |
||
| 185 | ]; |
||
| 186 | } |
||
| 187 | else { |
||
| 188 | $this->columns[$i] = [ |
||
| 189 | "name" => strtolower(trim(substr($data, 0, 11))), |
||
| 190 | "type" => $data[11], |
||
| 191 | "length" => unpack("C", $data[16])[1], |
||
| 192 | "decimal" => unpack("C", $data[17])[1], |
||
| 193 | "mdx_flag" => unpack("C", $data[31])[1], |
||
| 194 | ]; |
||
| 195 | if ($this->v_foxpro) { |
||
| 196 | $this->columns[$i]["flag"] = unpack("C", $data[18])[1]; |
||
| 197 | $this->columns[$i]["system"] = ($this->columns[$i]["flag"] == 1); |
||
| 198 | $this->columns[$i]["has_null"] = in_array($this->columns[$i]["flag"], [2, 6]); |
||
| 199 | $this->columns[$i]["binary"] = in_array($this->columns[$i]["flag"], [4, 6]); |
||
| 200 | $this->columns[$i]["auto_increment"] = ($this->columns[$i]["flag"] == 12); |
||
| 201 | if ($this->columns[$i]["auto_increment"]) { |
||
| 202 | $this->columns[$i]["auto_increment_next"] = unpack("L", substr($data, 19, 4))[1]; |
||
| 203 | $this->columns[$i]["auto_increment_step"] = unpack("C", $data[23])[1]; |
||
| 204 | } |
||
| 205 | } |
||
| 206 | else { |
||
| 207 | $this->columns[$i]["mdx_flag"] = unpack("C", $data[31])[1]; |
||
| 208 | } |
||
| 209 | } |
||
| 210 | if ($this->columns[$i]["type"] == "C") { |
||
| 211 | $this->columns[$i]["length"] = unpack("S", substr($data, ($this->dbase7) ? 33 : 16, 2))[1]; |
||
| 212 | $this->columns[$i]["decimal"] = 0; |
||
| 213 | } |
||
| 214 | } |
||
| 215 | } |
||
| 216 | $terminal_byte = unpack("C", fread($this->fp, 1))[1]; |
||
| 217 | if ($terminal_byte != 13) { |
||
| 218 | $this->error = true; |
||
| 219 | $this->error_info = "Not correct DBF file by columns"; |
||
| 220 | } |
||
| 221 | if ($this->v_foxpro) { |
||
| 222 | fread($this->fp, 263); |
||
| 223 | } |
||
| 224 | } |
||
| 225 | |||
| 226 | private function getDate($data) { |
||
| 227 | return $data[3].".".$data[2].".".($data[1] > 70 ? 1900 + $data[1] : 2000 + $data[1]); |
||
| 228 | } |
||
| 229 | |||
| 230 | private function getMemoFile($file) { |
||
| 231 | foreach ($this->memo["formats"] as $format => $versions) { |
||
| 232 | if (in_array($this->headers["version"], $versions)) { |
||
| 233 | return $this->fileExists($file.".".$format); |
||
| 234 | } |
||
| 235 | } |
||
| 236 | return false; |
||
| 237 | } |
||
| 238 | |||
| 239 | private function fileExists($fileName) { |
||
| 254 | } |
||
| 255 | } |
||
| 256 |