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 Xhgui_Storage_File 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 Xhgui_Storage_File, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 3 | class Xhgui_Storage_File implements \Xhgui_StorageInterface, \Xhgui_WatchedFunctionsStorageInterface  | 
            ||
| 4 | { | 
            ||
| 5 | |||
| 6 | /**  | 
            ||
| 7 | * @var string  | 
            ||
| 8 | */  | 
            ||
| 9 | protected $path = '../data/';  | 
            ||
| 10 | |||
| 11 | /**  | 
            ||
| 12 | * @var string  | 
            ||
| 13 | */  | 
            ||
| 14 | protected $prefix = 'xhgui.data';  | 
            ||
| 15 | |||
| 16 | /**  | 
            ||
| 17 | * @var bool|mixed  | 
            ||
| 18 | */  | 
            ||
| 19 | protected $separateMeta = true;  | 
            ||
| 20 | |||
| 21 | /**  | 
            ||
| 22 | * @var mixed  | 
            ||
| 23 | */  | 
            ||
| 24 | protected $dataSerializer;  | 
            ||
| 25 | |||
| 26 | /**  | 
            ||
| 27 | * @var mixed  | 
            ||
| 28 | */  | 
            ||
| 29 | protected $metaSerializer;  | 
            ||
| 30 | |||
| 31 | /**  | 
            ||
| 32 | * @var string  | 
            ||
| 33 | */  | 
            ||
| 34 | protected $watchedFunctionsPathPrefix = '../watched_functions/';  | 
            ||
| 35 | |||
| 36 | /**  | 
            ||
| 37 | * @var int[]  | 
            ||
| 38 | */  | 
            ||
| 39 | protected $countCache;  | 
            ||
| 40 | |||
| 41 | /**  | 
            ||
| 42 | * Xhgui_Storage_File constructor.  | 
            ||
| 43 | * @param $config  | 
            ||
| 44 | */  | 
            ||
| 45 | public function __construct($config)  | 
            ||
| 58 | |||
| 59 | /**  | 
            ||
| 60 | * @param Xhgui_Storage_Filter $filter  | 
            ||
| 61 | * @param bool $projections  | 
            ||
| 62 | * @return Xhgui_Storage_ResultSet  | 
            ||
| 63 | */  | 
            ||
| 64 | public function find(\Xhgui_Storage_Filter $filter, $projections = false)  | 
            ||
| 137 | |||
| 138 | /**  | 
            ||
| 139 | * @param Xhgui_Storage_Filter $filter  | 
            ||
| 140 | * @return int  | 
            ||
| 141 | */  | 
            ||
| 142 | public function count(\Xhgui_Storage_Filter $filter)  | 
            ||
| 150 | |||
| 151 | /**  | 
            ||
| 152 | * @param $id  | 
            ||
| 153 | * @return mixed  | 
            ||
| 154 | */  | 
            ||
| 155 | public function findOne($id)  | 
            ||
| 162 | |||
| 163 | /**  | 
            ||
| 164 | * @param $id  | 
            ||
| 165 | * @return bool  | 
            ||
| 166 | */  | 
            ||
| 167 | public function remove($id)  | 
            ||
| 179 | |||
| 180 | /**  | 
            ||
| 181 | *  | 
            ||
| 182 | */  | 
            ||
| 183 | public function drop()  | 
            ||
| 188 | |||
| 189 | /**  | 
            ||
| 190 | * @param $match  | 
            ||
| 191 | * @param $col  | 
            ||
| 192 | * @param int $percentile  | 
            ||
| 193 | * @return array  | 
            ||
| 194 | */  | 
            ||
| 195 | public function aggregate(\Xhgui_Storage_Filter $filter, $col, $percentile = 1)  | 
            ||
| 222 | |||
| 223 | |||
| 224 | /**  | 
            ||
| 225 | * @param $a  | 
            ||
| 226 | * @param $b  | 
            ||
| 227 | * @return int  | 
            ||
| 228 | */  | 
            ||
| 229 | public function sortByColumn($a, $b)  | 
            ||
| 280 | |||
| 281 | |||
| 282 | |||
| 283 | /**  | 
            ||
| 284 | * @param $file  | 
            ||
| 285 | * @return mixed  | 
            ||
| 286 | */  | 
            ||
| 287 | protected function getMetafileNameFromProfileName($file)  | 
            ||
| 292 | |||
| 293 | |||
| 294 | /**  | 
            ||
| 295 | * @param $timestamp  | 
            ||
| 296 | * @return bool|DateTime  | 
            ||
| 297 | */  | 
            ||
| 298 | protected function getDateTimeFromStringOrTimestamp($timestamp)  | 
            ||
| 321 | |||
| 322 | /**  | 
            ||
| 323 | * @param $data  | 
            ||
| 324 | */  | 
            ||
| 325 | public function insert($data)  | 
            ||
| 334 | |||
| 335 | /**  | 
            ||
| 336 | * @param $id  | 
            ||
| 337 | * @param $data  | 
            ||
| 338 | */  | 
            ||
| 339 | public function update($id, $data)  | 
            ||
| 343 | |||
| 344 | /**  | 
            ||
| 345 | * @param $path  | 
            ||
| 346 | * @param bool $meta  | 
            ||
| 347 | * @return mixed  | 
            ||
| 348 | */  | 
            ||
| 349 | protected function importFile($path, $meta = false)  | 
            ||
| 388 | |||
| 389 | /**  | 
            ||
| 390 | * @return array  | 
            ||
| 391 | */  | 
            ||
| 392 | public function getWatchedFunctions()  | 
            ||
| 401 | |||
| 402 | /**  | 
            ||
| 403 | * @param $name  | 
            ||
| 404 | * @return bool  | 
            ||
| 405 | */  | 
            ||
| 406 | View Code Duplication | public function addWatchedFunction($name)  | 
            |
| 415 | |||
| 416 | /**  | 
            ||
| 417 | * @param $id  | 
            ||
| 418 | * @param $name  | 
            ||
| 419 | * @return bool  | 
            ||
| 420 | */  | 
            ||
| 421 | View Code Duplication | public function updateWatchedFunction($id, $name)  | 
            |
| 430 | |||
| 431 | /**  | 
            ||
| 432 | * @param $id  | 
            ||
| 433 | */  | 
            ||
| 434 | public function removeWatchedFunction($id)  | 
            ||
| 440 | |||
| 441 | /**  | 
            ||
| 442 | * @param $fileName  | 
            ||
| 443 | * @return bool|\DateTime  | 
            ||
| 444 | */  | 
            ||
| 445 | public function getRequestTimeFromFilename($fileName)  | 
            ||
| 457 | }  | 
            ||
| 458 | 
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: