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 |
||
37 | class TraitDefinition extends AbstractStructureDefinition implements PropertiedStructureInterface |
||
38 | { |
||
39 | |||
40 | /** |
||
41 | * @const string TYPE The structure type |
||
42 | */ |
||
43 | const TYPE = 'trait'; |
||
44 | |||
45 | /** |
||
46 | * List of defined attributes |
||
47 | * |
||
48 | * @var \AppserverIo\Doppelgaenger\Entities\Lists\AttributeDefinitionList $attributeDefinitions |
||
49 | */ |
||
50 | protected $attributeDefinitions; |
||
51 | |||
52 | /** |
||
53 | * Trait constants |
||
54 | * |
||
55 | * @var array $constants |
||
56 | */ |
||
57 | protected $constants; |
||
58 | |||
59 | /** |
||
60 | * List of directly defined invariant conditions |
||
61 | * |
||
62 | * @var \AppserverIo\Doppelgaenger\Entities\Lists\AssertionList $invariantConditions |
||
63 | */ |
||
64 | protected $invariantConditions; |
||
65 | |||
66 | /** |
||
67 | * Default constructor |
||
68 | * |
||
69 | * @param string $path File path to the class definition |
||
70 | * @param string $namespace The namespace the class belongs to |
||
71 | * @param string $docBlock The initial class docblock header |
||
72 | * @param string $name Name of the class |
||
73 | * @param null $attributeDefinitions List of defined attributes |
||
74 | * @param null $invariantConditions List of directly defined invariant conditions |
||
75 | */ |
||
76 | public function __construct( |
||
93 | |||
94 | /** |
||
95 | * Getter method for attribute $attributeDefinitions |
||
96 | * |
||
97 | * @return null|AttributeDefinitionList |
||
98 | */ |
||
99 | public function getAttributeDefinitions() |
||
103 | |||
104 | /** |
||
105 | * Getter method for attribute $constants |
||
106 | * |
||
107 | * @return array |
||
108 | */ |
||
109 | public function getConstants() |
||
113 | |||
114 | /** |
||
115 | * Will return a list of all dependencies eg. parent class, interfaces and traits. |
||
116 | * |
||
117 | * @return array |
||
118 | */ |
||
119 | public function getDependencies() |
||
123 | |||
124 | /** |
||
125 | * Will return all invariants. |
||
126 | * |
||
127 | * @param boolean $nonPrivateOnly Make this true if you only want conditions which do not have a private context |
||
128 | * |
||
129 | * @return \AppserverIo\Doppelgaenger\Entities\Lists\AssertionList |
||
130 | */ |
||
131 | View Code Duplication | public function getInvariants($nonPrivateOnly = false) |
|
153 | |||
154 | /** |
||
155 | * Getter method for attribute $invariantConditions |
||
156 | * |
||
157 | * @return null|AssertionList |
||
158 | */ |
||
159 | public function getInvariantConditions() |
||
163 | |||
164 | /** |
||
165 | * Does this structure have parent structures? |
||
166 | * Traits do not by default |
||
167 | * |
||
168 | * @return boolean |
||
169 | */ |
||
170 | public function hasParents() |
||
174 | |||
175 | /** |
||
176 | * Setter method for attribute $attributeDefinitions |
||
177 | * |
||
178 | * @param \AppserverIo\Doppelgaenger\Entities\Lists\AttributeDefinitionList $attributeDefinitions List of attribute definitions |
||
179 | * |
||
180 | * @return null |
||
181 | */ |
||
182 | public function setAttributeDefinitions(AttributeDefinitionList $attributeDefinitions) |
||
186 | |||
187 | /** |
||
188 | * Setter method for the $constants property |
||
189 | * |
||
190 | * @param array $constants Constants the class defines |
||
191 | * |
||
192 | * @return null |
||
193 | */ |
||
194 | public function setConstants($constants) |
||
198 | |||
199 | /** |
||
200 | * Setter method for attribute $invariantConditions |
||
201 | * |
||
202 | * @param \AppserverIo\Doppelgaenger\Entities\Lists\AssertionList $invariantConditions List of invariant assertions |
||
203 | * |
||
204 | * @return null |
||
205 | */ |
||
206 | public function setInvariantConditions(AssertionList $invariantConditions) |
||
210 | } |
||
211 |
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.