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 |
||
7 | class ForeignKey implements ConstraintInterface |
||
8 | { |
||
9 | |||
10 | const ACTION_NO_ACTION = 'NO ACTION'; |
||
11 | const ACTION_CASCADE = 'CASCADE'; |
||
12 | const ACTION_RESTICT = 'RESTRICT'; |
||
13 | const ACTION_DEFAULT = 'SET DEFAULT'; |
||
14 | const ACTION_SET_NULL = 'SET NULL'; |
||
15 | |||
16 | private $columns; |
||
17 | private $table; |
||
18 | private $referencedTable; |
||
19 | private $updateAction; |
||
20 | private $deleteAction; |
||
21 | |||
22 | /** |
||
23 | * Constructor. |
||
24 | * |
||
25 | * @param Table $table Table instance. |
||
26 | * @param Table $referencedTable Table reference instance. |
||
27 | */ |
||
28 | public function __construct(Table $table, Table $referencedTable) |
||
35 | |||
36 | /** |
||
37 | * {@inheritdoc} |
||
38 | */ |
||
39 | public function getName() |
||
46 | |||
47 | /** |
||
48 | * {@inheritdoc} |
||
49 | */ |
||
50 | public function getTable() |
||
54 | |||
55 | /** |
||
56 | * Sets a table instance. |
||
57 | * |
||
58 | * @param Table $table Table instance. |
||
59 | * |
||
60 | * @return PrimaryKey Self. |
||
61 | */ |
||
62 | public function setTable(Table $table) |
||
68 | |||
69 | /** |
||
70 | * Gets a reference table name. |
||
71 | * |
||
72 | * @return string Reference table name. |
||
73 | */ |
||
74 | public function getReferencedTable() |
||
78 | |||
79 | /** |
||
80 | * Sets foreign key columns. |
||
81 | * |
||
82 | * @param array $columns Columns list. |
||
83 | * |
||
84 | * @return ForeignKey Self instance. |
||
85 | */ |
||
86 | View Code Duplication | public function setColumns($columns) |
|
95 | |||
96 | /** |
||
97 | * Gets column names. |
||
98 | * |
||
99 | * @return array Column names. |
||
100 | */ |
||
101 | public function getColumns() |
||
105 | |||
106 | /** |
||
107 | * Sets foreign key reference columns. |
||
108 | * |
||
109 | * @param array $columns Columns list. |
||
110 | * |
||
111 | * @return ForeignKey Self instance. |
||
112 | */ |
||
113 | View Code Duplication | public function setReferencedColumns($columns) |
|
122 | |||
123 | /** |
||
124 | * Gets reference column names. |
||
125 | * |
||
126 | * @return array Column names. |
||
127 | */ |
||
128 | public function getReferencedColumns() |
||
132 | |||
133 | /** |
||
134 | * Gets an update action. |
||
135 | * |
||
136 | * @return string |
||
137 | */ |
||
138 | public function getUpdateAction() |
||
142 | |||
143 | /** |
||
144 | * Gets a delete action. |
||
145 | * |
||
146 | * @return string |
||
147 | */ |
||
148 | public function getDeleteAction() |
||
152 | |||
153 | /** |
||
154 | * Sets an update action. |
||
155 | * |
||
156 | * @param string $updateAction Update action. |
||
157 | * |
||
158 | * @throws InvalidArgumentException If the provided argument is not of action type. |
||
159 | * |
||
160 | * @return void |
||
161 | */ |
||
162 | View Code Duplication | public function setUpdateAction($updateAction) |
|
170 | |||
171 | /** |
||
172 | * Sets a delete action. |
||
173 | * |
||
174 | * @param string $deleteAction Delete action. |
||
175 | * |
||
176 | * @throws InvalidArgumentException If the provided argument is not of action type. |
||
177 | * |
||
178 | * @return void |
||
179 | */ |
||
180 | View Code Duplication | public function setDeleteAction($deleteAction) |
|
188 | |||
189 | /** |
||
190 | * Sets an update action on restrict. |
||
191 | * |
||
192 | * @return ForeignKey |
||
193 | */ |
||
194 | public function updateRestrict() |
||
200 | |||
201 | /** |
||
202 | * Sets an update action on cascade. |
||
203 | * |
||
204 | * @return ForeignKey |
||
205 | */ |
||
206 | public function updateCascade() |
||
212 | |||
213 | /** |
||
214 | * Sets an update action on set null. |
||
215 | * |
||
216 | * @return ForeignKey |
||
217 | */ |
||
218 | public function updateSetNull() |
||
224 | |||
225 | /** |
||
226 | * Sets an update action on default. |
||
227 | * |
||
228 | * @return ForeignKey |
||
229 | */ |
||
230 | public function updateSetDefault() |
||
236 | |||
237 | /** |
||
238 | * Sets a delete action on restrict. |
||
239 | * |
||
240 | * @return ForeignKey |
||
241 | */ |
||
242 | public function deleteRestrict() |
||
248 | |||
249 | /** |
||
250 | * Sets a delete action on cascade. |
||
251 | * |
||
252 | * @return ForeignKey |
||
253 | */ |
||
254 | public function deleteCascade() |
||
260 | |||
261 | /** |
||
262 | * Sets a delete action on set null. |
||
263 | * |
||
264 | * @return ForeignKey |
||
265 | */ |
||
266 | public function deleteSetNull() |
||
272 | |||
273 | /** |
||
274 | * Sets a delete action on default. |
||
275 | * |
||
276 | * @return ForeignKey |
||
277 | */ |
||
278 | public function deleteSetDefault() |
||
284 | |||
285 | private function getAvailableActions() |
||
295 | } |
||
296 |
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.