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 declare(strict_types=1); |
||
28 | class Driver extends AbstractDriver implements DriverInterface { |
||
29 | |||
30 | /** |
||
31 | * Reference to the resource returned by |
||
32 | * the last query executed |
||
33 | * |
||
34 | * @var resource |
||
35 | */ |
||
36 | protected $statementLink = NULL; |
||
37 | |||
38 | /** |
||
39 | * Reference to the current transaction |
||
40 | * |
||
41 | * @var resource |
||
42 | */ |
||
43 | protected $trans = NULL; |
||
44 | |||
45 | /** |
||
46 | * Reference to the connection resource |
||
47 | * |
||
48 | * @var resource |
||
49 | */ |
||
50 | protected $conn = NULL; |
||
51 | |||
52 | /** |
||
53 | * Reference to the service resource |
||
54 | * |
||
55 | * @var resource |
||
56 | */ |
||
57 | protected $service = NULL; |
||
58 | |||
59 | /** |
||
60 | * Firebird doesn't have the truncate keyword |
||
61 | * |
||
62 | * @var boolean |
||
63 | */ |
||
64 | protected $hasTruncate = FALSE; |
||
65 | |||
66 | /** |
||
67 | * Open the link to the database |
||
68 | * |
||
69 | * @param string $dbpath |
||
70 | * @param string $user |
||
71 | * @param string $pass |
||
72 | * @param array $options |
||
73 | * @throws PDOException |
||
74 | */ |
||
75 | public function __construct($dbpath, $user='SYSDBA', $pass='masterkey', array $options = []) |
||
96 | |||
97 | /** |
||
98 | * Cleanup some loose ends |
||
99 | * @codeCoverageIgnore |
||
100 | */ |
||
101 | public function __destruct() |
||
105 | |||
106 | /** |
||
107 | * Return service handle |
||
108 | * |
||
109 | * @return resource |
||
110 | */ |
||
111 | public function getService() |
||
115 | |||
116 | /** |
||
117 | * Execute an sql statement and return number of affected rows |
||
118 | * |
||
119 | * @param string $sql |
||
120 | * @return int |
||
121 | */ |
||
122 | public function exec($sql) |
||
126 | |||
127 | /** |
||
128 | * Implement for compatibility with PDO |
||
129 | * |
||
130 | * @param int $attribute |
||
131 | * @return mixed |
||
132 | */ |
||
133 | public function getAttribute($attribute) |
||
137 | |||
138 | /** |
||
139 | * Return whether the current statement is in a transaction |
||
140 | * |
||
141 | * @return bool |
||
142 | */ |
||
143 | public function inTransaction() |
||
147 | |||
148 | /** |
||
149 | * Returns the last value of the specified generator |
||
150 | * |
||
151 | * @param string $name |
||
152 | * @return mixed |
||
153 | */ |
||
154 | public function lastInsertId($name = NULL) |
||
158 | |||
159 | /** |
||
160 | * Wrapper public function to better match PDO |
||
161 | * |
||
162 | * @param string $sql |
||
163 | * @return Result |
||
164 | * @throws PDOException |
||
165 | */ |
||
166 | public function query($sql = '') |
||
188 | |||
189 | /** |
||
190 | * Emulate PDO prepare |
||
191 | * |
||
192 | * @param string $query |
||
193 | * @param array $options |
||
194 | * @return Result |
||
195 | * @throws PDOException |
||
196 | */ |
||
197 | public function prepare($query, $options=[]) |
||
211 | |||
212 | /** |
||
213 | * Start a database transaction |
||
214 | * |
||
215 | * @return boolean|null |
||
216 | */ |
||
217 | public function beginTransaction() |
||
221 | |||
222 | /** |
||
223 | * Commit a database transaction |
||
224 | * |
||
225 | * @return bool |
||
226 | */ |
||
227 | public function commit() |
||
233 | |||
234 | /** |
||
235 | * Rollback a transaction |
||
236 | * |
||
237 | * @return bool |
||
238 | */ |
||
239 | public function rollBack() |
||
245 | |||
246 | /** |
||
247 | * Set a connection attribute |
||
248 | * @param int $attribute |
||
249 | * @param mixed $value |
||
250 | * @return bool |
||
251 | */ |
||
252 | public function setAttribute($attribute, $value) |
||
256 | |||
257 | /** |
||
258 | * Prepare and execute a query |
||
259 | * |
||
260 | * @param string $sql |
||
261 | * @param array $args |
||
262 | * @return Result |
||
263 | */ |
||
264 | public function prepareExecute($sql, $args) |
||
273 | |||
274 | /** |
||
275 | * Method to emulate PDO->quote |
||
276 | * |
||
277 | * @param string $str |
||
278 | * @param int $paramType |
||
279 | * @return string |
||
280 | */ |
||
281 | public function quote($str, $paramType = PDO::PARAM_STR) |
||
290 | |||
291 | /** |
||
292 | * Method to emulate PDO->errorInfo / PDOStatement->errorInfo |
||
293 | * |
||
294 | * @return array |
||
295 | */ |
||
296 | public function errorInfo() |
||
303 | |||
304 | /** |
||
305 | * Method to emulate PDO->errorCode |
||
306 | * |
||
307 | * @return array |
||
308 | */ |
||
309 | public function errorCode() |
||
313 | |||
314 | /** |
||
315 | * Bind a prepared query with arguments for executing |
||
316 | * |
||
317 | * @param string $sql |
||
318 | * @param array $params |
||
319 | * @return NULL |
||
320 | */ |
||
321 | public function prepareQuery($sql, $params) |
||
327 | |||
328 | /** |
||
329 | * Create sql for batch insert |
||
330 | * |
||
331 | * @param string $table |
||
332 | * @param array $data |
||
333 | * @return array |
||
334 | */ |
||
335 | public function insertBatch($table, $data=[]) |
||
370 | } |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.