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 Db 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 Db, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
21 | class Db |
||
22 | { //------------------------------------------------------// |
||
23 | // クラス変数定義 |
||
24 | //------------------------------------------------------// |
||
25 | /** |
||
26 | * $pdo_instance |
||
27 | * @access private |
||
28 | * @var object PDOクラスインスタンスを保持 |
||
29 | * @instanceof \PDO |
||
30 | */ |
||
31 | private $pdo_instance = ''; |
||
32 | |||
33 | /** |
||
34 | * $pdostatement_instance |
||
35 | * @access private |
||
36 | * @var object PDOStatementクラスインスタンスを保持 |
||
37 | * @instanceof \PDOStatement |
||
38 | */ |
||
39 | private $pdostatement_instance = ''; |
||
40 | |||
41 | /** |
||
42 | * $dbinfo |
||
43 | * @access private |
||
44 | * @var array DB接続に必要な情報 |
||
45 | */ |
||
46 | private $dbinfo = [ ]; |
||
47 | |||
48 | //------------------------------------------------------// |
||
49 | // クラスメソッド定義 |
||
50 | //------------------------------------------------------// |
||
51 | use RisolutoErrorLogTrait; |
||
52 | |||
53 | /** |
||
54 | * connect(array $param) |
||
55 | * |
||
56 | * DBへの接続を開始する |
||
57 | * |
||
58 | * @param array $param DB接続に必要となる情報を含んだ配列 |
||
59 | * @param array $option DB接続に指定するオプション情報を含んだ配列 |
||
60 | * |
||
61 | * @return boolean 実行結果(true: 成功 / false: 失敗) |
||
62 | * |
||
63 | */ |
||
64 | public function connect( array $param, array $option = [ ] ) |
||
102 | |||
103 | /** |
||
104 | * disConnect($force = false) |
||
105 | * |
||
106 | * DBへの接続を終了する |
||
107 | * |
||
108 | * @param boolean $force 持続的接続時に切断するか(true: 切断する / false: 切断しない(デフォルト)) |
||
109 | * |
||
110 | * @return boolean 常にtrue |
||
111 | * |
||
112 | */ |
||
113 | public function disConnect( $force = false ) |
||
122 | |||
123 | /** |
||
124 | * getAttribute($attribute) |
||
125 | * |
||
126 | * DB接続に関する属性値を取得する |
||
127 | * |
||
128 | * @param string $attribute 取得対象となるアトリビュート(PDO::ATTR_*から「PDO::ATTR_*」を除いたもの、または「ALL」) |
||
129 | * |
||
130 | * @return array 属性値が格納された連想配列 |
||
131 | * |
||
132 | */ |
||
133 | public function getAttribute( $attribute = 'ALL' ) |
||
189 | |||
190 | /** |
||
191 | * setAttribute($attribute, $value) |
||
192 | * |
||
193 | * DB接続に関する属性値をセットする |
||
194 | * |
||
195 | * @param integer $attribute 設定対象となるアトリビュート |
||
196 | * @param mixed $value 設定する値 |
||
197 | * |
||
198 | * @return boolean true:正常終了/false:異常終了 |
||
199 | * |
||
200 | */ |
||
201 | public function setAttribute( $attribute, $value ) |
||
209 | |||
210 | /** |
||
211 | * beginTransaction() |
||
212 | * |
||
213 | * トランザクションを開始する |
||
214 | * |
||
215 | * @param void |
||
216 | * |
||
217 | * @return boolean true:正常終了/false:異常終了 |
||
218 | * |
||
219 | */ |
||
220 | public function beginTransaction() |
||
224 | |||
225 | /** |
||
226 | * inTransaction() |
||
227 | * |
||
228 | * トランザクションが開始しているかを判定する |
||
229 | * |
||
230 | * @param void |
||
231 | * |
||
232 | * @return boolean true:トランザクションが開始している/false:トランザクションが開始していない |
||
233 | * |
||
234 | */ |
||
235 | public function inTransaction() |
||
239 | |||
240 | /** |
||
241 | * commit() |
||
242 | * |
||
243 | * トランザクションをコミットする |
||
244 | * |
||
245 | * @param void |
||
246 | * |
||
247 | * @return boolean true:正常終了/false:異常終了 |
||
248 | * |
||
249 | */ |
||
250 | public function commit() |
||
254 | |||
255 | /** |
||
256 | * rollBack() |
||
257 | * |
||
258 | * トランザクションをロールバックする |
||
259 | * |
||
260 | * @param void |
||
261 | * |
||
262 | * @return boolean true:正常終了/false:異常終了 |
||
263 | * |
||
264 | */ |
||
265 | public function rollBack() |
||
276 | |||
277 | /** |
||
278 | * lastInsertId($name) |
||
279 | * |
||
280 | * 最後に挿入されたID値を取得する |
||
281 | * |
||
282 | * @param string $name 取得対象となるID値のカラム名 |
||
283 | * |
||
284 | * @return string 取得したID値 |
||
285 | * |
||
286 | */ |
||
287 | public function lastInsertId( $name = null ) |
||
298 | |||
299 | /** |
||
300 | * exec($sql) |
||
301 | * |
||
302 | * SQLを実行する |
||
303 | * |
||
304 | * @param string $sql 実行するSQL |
||
305 | * |
||
306 | * @return boolean true:正常終了/false:異常終了 |
||
307 | * |
||
308 | */ |
||
309 | public function exec( $sql ) |
||
317 | |||
318 | /** |
||
319 | * doQuery($sql = '', array $param = [], array $query_options = [], $fetch_style = \PDO::FETCH_ASSOC) |
||
320 | * |
||
321 | * SQLを実行する |
||
322 | * |
||
323 | * @param string $sql 実行するSQL("clear"が指定された場合はPDOStatementのインスタンスをクリア) |
||
324 | * @param array $param PDOStatement::bindParam()へ渡すバインドする値(array(id, value, type[, length])) |
||
325 | * @param array $query_options PDO::prepare()へ渡すオプション |
||
326 | * @param integer $fetch_style PDOStatement::fetchAll()へ渡すオプション(\PDO::FETCH_**のいずれか) |
||
327 | * |
||
328 | * @return mixed SQLの実行結果/false:異常終了 |
||
329 | * |
||
330 | */ |
||
331 | public function doQuery( |
||
404 | |||
405 | /** |
||
406 | * genDSN() |
||
407 | * |
||
408 | * DSN文字列を生成する |
||
409 | * |
||
410 | * @access private |
||
411 | * |
||
412 | * @param void |
||
413 | * |
||
414 | * @return string DSN文字列 |
||
415 | */ |
||
416 | private function genDSN() |
||
453 | |||
454 | /** |
||
455 | * genErrorMsg($key = '') |
||
456 | * |
||
457 | * クラス内で発生したエラーに対するエラーメッセージを生成する |
||
458 | * |
||
459 | * @access private |
||
460 | * |
||
461 | * @param string $key エラーを示すキー文字列 |
||
462 | * @param string $optional_text オプションの文字列 |
||
463 | * |
||
464 | * @return string エラーメッセージ |
||
465 | */ |
||
466 | private function genErrorMsg( $key = '', $optional_text = '' ) |
||
492 | } |
||
493 |
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.