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 |
||
| 13 | final class Prepare extends \mysqli_stmt |
||
| 14 | { |
||
| 15 | /** |
||
| 16 | * @var string - the unchanged query string provided to the constructor |
||
| 17 | */ |
||
| 18 | private $_sql = ''; |
||
| 19 | |||
| 20 | /** |
||
| 21 | * @var string - the query string with bound parameters interpolated |
||
| 22 | */ |
||
| 23 | private $_sql_with_bound_parameters = ''; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * @var bool |
||
| 27 | */ |
||
| 28 | private $_use_bound_parameters_interpolated = false; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * @var array - array of arrays containing values that have been bound to the query as parameters |
||
| 32 | */ |
||
| 33 | private $_boundParams = []; |
||
| 34 | |||
| 35 | /** |
||
| 36 | * @var DB |
||
| 37 | */ |
||
| 38 | private $_db; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * @var Debug |
||
| 42 | */ |
||
| 43 | private $_debug; |
||
| 44 | |||
| 45 | /** |
||
| 46 | * Prepare constructor. |
||
| 47 | * |
||
| 48 | * @param DB $db |
||
| 49 | * @param string $query |
||
| 50 | */ |
||
| 51 | 10 | public function __construct(DB $db, string $query) |
|
| 60 | |||
| 61 | /** |
||
| 62 | * Prepare destructor. |
||
| 63 | */ |
||
| 64 | 10 | public function __destruct() |
|
| 68 | |||
| 69 | /** |
||
| 70 | * Combines the values stored in $this->boundParams into one array suitable for pushing as the input arguments to |
||
| 71 | * parent::bind_param when used with call_user_func_array |
||
| 72 | * |
||
| 73 | * @return array |
||
| 74 | */ |
||
| 75 | 6 | private function _buildArguments(): array |
|
| 87 | |||
| 88 | /** |
||
| 89 | * Escapes the supplied value. |
||
| 90 | * |
||
| 91 | * @param array $param |
||
| 92 | * |
||
| 93 | * @return array 0 => "$value" escaped<br /> |
||
| 94 | * 1 => "$valueForSqlWithBoundParameters" for insertion into the interpolated query string |
||
| 95 | */ |
||
| 96 | 6 | private function _prepareValue(array &$param): array |
|
| 115 | |||
| 116 | /** |
||
| 117 | * @return int |
||
| 118 | */ |
||
| 119 | public function affected_rows(): int |
||
| 123 | |||
| 124 | /** |
||
| 125 | * This is a wrapper for "bind_param" what binds variables to a prepared statement as parameters. If you use this |
||
| 126 | * wrapper, you can debug your query with e.g. "$this->get_sql_with_bound_parameters()". |
||
| 127 | * |
||
| 128 | * @param string $types <strong>i<strong> corresponding variable has type integer<br /> |
||
| 129 | * <strong>d</strong> corresponding variable has type double<br /> |
||
| 130 | * <strong>s</strong> corresponding variable has type string<br /> |
||
| 131 | * <strong>b</strong> corresponding variable is a blob and will be sent in packets |
||
| 132 | * |
||
| 133 | * INFO: We have to explicitly declare all parameters as references, otherwise it does not seem possible to pass |
||
| 134 | * them on without losing the reference property |
||
| 135 | * @param mixed ...$v |
||
| 136 | * |
||
| 137 | * @return bool |
||
| 138 | */ |
||
| 139 | 6 | public function bind_param_debug(string $types, &...$v): bool |
|
| 170 | |||
| 171 | /** |
||
| 172 | * {@inheritdoc} |
||
| 173 | * |
||
| 174 | * @return bool |
||
| 175 | */ |
||
| 176 | public function execute_raw(): bool |
||
| 180 | |||
| 181 | /** |
||
| 182 | * Executes a prepared Query |
||
| 183 | * |
||
| 184 | * @see http://php.net/manual/en/mysqli-stmt.execute.php |
||
| 185 | * |
||
| 186 | * @return bool|int|Result|string "Result" by "<b>SELECT</b>"-queries<br /> |
||
| 187 | * "int|string" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br /> |
||
| 188 | * "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br /> |
||
| 189 | * "true" by e.g. "DROP"-queries<br /> |
||
| 190 | * "false" on error |
||
| 191 | */ |
||
| 192 | 9 | public function execute() |
|
| 249 | |||
| 250 | /** |
||
| 251 | * Prepare an SQL statement for execution |
||
| 252 | * |
||
| 253 | * @see http://php.net/manual/en/mysqli-stmt.prepare.php |
||
| 254 | * |
||
| 255 | * @param string $query <p> |
||
| 256 | * The query, as a string. It must consist of a single SQL statement. |
||
| 257 | * </p> |
||
| 258 | * <p> |
||
| 259 | * You can include one or more parameter markers in the SQL statement by |
||
| 260 | * embedding question mark (?) characters at the |
||
| 261 | * appropriate positions. |
||
| 262 | * </p> |
||
| 263 | * <p> |
||
| 264 | * You should not add a terminating semicolon or \g |
||
| 265 | * to the statement. |
||
| 266 | * </p> |
||
| 267 | * <p> |
||
| 268 | * The markers are legal only in certain places in SQL statements. |
||
| 269 | * For example, they are allowed in the VALUES() list of an INSERT statement |
||
| 270 | * (to specify column values for a row), or in a comparison with a column in |
||
| 271 | * a WHERE clause to specify a comparison value. |
||
| 272 | * </p> |
||
| 273 | * <p> |
||
| 274 | * However, they are not allowed for identifiers (such as table or column names), |
||
| 275 | * in the select list that names the columns to be returned by a SELECT statement), |
||
| 276 | * or to specify both operands of a binary operator such as the = |
||
| 277 | * equal sign. The latter restriction is necessary because it would be impossible |
||
| 278 | * to determine the parameter type. In general, parameters are legal only in Data |
||
| 279 | * Manipulation Language (DML) statements, and not in Data Definition Language |
||
| 280 | * (DDL) statements. |
||
| 281 | * </p> |
||
| 282 | * |
||
| 283 | * @return bool |
||
| 284 | * <p>false on error</p> |
||
| 285 | * |
||
| 286 | * @since 5.0 |
||
| 287 | */ |
||
| 288 | 10 | public function prepare($query): bool |
|
| 315 | |||
| 316 | /** |
||
| 317 | * Ger the bound parameters from sql-query as array, if you use the "$this->bind_param_debug()" method. |
||
| 318 | * |
||
| 319 | * @return array |
||
| 320 | */ |
||
| 321 | public function get_bound_params(): array |
||
| 325 | |||
| 326 | /** |
||
| 327 | * @return string |
||
| 328 | */ |
||
| 329 | public function get_sql(): string |
||
| 333 | |||
| 334 | /** |
||
| 335 | * Get the sql-query with bound parameters, if you use the "$this->bind_param_debug()" method. |
||
| 336 | * |
||
| 337 | * @return string |
||
| 338 | */ |
||
| 339 | 4 | public function get_sql_with_bound_parameters(): string |
|
| 343 | |||
| 344 | /** |
||
| 345 | * @return int |
||
| 346 | */ |
||
| 347 | public function insert_id(): int |
||
| 351 | |||
| 352 | /** |
||
| 353 | * Copies $this->_sql then replaces bound markers with associated values ($this->_sql is not modified |
||
| 354 | * but the resulting query string is assigned to $this->sql_bound_parameters) |
||
| 355 | * |
||
| 356 | * @return string $testQuery - interpolated db query string |
||
| 357 | */ |
||
| 358 | 6 | private function interpolateQuery(): string |
|
| 379 | |||
| 380 | /** |
||
| 381 | * Error-handling for the sql-query. |
||
| 382 | * |
||
| 383 | * @param string $errorMsg |
||
| 384 | * @param string $sql |
||
| 385 | * |
||
| 386 | * @throws DBGoneAwayException |
||
| 387 | * @throws QueryException |
||
| 388 | * |
||
| 389 | * @return bool|int|Result|string "Result" by "<b>SELECT</b>"-queries<br /> |
||
| 390 | * "int|string" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br /> |
||
| 391 | * "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br /> |
||
| 392 | * "true" by e.g. "DROP"-queries<br /> |
||
| 393 | * "false" on error |
||
| 394 | */ |
||
| 395 | 2 | private function queryErrorHandling(string $errorMsg, string $sql) |
|
| 424 | } |
||
| 425 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.