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 Adodb 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 Adodb, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
33 | class Adodb |
||
34 | { |
||
35 | use UtilContainerAwareTrait; |
||
36 | |||
37 | |||
38 | /** |
||
39 | * PHP script charset |
||
40 | * |
||
41 | * Used to compare with db charset. |
||
42 | * |
||
43 | * This is charset of PHP script. Operation system has their default |
||
44 | * charset, but text editor can specify other charset too. |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | public $charsetPhp = 'UTF-8'; |
||
49 | |||
50 | /** |
||
51 | * Real ADOdb connection object |
||
52 | * |
||
53 | * @var object |
||
54 | */ |
||
55 | protected $conn = null; |
||
56 | |||
57 | /** |
||
58 | * Table schema |
||
59 | * |
||
60 | * { |
||
61 | * table: { |
||
62 | * col: { |
||
63 | * name: ts |
||
64 | * max_length: -1 |
||
65 | * type: timestamp |
||
66 | * scale: |
||
67 | * not_null: |
||
68 | * primary_key: |
||
69 | * auto_increment: |
||
70 | * binary: |
||
71 | * unsigned: |
||
72 | * zerofill: |
||
73 | * has_default: 1 |
||
74 | * default_value: CURRENT_TIMESTAMP |
||
75 | * } |
||
76 | * } |
||
77 | * } |
||
78 | * |
||
79 | * Notice: col is ADOFieldObject object, not array ! |
||
80 | * |
||
81 | * @var array |
||
82 | */ |
||
83 | public $metaColumn = []; |
||
84 | |||
85 | /** |
||
86 | * Table column name array, with upper case column name as index |
||
87 | * |
||
88 | * { |
||
89 | * COLUMN: column |
||
90 | * } |
||
91 | * |
||
92 | * @var array |
||
93 | */ |
||
94 | public $metaColumnName = []; |
||
95 | |||
96 | /** |
||
97 | * Primary key columns of table |
||
98 | * |
||
99 | * { |
||
100 | * tbl: colPk |
||
101 | * OR |
||
102 | * tbl: [pkCol1, pkCol2] |
||
103 | * } |
||
104 | * |
||
105 | * @var array |
||
106 | */ |
||
107 | public $metaPrimaryKey = []; |
||
108 | |||
109 | /** |
||
110 | * Db profile |
||
111 | * |
||
112 | * {host, user, pass, name, type, lang} |
||
113 | * |
||
114 | * @var array |
||
115 | */ |
||
116 | public $profile = null; |
||
117 | |||
118 | /** |
||
119 | * Total query count |
||
120 | * |
||
121 | * @var int |
||
122 | */ |
||
123 | protected $queryCount = 0; |
||
124 | |||
125 | /** |
||
126 | * Sql generator object |
||
127 | * |
||
128 | * @var SqlGenerator |
||
129 | */ |
||
130 | protected $sqlGenerator; |
||
131 | |||
132 | |||
133 | /** |
||
134 | * constructor |
||
135 | * |
||
136 | * $dbprofile = {type:, host:, user:, pass:, name:, lang:,} |
||
137 | * type: mysql/sybase_ase etc. |
||
138 | * name: db name to select. |
||
139 | * lang: db server charset. |
||
140 | * |
||
141 | * if $pathAdodb is empty, should load ADOdb through ClassLoader. |
||
142 | * |
||
143 | * @param array $profile |
||
144 | * @param string $pathAdodb Include path of original ADOdb |
||
145 | */ |
||
146 | public function __construct($profile, $pathAdodb = '') |
||
166 | |||
167 | |||
168 | /** |
||
169 | * Redirect method call to ADOdb |
||
170 | * |
||
171 | * @var string $name Method name |
||
172 | * @var array $arg Method argument |
||
173 | * @return mixed |
||
174 | */ |
||
175 | public function __call($name, $arg) |
||
235 | |||
236 | |||
237 | /** |
||
238 | * Redirect property get to ADOdb |
||
239 | * |
||
240 | * @param string $name |
||
241 | * @return mixed |
||
242 | */ |
||
243 | public function __get($name) |
||
247 | |||
248 | |||
249 | /** |
||
250 | * Redirect property set to adodb |
||
251 | * |
||
252 | * @param string $name |
||
253 | * @param mixed $val |
||
254 | */ |
||
255 | public function __set($name, $val) |
||
270 | |||
271 | |||
272 | /** |
||
273 | * Connect to db |
||
274 | * |
||
275 | * If db is mysql, will auto execute 'set names utf8'. |
||
276 | * |
||
277 | * @see $profile |
||
278 | * @param boolean $forcenew Force new connection |
||
279 | * @return boolean |
||
280 | */ |
||
281 | public function connect($forcenew = false) |
||
358 | |||
359 | |||
360 | /** |
||
361 | * Convert encoding from db to sys |
||
362 | * |
||
363 | * Mostly used on query result. |
||
364 | * |
||
365 | * @param array|string &$result Array or string, not RecordSet object |
||
366 | * @return array|string |
||
367 | */ |
||
368 | View Code Duplication | public function convertEncodingResult(&$result) |
|
390 | |||
391 | |||
392 | /** |
||
393 | * Convert encoding from sys to db |
||
394 | * |
||
395 | * Mostly used on SQL statement. |
||
396 | * |
||
397 | * @param mixed &$sql |
||
398 | * @return mixed |
||
399 | */ |
||
400 | View Code Duplication | public function convertEncodingSql(&$sql) |
|
421 | |||
422 | |||
423 | /** |
||
424 | * Count how many db query have executed |
||
425 | * |
||
426 | * Can be extend to count on multi db objects. |
||
427 | * |
||
428 | * @param int $step |
||
429 | */ |
||
430 | protected function countQuery($step = 1) |
||
434 | |||
435 | |||
436 | /** |
||
437 | * Delete rows by condition user given |
||
438 | * |
||
439 | * Return value: |
||
440 | * -1 error, |
||
441 | * 0 not found, |
||
442 | * N > 0 number of deleted rows. |
||
443 | * |
||
444 | * @param string $table |
||
445 | * @param string $condition Not empty, can be raw sql where, having etc |
||
446 | * @return int |
||
447 | */ |
||
448 | View Code Duplication | public function deleteRow($table, $condition) |
|
472 | |||
473 | |||
474 | /** |
||
475 | * Alias of errorMessage() for backward compatible |
||
476 | */ |
||
477 | public function errorMsg() |
||
481 | |||
482 | |||
483 | /** |
||
484 | * Alias of errorCode() for backward compatible |
||
485 | */ |
||
486 | public function errorNo() |
||
490 | |||
491 | |||
492 | /** |
||
493 | * Execute SQL, without transaction |
||
494 | * |
||
495 | * @param mixed $sql SQL statement or sqlCfg for SqlGenerator |
||
496 | * @param mixed $inputArr |
||
497 | * @return object |
||
498 | */ |
||
499 | public function execute($sql, $inputArr = false) |
||
511 | |||
512 | |||
513 | /** |
||
514 | * Prepare and execute sql, with transaction |
||
515 | * |
||
516 | * @param string $sql |
||
517 | * @param array|boolean $inputArr Optional parameters in sql |
||
518 | * @return object |
||
519 | */ |
||
520 | public function executePrepare($sql, $inputArr = false) |
||
556 | |||
557 | |||
558 | /** |
||
559 | * Generate SQL statement |
||
560 | * |
||
561 | * User should avoid use SELECT/UPDATE/INSERT/DELETE simultaneously. |
||
562 | * |
||
563 | * Generate order by SQL statement format order. |
||
564 | * |
||
565 | * UPDATE/INSERT/DELETE is followed by [TBL_NAME], so need not use FROM. |
||
566 | * |
||
567 | * @see Fwlib\Db\SqlGenerator |
||
568 | * @param array $sqlConfig |
||
569 | * @return string |
||
570 | */ |
||
571 | public function generateSql($sqlConfig) |
||
579 | |||
580 | |||
581 | /** |
||
582 | * Generate SQL statement for Prepare |
||
583 | * |
||
584 | * Format like value -> ? or :name, and quote chars removed. |
||
585 | * |
||
586 | * @see generateSql() |
||
587 | * @see Fwlib\Db\SqlGenerator |
||
588 | * @param array $sqlConfig |
||
589 | * @return string |
||
590 | */ |
||
591 | public function generateSqlPrepared($sqlConfig) |
||
599 | |||
600 | |||
601 | /** |
||
602 | * Get single row data from single table using key |
||
603 | * |
||
604 | * Also, this method can be used to retrieve data from a table by primary |
||
605 | * or unique key, default and recommend for primary key, which can be auto |
||
606 | * retrieved from table meta. |
||
607 | * |
||
608 | * Whatever key is used, the result should only contain maximum one row, |
||
609 | * or the result is wrong, commonly only include data of first match row. |
||
610 | * |
||
611 | * |
||
612 | * $keyValue, $column, $keyColumn support multiple value split by ',' or |
||
613 | * array, eg: 'value' or 'value1, value2' or array('value1', 'value2') |
||
614 | * |
||
615 | * $column can use style like 'colName AS colAlias'. |
||
616 | * |
||
617 | * '*' can be used for $column, means all columns in table. |
||
618 | * |
||
619 | * Notice: if $column is array, must indexed by number start from 0. |
||
620 | * |
||
621 | * @param string $table |
||
622 | * @param int|string $keyValue |
||
623 | * @param string|array $column Empty or '*' for all column |
||
624 | * @param string|array $keyColumn Empty to use primary key |
||
625 | * @return int|string|array Single value or array of it, null if error |
||
626 | * occur |
||
627 | */ |
||
628 | public function getByKey( |
||
713 | |||
714 | |||
715 | /** |
||
716 | * Dummy for ADOdb's ErrorNo() |
||
717 | * |
||
718 | * @return int |
||
719 | */ |
||
720 | public function getErrorCode() |
||
724 | |||
725 | |||
726 | /** |
||
727 | * Dummy for ADOdb's ErrorMsg() |
||
728 | * |
||
729 | * @return string |
||
730 | */ |
||
731 | public function getErrorMessage() |
||
735 | |||
736 | |||
737 | /** |
||
738 | * Get table schema |
||
739 | * |
||
740 | * @see $metaColumn |
||
741 | * @param string $table |
||
742 | * @param boolean $forcenew Force to retrieve instead of read from cache |
||
743 | * @return array |
||
744 | */ |
||
745 | public function getMetaColumn($table, $forcenew = false) |
||
775 | |||
776 | |||
777 | /** |
||
778 | * Get table column name |
||
779 | * |
||
780 | * @see $metaColumnName |
||
781 | * @param string $table |
||
782 | * @param boolean $forcenew Force to retrieve instead of read from cache |
||
783 | * @return array |
||
784 | */ |
||
785 | public function getMetaColumnName($table, $forcenew = false) |
||
793 | |||
794 | |||
795 | /** |
||
796 | * Get primary key column of a table |
||
797 | * |
||
798 | * Return single string value or array for multi column primary key. |
||
799 | * |
||
800 | * @param string $table |
||
801 | * @param boolean $forcenew Force to retrieve instead of read from cache |
||
802 | * @return mixed |
||
803 | * @see $metaPrimaryKey |
||
804 | */ |
||
805 | public function getMetaPrimaryKey($table, $forcenew = false) |
||
898 | |||
899 | |||
900 | /** |
||
901 | * Get name of timestamp column of a table |
||
902 | * |
||
903 | * Timestamp column are various for different db, hard to test. |
||
904 | * |
||
905 | * @param $table |
||
906 | * @return string |
||
907 | */ |
||
908 | public function getMetaTimestamp($table) |
||
975 | |||
976 | |||
977 | /** |
||
978 | * Getter of $profile |
||
979 | * |
||
980 | * @return array |
||
981 | */ |
||
982 | public function getProfile() |
||
986 | |||
987 | |||
988 | /** |
||
989 | * Get string describe of profile |
||
990 | * |
||
991 | * Usually used for identify db source. |
||
992 | * |
||
993 | * @param string $separator |
||
994 | * @return string |
||
995 | */ |
||
996 | public function getProfileString($separator = '-') |
||
1002 | |||
1003 | |||
1004 | /** |
||
1005 | * Getter of $queryCount |
||
1006 | * |
||
1007 | * @return int |
||
1008 | */ |
||
1009 | public function getQueryCount() |
||
1013 | |||
1014 | |||
1015 | /** |
||
1016 | * Get rows count by condition user given |
||
1017 | * |
||
1018 | * Return value: |
||
1019 | * -1: error, |
||
1020 | * N >= 0: number of rows. |
||
1021 | * |
||
1022 | * @param string $table |
||
1023 | * @param string $condition Raw sql, can be WHERE, HAVING etc |
||
1024 | * @return int |
||
1025 | */ |
||
1026 | View Code Duplication | public function getRowCount($table, $condition = '') |
|
1047 | |||
1048 | |||
1049 | /** |
||
1050 | * Get delimiter between SQL for various db |
||
1051 | * |
||
1052 | * @param string $tail Tail of line for eye candy |
||
1053 | * @return string |
||
1054 | */ |
||
1055 | public function getSqlDelimiter($tail = "\n") |
||
1077 | |||
1078 | |||
1079 | /** |
||
1080 | * Get SqlGenerator instance |
||
1081 | * |
||
1082 | * @return SqlGenerator |
||
1083 | */ |
||
1084 | protected function getSqlGenerator() |
||
1092 | |||
1093 | |||
1094 | /** |
||
1095 | * Get SQL: begin transaction |
||
1096 | * |
||
1097 | * @return string |
||
1098 | */ |
||
1099 | public function getSqlTransBegin() |
||
1112 | |||
1113 | |||
1114 | /** |
||
1115 | * Get SQL: commit transaction |
||
1116 | * |
||
1117 | * @return string |
||
1118 | */ |
||
1119 | public function getSqlTransCommit() |
||
1123 | |||
1124 | |||
1125 | /** |
||
1126 | * Get SQL: rollback transaction |
||
1127 | * |
||
1128 | * @return string |
||
1129 | */ |
||
1130 | public function getSqlTransRollback() |
||
1134 | |||
1135 | |||
1136 | /** |
||
1137 | * If current db is connected successful |
||
1138 | * |
||
1139 | * @return boolean |
||
1140 | */ |
||
1141 | public function isConnected() |
||
1145 | |||
1146 | |||
1147 | /** |
||
1148 | * If current db type is mysql |
||
1149 | * |
||
1150 | * @return boolean |
||
1151 | */ |
||
1152 | public function isDbMysql() |
||
1156 | |||
1157 | |||
1158 | /** |
||
1159 | * If current db type is sybase and connect with PDO (DBLIB) |
||
1160 | * |
||
1161 | * @return bool |
||
1162 | */ |
||
1163 | public function isDbPdoSybase() |
||
1168 | |||
1169 | |||
1170 | /** |
||
1171 | * If current db type is sybase |
||
1172 | * |
||
1173 | * @return boolean |
||
1174 | */ |
||
1175 | public function isDbSybase() |
||
1182 | |||
1183 | |||
1184 | /** |
||
1185 | * If a table exists in db ? |
||
1186 | * |
||
1187 | * @param string $table |
||
1188 | * @return boolean |
||
1189 | */ |
||
1190 | View Code Duplication | public function isTableExist($table) |
|
1217 | |||
1218 | |||
1219 | /** |
||
1220 | * If timestamp column's value is unique |
||
1221 | * |
||
1222 | * @return boolean |
||
1223 | */ |
||
1224 | public function isTimestampUnique() |
||
1238 | |||
1239 | |||
1240 | /** |
||
1241 | * Generate a bind placeholder portable |
||
1242 | * |
||
1243 | * @param string $name |
||
1244 | * @return string |
||
1245 | */ |
||
1246 | public function param($name) |
||
1256 | |||
1257 | |||
1258 | /** |
||
1259 | * Generate a bind placeholder portable, for PDO only |
||
1260 | * |
||
1261 | * Will add CONVERT() for int/numeric data type |
||
1262 | * |
||
1263 | * @param string $table |
||
1264 | * @param string $name |
||
1265 | * @return string |
||
1266 | */ |
||
1267 | public function pdoParam($table, $name) |
||
1313 | |||
1314 | |||
1315 | /** |
||
1316 | * Smart quote string in sql, by check columns type |
||
1317 | * |
||
1318 | * @param string $table |
||
1319 | * @param string $col |
||
1320 | * @param mixed $val |
||
1321 | * @return string |
||
1322 | */ |
||
1323 | View Code Duplication | public function quoteValue($table, $col, $val) |
|
1376 | |||
1377 | |||
1378 | /** |
||
1379 | * Set PHP script file charset |
||
1380 | * |
||
1381 | * @param string $charset |
||
1382 | * @see $charsetPhp |
||
1383 | */ |
||
1384 | public function setCharsetPhp($charset) |
||
1388 | |||
1389 | |||
1390 | /** |
||
1391 | * Setter of fetchMode |
||
1392 | * |
||
1393 | * This is a transfer method to fool code inspection. |
||
1394 | * |
||
1395 | * @param int $fetchMode |
||
1396 | * @return int |
||
1397 | */ |
||
1398 | public function setFetchMode($fetchMode) |
||
1404 | |||
1405 | |||
1406 | /** |
||
1407 | * Smart write data row(s) to db |
||
1408 | * |
||
1409 | * Can auto check row existence, and decide to use INSERT or UPDATE, this |
||
1410 | * require primary key column included in $data array. Also, table MUST |
||
1411 | * have primary key defined. |
||
1412 | * |
||
1413 | * Param $data can include single row(1-dim array, index is column name) |
||
1414 | * or multiple rows(2-dim array, index layer 1 MUST be number and will not |
||
1415 | * write to db, layer 2 is same as single row). |
||
1416 | * |
||
1417 | * Param $mode is case insensitive: |
||
1418 | * A: auto detect, for multiple rows data, will only detect by FIRST row. |
||
1419 | * U: update, |
||
1420 | * I: insert, |
||
1421 | * |
||
1422 | * Return number of inserted or updated rows: |
||
1423 | * -1: got error, |
||
1424 | * N >=0: success, which N is affected rows. |
||
1425 | * |
||
1426 | * Even data to write exists in db and same, it will still do write |
||
1427 | * operation, and been counted in return value. |
||
1428 | * |
||
1429 | * @param string $table |
||
1430 | * @param array $data Row(s) data |
||
1431 | * @param string $mode Write mode |
||
1432 | * @return int |
||
1433 | */ |
||
1434 | public function write($table, $data, $mode = 'A') |
||
1590 | } |
||
1591 |
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.