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:
| 1 | <?php |
||
| 8 | class PropertyHider extends stdClass { |
||
| 9 | |||
| 10 | /** |
||
| 11 | * Property list |
||
| 12 | * |
||
| 13 | * @var array[] |
||
| 14 | */ |
||
| 15 | protected static $_properties = array(); |
||
| 16 | |||
| 17 | /** |
||
| 18 | * List of property names that was changed since last DB operation |
||
| 19 | * |
||
| 20 | * @var string[] |
||
| 21 | */ |
||
| 22 | protected $propertiesChanged = array(); |
||
| 23 | /** |
||
| 24 | * List of property names->$delta that was adjusted since last DB operation - and then need to be processed as Deltas |
||
| 25 | * |
||
| 26 | * @var string[] |
||
| 27 | */ |
||
| 28 | protected $propertiesAdjusted = array(); |
||
| 29 | |||
| 30 | /** |
||
| 31 | * @param array $properties |
||
| 32 | */ |
||
| 33 | 1 | public static function setProperties($properties) { |
|
| 37 | |||
| 38 | 1 | public static function getProperties() { |
|
| 41 | |||
| 42 | /** |
||
| 43 | * PropertyHider constructor. |
||
| 44 | */ |
||
| 45 | 1 | public function __construct() { |
|
| 47 | |||
| 48 | // protected function checkForGetSet($name, $left3) { |
||
|
|
|||
| 49 | // // If method is not getter or setter OR property name not exists in $_properties - raising exception |
||
| 50 | // // Descendants can catch this Exception to make own __call magic |
||
| 51 | // if ($left3 != 'get' && $left3 != 'set') { |
||
| 52 | // throw new ExceptionNotGetterOrSetter('Magic call is not getter or setter ' . get_called_class() . '::' . $name, ERR_ERROR); |
||
| 53 | // } |
||
| 54 | // } |
||
| 55 | // |
||
| 56 | // protected function checkForPropertyExists($name, $propertyName) { |
||
| 57 | // if (empty(static::$_properties[$propertyName])) { |
||
| 58 | // throw new ExceptionPropertyNotExists('Property ' . $propertyName . ' not exists when calling getter/setter ' . get_called_class() . '::' . $name, ERR_ERROR); |
||
| 59 | // } |
||
| 60 | // } |
||
| 61 | |||
| 62 | // protected function checkForDoubleAdjust($name, $left3, $propertyName) { |
||
| 63 | // if ($left3 == 'set' && array_key_exists($propertyName, $this->propertiesAdjusted)) { |
||
| 64 | // throw new PropertyAccessException('Property ' . $propertyName . ' already was adjusted so no SET is possible until dbSave in ' . get_called_class() . '::' . $name, ERR_ERROR); |
||
| 65 | // } |
||
| 66 | // } |
||
| 67 | |||
| 68 | // /** |
||
| 69 | // * Handles getters and setters |
||
| 70 | // * |
||
| 71 | // * @param string $name |
||
| 72 | // * @param array $arguments |
||
| 73 | // * |
||
| 74 | // * @return mixed |
||
| 75 | // * @throws ExceptionNotGetterOrSetter |
||
| 76 | // * @throws ExceptionPropertyNotExists |
||
| 77 | // * @throws PropertyAccessException |
||
| 78 | // */ |
||
| 79 | // protected function callGetSet($name, $arguments) { |
||
| 80 | // $this->checkForGetSet($name, $left3 = substr($name, 0, 3)); |
||
| 81 | // $this->checkForPropertyExists($name, $propertyName = lcfirst(substr($name, 3))); |
||
| 82 | // // TODO check for read-only |
||
| 83 | // $this->checkForDoubleAdjust($name, $left3, $propertyName); |
||
| 84 | // |
||
| 85 | // $result = null; |
||
| 86 | // |
||
| 87 | // // Now deciding - will we call a protected setter or will we work with protected property |
||
| 88 | // if (method_exists($this, $name)) { |
||
| 89 | // // If method exists - just calling it |
||
| 90 | // $result = call_user_func_array(array($this, $name), $arguments); |
||
| 91 | // } else { |
||
| 92 | // // No getter/setter exists - works directly with protected property |
||
| 93 | // if ($left3 === 'set') { |
||
| 94 | // $this->{'_' . $propertyName} = $arguments[0]; |
||
| 95 | // } elseif ($left3 === 'get') { |
||
| 96 | // $result = $this->{'_' . $propertyName}; |
||
| 97 | // } |
||
| 98 | // } |
||
| 99 | // |
||
| 100 | // if ($left3 === 'set') { |
||
| 101 | // $this->propertiesChanged[$propertyName] = true; |
||
| 102 | // } |
||
| 103 | // |
||
| 104 | // return $result; |
||
| 105 | // } |
||
| 106 | |||
| 107 | // public function __call($name, $arguments) { |
||
| 108 | // $this->callGetSet($name, $arguments); |
||
| 109 | // } |
||
| 110 | |||
| 111 | 5 | protected function checkPropertyExists($name) { |
|
| 116 | |||
| 117 | 3 | protected function checkOverwriteAdjusted($name) { |
|
| 122 | |||
| 123 | |||
| 124 | /** |
||
| 125 | * Getter with support of protected methods |
||
| 126 | * |
||
| 127 | * @param $name |
||
| 128 | * |
||
| 129 | * @return mixed |
||
| 130 | * @throws ExceptionPropertyNotExists |
||
| 131 | */ |
||
| 132 | 4 | View Code Duplication | public function __get($name) { |
| 149 | |||
| 150 | /** |
||
| 151 | * Real setter function |
||
| 152 | * |
||
| 153 | * @param string $name |
||
| 154 | * @param mixed $value |
||
| 155 | * |
||
| 156 | * @return mixed|null |
||
| 157 | * @throws ExceptionPropertyNotExists |
||
| 158 | */ |
||
| 159 | 4 | View Code Duplication | protected function ___set($name, $value) { |
| 178 | |||
| 179 | /** |
||
| 180 | * Setter wrapper with support of protected properties/methods |
||
| 181 | * |
||
| 182 | * @param string $name |
||
| 183 | * @param mixed $value |
||
| 184 | * |
||
| 185 | * @return mixed|null |
||
| 186 | * @throws ExceptionPropertyNotExists |
||
| 187 | */ |
||
| 188 | // TODO - сеттер должен параллельно изменять значение db_row - for now... |
||
| 189 | // TODO - Проверка, а действительно ли данные были изменены?? Понадобится определение типов - разные типы сравниваются по-разному |
||
| 190 | 4 | public function __set($name, $value) { |
|
| 198 | |||
| 199 | /** |
||
| 200 | * Adjust property value with $diff |
||
| 201 | * Adjusted values put into DB with UPDATE query |
||
| 202 | * Adjuster callback adjXXX() should return new value which will be propagated via ___set() |
||
| 203 | * |
||
| 204 | * @param string $name |
||
| 205 | * @param mixed $diff |
||
| 206 | * |
||
| 207 | * @return mixed |
||
| 208 | */ |
||
| 209 | 1 | public function __adjust($name, $diff) { |
|
| 233 | |||
| 234 | } |
||
| 235 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.