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 Database_Driver 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 Database_Driver, and based on these observations, apply Extract Interface, too.
| 1 | <?php defined('SYSPATH') or die('No direct access allowed.'); |
||
| 12 | abstract class Database_Driver |
||
| 13 | { |
||
| 14 | protected $query_cache; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * Connect to our database. |
||
| 18 | * Returns FALSE on failure or a MySQL resource. |
||
| 19 | * |
||
| 20 | * @return mixed |
||
| 21 | */ |
||
| 22 | abstract public function connect(); |
||
| 23 | |||
| 24 | /** |
||
| 25 | * Perform a query based on a manually written query. |
||
| 26 | * |
||
| 27 | * @param string SQL query to execute |
||
| 28 | * @return Database_Result |
||
| 29 | */ |
||
| 30 | abstract public function query($sql); |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Builds a DELETE query. |
||
| 34 | * |
||
| 35 | * @param string table name |
||
| 36 | * @param array where clause |
||
| 37 | * @return string |
||
| 38 | */ |
||
| 39 | public function delete($table, $where) |
||
| 43 | |||
| 44 | /** |
||
| 45 | * Builds an UPDATE query. |
||
| 46 | * |
||
| 47 | * @param string table name |
||
| 48 | * @param array key => value pairs |
||
| 49 | * @param array where clause |
||
| 50 | * @return string |
||
| 51 | */ |
||
| 52 | View Code Duplication | public function update($table, $values, $where) |
|
| 59 | |||
| 60 | /** |
||
| 61 | * Set the charset using 'SET NAMES <charset>'. |
||
| 62 | * |
||
| 63 | * @param string character set to use |
||
| 64 | */ |
||
| 65 | public function set_charset($charset) |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Wrap the tablename in backticks, has support for: table.field syntax. |
||
| 72 | * |
||
| 73 | * @param string table name |
||
| 74 | * @return string |
||
| 75 | */ |
||
| 76 | abstract public function escape_table($table); |
||
| 77 | |||
| 78 | /** |
||
| 79 | * Escape a column/field name, has support for special commands. |
||
| 80 | * |
||
| 81 | * @param string column name |
||
| 82 | * @return string |
||
| 83 | */ |
||
| 84 | abstract public function escape_column($column); |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Builds a WHERE portion of a query. |
||
| 88 | * |
||
| 89 | * @param mixed key |
||
| 90 | * @param string value |
||
| 91 | * @param string type |
||
| 92 | * @param int number of where clauses |
||
| 93 | * @param boolean escape the value |
||
| 94 | * @return string |
||
| 95 | */ |
||
| 96 | public function where($key, $value, $type, $num_wheres, $quote) |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Builds a LIKE portion of a query. |
||
| 134 | * |
||
| 135 | * @param mixed field name |
||
| 136 | * @param string value to match with field |
||
| 137 | * @param boolean add wildcards before and after the match |
||
| 138 | * @param string clause type (AND or OR) |
||
| 139 | * @param int number of likes |
||
| 140 | * @return string |
||
| 141 | */ |
||
| 142 | View Code Duplication | public function like($field, $match, $auto, $type, $num_likes) |
|
| 155 | |||
| 156 | /** |
||
| 157 | * Builds a NOT LIKE portion of a query. |
||
| 158 | * |
||
| 159 | * @param mixed field name |
||
| 160 | * @param string value to match with field |
||
| 161 | * @param string clause type (AND or OR) |
||
| 162 | * @param int number of likes |
||
| 163 | * @return string |
||
| 164 | */ |
||
| 165 | View Code Duplication | public function notlike($field, $match, $auto, $type, $num_likes) |
|
| 178 | |||
| 179 | /** |
||
| 180 | * Builds a REGEX portion of a query. |
||
| 181 | * |
||
| 182 | * @param string field name |
||
| 183 | * @param string value to match with field |
||
| 184 | * @param string clause type (AND or OR) |
||
| 185 | * @param integer number of regexes |
||
| 186 | * @return string |
||
| 187 | */ |
||
| 188 | public function regex($field, $match, $type, $num_regexs) |
||
| 192 | |||
| 193 | /** |
||
| 194 | * Builds a NOT REGEX portion of a query. |
||
| 195 | * |
||
| 196 | * @param string field name |
||
| 197 | * @param string value to match with field |
||
| 198 | * @param string clause type (AND or OR) |
||
| 199 | * @param integer number of regexes |
||
| 200 | * @return string |
||
| 201 | */ |
||
| 202 | public function notregex($field, $match, $type, $num_regexs) |
||
| 206 | |||
| 207 | /** |
||
| 208 | * Builds an INSERT query. |
||
| 209 | * |
||
| 210 | * @param string table name |
||
| 211 | * @param array keys |
||
| 212 | * @param array values |
||
| 213 | * @return string |
||
| 214 | */ |
||
| 215 | View Code Duplication | public function insert($table, $keys, $values) |
|
| 223 | |||
| 224 | /** |
||
| 225 | * Builds a MERGE portion of a query. |
||
| 226 | * |
||
| 227 | * @param string table name |
||
| 228 | * @param array keys |
||
| 229 | * @param array values |
||
| 230 | * @return string |
||
| 231 | */ |
||
| 232 | public function merge($table, $keys, $values) |
||
| 236 | |||
| 237 | /** |
||
| 238 | * Builds a LIMIT portion of a query. |
||
| 239 | * |
||
| 240 | * @param integer limit |
||
| 241 | * @param integer offset |
||
| 242 | * @return string |
||
| 243 | */ |
||
| 244 | abstract public function limit($limit, $offset = 0); |
||
| 245 | |||
| 246 | /** |
||
| 247 | * Creates a prepared statement. |
||
| 248 | * |
||
| 249 | * @param string SQL query |
||
| 250 | * @return Database_Stmt |
||
| 251 | */ |
||
| 252 | public function stmt_prepare($sql = '') |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Compiles the SELECT statement. |
||
| 259 | * Generates a query string based on which functions were used. |
||
| 260 | * Should not be called directly, the get() function calls it. |
||
| 261 | * |
||
| 262 | * @param array select query values |
||
| 263 | * @return string |
||
| 264 | */ |
||
| 265 | abstract public function compile_select($database); |
||
| 266 | |||
| 267 | /** |
||
| 268 | * Determines if the string has an arithmetic operator in it. |
||
| 269 | * |
||
| 270 | * @param string string to check |
||
| 271 | * @return boolean |
||
| 272 | */ |
||
| 273 | public function has_operator($str) |
||
| 277 | |||
| 278 | /** |
||
| 279 | * Escapes any input value. |
||
| 280 | * |
||
| 281 | * @param mixed value to escape |
||
| 282 | * @return string |
||
| 283 | */ |
||
| 284 | public function escape($value) |
||
| 308 | |||
| 309 | /** |
||
| 310 | * Escapes a string for a query. |
||
| 311 | * |
||
| 312 | * @param mixed value to escape |
||
| 313 | * @return string |
||
| 314 | */ |
||
| 315 | abstract public function escape_str($str); |
||
| 316 | |||
| 317 | /** |
||
| 318 | * Lists all tables in the database. |
||
| 319 | * |
||
| 320 | * @return array |
||
| 321 | */ |
||
| 322 | abstract public function list_tables(); |
||
| 323 | |||
| 324 | /** |
||
| 325 | * Lists all fields in a table. |
||
| 326 | * |
||
| 327 | * @param string table name |
||
| 328 | * @return array |
||
| 329 | */ |
||
| 330 | abstract public function list_fields($table); |
||
| 331 | |||
| 332 | /** |
||
| 333 | * Returns the last database error. |
||
| 334 | * |
||
| 335 | * @return string |
||
| 336 | */ |
||
| 337 | abstract public function show_error(); |
||
| 338 | |||
| 339 | /** |
||
| 340 | * Returns field data about a table. |
||
| 341 | * |
||
| 342 | * @param string table name |
||
| 343 | * @return array |
||
| 344 | */ |
||
| 345 | abstract public function field_data($table); |
||
| 346 | |||
| 347 | /** |
||
| 348 | * Fetches SQL type information about a field, in a generic format. |
||
| 349 | * |
||
| 350 | * @param string field datatype |
||
| 351 | * @return string |
||
| 352 | */ |
||
| 353 | protected function sql_type($str) |
||
| 399 | |||
| 400 | /** |
||
| 401 | * Clears the internal query cache. |
||
| 402 | * |
||
| 403 | * @param string SQL query |
||
| 404 | */ |
||
| 405 | public function clear_cache($sql = null) |
||
| 415 | |||
| 416 | /** |
||
| 417 | * Creates a hash for an SQL query string. Replaces newlines with spaces, |
||
| 418 | * trims, and hashes. |
||
| 419 | * |
||
| 420 | * @param string SQL query |
||
| 421 | * @return string |
||
| 422 | */ |
||
| 423 | protected function query_hash($sql) |
||
| 427 | } // End Database Driver Interface |
||
| 428 | |||
| 609 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.