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 Model 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 Model, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
24 | abstract class Model implements \ArrayAccess |
||
25 | { |
||
26 | const IMMUTABLE = 0; |
||
27 | const MUTABLE_CREATE_ONLY = 1; |
||
28 | const MUTABLE = 2; |
||
29 | |||
30 | const TYPE_STRING = 'string'; |
||
31 | const TYPE_NUMBER = 'number'; |
||
32 | const TYPE_BOOLEAN = 'boolean'; |
||
33 | const TYPE_DATE = 'date'; |
||
34 | const TYPE_OBJECT = 'object'; |
||
35 | const TYPE_ARRAY = 'array'; |
||
36 | |||
37 | const ERROR_REQUIRED_FIELD_MISSING = 'required_field_missing'; |
||
38 | const ERROR_VALIDATION_FAILED = 'validation_failed'; |
||
39 | const ERROR_NOT_UNIQUE = 'not_unique'; |
||
40 | |||
41 | const DEFAULT_ID_PROPERTY = 'id'; |
||
42 | |||
43 | ///////////////////////////// |
||
44 | // Model visible variables |
||
45 | ///////////////////////////// |
||
46 | |||
47 | /** |
||
48 | * List of model ID property names. |
||
49 | * |
||
50 | * @staticvar array |
||
51 | */ |
||
52 | protected static $ids = [self::DEFAULT_ID_PROPERTY]; |
||
53 | |||
54 | /** |
||
55 | * Property definitions expressed as a key-value map with |
||
56 | * property names as the keys. |
||
57 | * i.e. ['enabled' => ['type' => Model::TYPE_BOOLEAN]]. |
||
58 | * |
||
59 | * @staticvar array |
||
60 | */ |
||
61 | protected static $properties = []; |
||
62 | |||
63 | /** |
||
64 | * @staticvar \Pimple\Container |
||
65 | */ |
||
66 | protected static $injectedApp; |
||
67 | |||
68 | /** |
||
69 | * @staticvar array |
||
70 | */ |
||
71 | protected static $dispatchers; |
||
72 | |||
73 | /** |
||
74 | * @var number|string|bool |
||
75 | */ |
||
76 | protected $_id; |
||
77 | |||
78 | /** |
||
79 | * @var \Pimple\Container |
||
80 | */ |
||
81 | protected $app; |
||
82 | |||
83 | /** |
||
84 | * @var array |
||
85 | */ |
||
86 | protected $_values = []; |
||
87 | |||
88 | /** |
||
89 | * @var array |
||
90 | */ |
||
91 | protected $_unsaved = []; |
||
92 | |||
93 | /** |
||
94 | * @var array |
||
95 | */ |
||
96 | protected $_relationships = []; |
||
97 | |||
98 | ///////////////////////////// |
||
99 | // Base model variables |
||
100 | ///////////////////////////// |
||
101 | |||
102 | /** |
||
103 | * @staticvar array |
||
104 | */ |
||
105 | private static $propertyDefinitionBase = [ |
||
106 | 'type' => self::TYPE_STRING, |
||
107 | 'mutable' => self::MUTABLE, |
||
108 | 'null' => false, |
||
109 | 'unique' => false, |
||
110 | 'required' => false, |
||
111 | ]; |
||
112 | |||
113 | /** |
||
114 | * @staticvar array |
||
115 | */ |
||
116 | private static $defaultIDProperty = [ |
||
117 | 'type' => self::TYPE_NUMBER, |
||
118 | 'mutable' => self::IMMUTABLE, |
||
119 | ]; |
||
120 | |||
121 | /** |
||
122 | * @staticvar array |
||
123 | */ |
||
124 | private static $timestampProperties = [ |
||
125 | 'created_at' => [ |
||
126 | 'type' => self::TYPE_DATE, |
||
127 | 'default' => null, |
||
128 | 'null' => true, |
||
129 | 'validate' => 'timestamp|db_timestamp', |
||
130 | ], |
||
131 | 'updated_at' => [ |
||
132 | 'type' => self::TYPE_DATE, |
||
133 | 'validate' => 'timestamp|db_timestamp', |
||
134 | ], |
||
135 | ]; |
||
136 | |||
137 | /** |
||
138 | * @staticvar array |
||
139 | */ |
||
140 | private static $initialized = []; |
||
141 | |||
142 | /** |
||
143 | * @staticvar Model\Driver\DriverInterface |
||
144 | */ |
||
145 | private static $driver; |
||
146 | |||
147 | /** |
||
148 | * @staticvar array |
||
149 | */ |
||
150 | private static $accessors = []; |
||
151 | |||
152 | /** |
||
153 | * @staticvar array |
||
154 | */ |
||
155 | private static $mutators = []; |
||
156 | |||
157 | /** |
||
158 | * @var bool |
||
159 | */ |
||
160 | private $_ignoreUnsaved; |
||
161 | |||
162 | /** |
||
163 | * Creates a new model object. |
||
164 | * |
||
165 | * @param array|string|Model|false $id ordered array of ids or comma-separated id string |
||
166 | * @param array $values optional key-value map to pre-seed model |
||
167 | */ |
||
168 | public function __construct($id = false, array $values = []) |
||
197 | |||
198 | /** |
||
199 | * Performs initialization on this model. |
||
200 | */ |
||
201 | private function init() |
||
210 | |||
211 | /** |
||
212 | * The initialize() method is called once per model. It's used |
||
213 | * to perform any one-off tasks before the model gets |
||
214 | * constructed. This is a great place to add any model |
||
215 | * properties. When extending this method be sure to call |
||
216 | * parent::initialize() as some important stuff happens here. |
||
217 | * If extending this method to add properties then you should |
||
218 | * call parent::initialize() after adding any properties. |
||
219 | */ |
||
220 | protected function initialize() |
||
245 | |||
246 | /** |
||
247 | * Injects a DI container. |
||
248 | * |
||
249 | * @param \Pimple\Container $app |
||
250 | */ |
||
251 | public static function inject(Container $app) |
||
255 | |||
256 | /** |
||
257 | * Gets the DI container used for this model. |
||
258 | * |
||
259 | * @return Container |
||
260 | */ |
||
261 | public function getApp() |
||
265 | |||
266 | /** |
||
267 | * Sets the driver for all models. |
||
268 | * |
||
269 | * @param Model\Driver\DriverInterface $driver |
||
270 | */ |
||
271 | public static function setDriver(DriverInterface $driver) |
||
275 | |||
276 | /** |
||
277 | * Gets the driver for all models. |
||
278 | * |
||
279 | * @return Model\Driver\DriverInterface |
||
280 | */ |
||
281 | public static function getDriver() |
||
285 | |||
286 | /** |
||
287 | * Gets the name of the model without namespacing. |
||
288 | * |
||
289 | * @return string |
||
290 | */ |
||
291 | public static function modelName() |
||
300 | |||
301 | /** |
||
302 | * Gets the model ID. |
||
303 | * |
||
304 | * @return string|number|false ID |
||
305 | */ |
||
306 | public function id() |
||
310 | |||
311 | /** |
||
312 | * Gets a key-value map of the model ID. |
||
313 | * |
||
314 | * @return array ID map |
||
315 | */ |
||
316 | public function ids() |
||
334 | |||
335 | ///////////////////////////// |
||
336 | // Magic Methods |
||
337 | ///////////////////////////// |
||
338 | |||
339 | /** |
||
340 | * Converts the model into a string. |
||
341 | * |
||
342 | * @return string |
||
343 | */ |
||
344 | public function __toString() |
||
348 | |||
349 | /** |
||
350 | * Shortcut to a get() call for a given property. |
||
351 | * |
||
352 | * @param string $name |
||
353 | * |
||
354 | * @return mixed |
||
355 | */ |
||
356 | public function __get($name) |
||
362 | |||
363 | /** |
||
364 | * Sets an unsaved value. |
||
365 | * |
||
366 | * @param string $name |
||
367 | * @param mixed $value |
||
368 | */ |
||
369 | public function __set($name, $value) |
||
384 | |||
385 | /** |
||
386 | * Checks if an unsaved value or property exists by this name. |
||
387 | * |
||
388 | * @param string $name |
||
389 | * |
||
390 | * @return bool |
||
391 | */ |
||
392 | public function __isset($name) |
||
396 | |||
397 | /** |
||
398 | * Unsets an unsaved value. |
||
399 | * |
||
400 | * @param string $name |
||
401 | */ |
||
402 | public function __unset($name) |
||
413 | |||
414 | ///////////////////////////// |
||
415 | // ArrayAccess Interface |
||
416 | ///////////////////////////// |
||
417 | |||
418 | public function offsetExists($offset) |
||
422 | |||
423 | public function offsetGet($offset) |
||
427 | |||
428 | public function offsetSet($offset, $value) |
||
432 | |||
433 | public function offsetUnset($offset) |
||
437 | |||
438 | public static function __callStatic($name, $parameters) |
||
445 | |||
446 | ///////////////////////////// |
||
447 | // Property Definitions |
||
448 | ///////////////////////////// |
||
449 | |||
450 | /** |
||
451 | * Gets all the property definitions for the model. |
||
452 | * |
||
453 | * @return array key-value map of properties |
||
454 | */ |
||
455 | public static function getProperties() |
||
459 | |||
460 | /** |
||
461 | * Gets a property defition for the model. |
||
462 | * |
||
463 | * @param string $property property to lookup |
||
464 | * |
||
465 | * @return array|null property |
||
466 | */ |
||
467 | public static function getProperty($property) |
||
471 | |||
472 | /** |
||
473 | * Gets the names of the model ID properties. |
||
474 | * |
||
475 | * @return array |
||
476 | */ |
||
477 | public static function getIDProperties() |
||
481 | |||
482 | /** |
||
483 | * Checks if the model has a property. |
||
484 | * |
||
485 | * @param string $property property |
||
486 | * |
||
487 | * @return bool has property |
||
488 | */ |
||
489 | public static function hasProperty($property) |
||
493 | |||
494 | /** |
||
495 | * Gets the mutator method name for a given proeprty name. |
||
496 | * Looks for methods in the form of `setPropertyValue`. |
||
497 | * i.e. the mutator for `last_name` would be `setLastNameValue`. |
||
498 | * |
||
499 | * @param string $property property |
||
500 | * |
||
501 | * @return string|false method name if it exists |
||
502 | */ |
||
503 | View Code Duplication | public static function getMutator($property) |
|
521 | |||
522 | /** |
||
523 | * Gets the accessor method name for a given proeprty name. |
||
524 | * Looks for methods in the form of `getPropertyValue`. |
||
525 | * i.e. the accessor for `last_name` would be `getLastNameValue`. |
||
526 | * |
||
527 | * @param string $property property |
||
528 | * |
||
529 | * @return string|false method name if it exists |
||
530 | */ |
||
531 | View Code Duplication | public static function getAccessor($property) |
|
549 | |||
550 | ///////////////////////////// |
||
551 | // CRUD Operations |
||
552 | ///////////////////////////// |
||
553 | |||
554 | /** |
||
555 | * Saves the model. |
||
556 | * |
||
557 | * @return bool |
||
558 | */ |
||
559 | public function save() |
||
567 | |||
568 | /** |
||
569 | * Creates a new model. |
||
570 | * |
||
571 | * @param array $data optional key-value properties to set |
||
572 | * |
||
573 | * @return bool |
||
574 | * |
||
575 | * @throws BadMethodCallException when called on an existing model |
||
576 | */ |
||
577 | public function create(array $data = []) |
||
665 | |||
666 | /** |
||
667 | * Ignores unsaved values when fetching the next value. |
||
668 | * |
||
669 | * @return self |
||
670 | */ |
||
671 | public function ignoreUnsaved() |
||
677 | |||
678 | /** |
||
679 | * Fetches property values from the model. |
||
680 | * |
||
681 | * This method looks up values in this order: |
||
682 | * IDs, local cache, unsaved values, storage layer, defaults |
||
683 | * |
||
684 | * @param array $properties list of property names to fetch values of |
||
685 | * |
||
686 | * @return array |
||
687 | */ |
||
688 | public function get(array $properties) |
||
716 | |||
717 | /** |
||
718 | * Builds a key-value map of the requested properties given a set of values |
||
719 | * |
||
720 | * @param array $properties |
||
721 | * @param array $values |
||
722 | * |
||
723 | * @return array |
||
724 | * |
||
725 | * @throws InvalidArgumentException when a property was requested not present in the values |
||
726 | */ |
||
727 | private function buildGetResponse(array $properties, array $values) |
||
756 | |||
757 | /** |
||
758 | * Gets the ID for a newly created model. |
||
759 | * |
||
760 | * @return string |
||
761 | */ |
||
762 | protected function getNewID() |
||
779 | |||
780 | /** |
||
781 | * Converts the model to an array. |
||
782 | * |
||
783 | * @return array model array |
||
784 | */ |
||
785 | public function toArray() |
||
808 | |||
809 | /** |
||
810 | * Converts the model to an array. |
||
811 | * |
||
812 | * @param array $exclude properties to exclude |
||
813 | * @param array $include properties to include |
||
814 | * @param array $expand properties to expand |
||
815 | * |
||
816 | * @return array properties |
||
817 | */ |
||
818 | public function toArrayDeprecated(array $exclude = [], array $include = [], array $expand = []) |
||
865 | |||
866 | /** |
||
867 | * Expands any relational properties within a result. |
||
868 | * |
||
869 | * @param array $result |
||
870 | * @param array $namedExc |
||
871 | * @param array $namedInc |
||
872 | * @param array $namedExp |
||
873 | * |
||
874 | * @return array |
||
875 | */ |
||
876 | private function toArrayExpand(array $result, array $namedExc, array $namedInc, array $namedExp) |
||
900 | |||
901 | /** |
||
902 | * Updates the model. |
||
903 | * |
||
904 | * @param array $data optional key-value properties to set |
||
905 | * |
||
906 | * @return bool |
||
907 | * |
||
908 | * @throws BadMethodCallException when not called on an existing model |
||
909 | */ |
||
910 | public function set(array $data = []) |
||
973 | |||
974 | /** |
||
975 | * Delete the model. |
||
976 | * |
||
977 | * @return bool success |
||
978 | */ |
||
979 | public function delete() |
||
1006 | |||
1007 | ///////////////////////////// |
||
1008 | // Queries |
||
1009 | ///////////////////////////// |
||
1010 | |||
1011 | /** |
||
1012 | * Generates a new query instance. |
||
1013 | * |
||
1014 | * @return Model\Query |
||
1015 | */ |
||
1016 | public static function query() |
||
1025 | |||
1026 | /** |
||
1027 | * Gets the toal number of records matching an optional criteria. |
||
1028 | * |
||
1029 | * @param array $where criteria |
||
1030 | * |
||
1031 | * @return int total |
||
1032 | */ |
||
1033 | public static function totalRecords(array $where = []) |
||
1040 | |||
1041 | /** |
||
1042 | * Checks if the model exists in the database. |
||
1043 | * |
||
1044 | * @return bool |
||
1045 | */ |
||
1046 | public function exists() |
||
1050 | |||
1051 | /** |
||
1052 | * @deprecated alias for refresh() |
||
1053 | */ |
||
1054 | public function load() |
||
1058 | |||
1059 | /** |
||
1060 | * Loads the model from the storage layer. |
||
1061 | * |
||
1062 | * @return self |
||
1063 | */ |
||
1064 | public function refresh() |
||
1081 | |||
1082 | /** |
||
1083 | * Loads values into the model. |
||
1084 | * |
||
1085 | * @param array $values values |
||
1086 | * |
||
1087 | * @return self |
||
1088 | */ |
||
1089 | public function refreshWith(array $values) |
||
1095 | |||
1096 | /** |
||
1097 | * Clears the cache for this model. |
||
1098 | * |
||
1099 | * @return self |
||
1100 | */ |
||
1101 | public function clearCache() |
||
1109 | |||
1110 | ///////////////////////////// |
||
1111 | // Relationships |
||
1112 | ///////////////////////////// |
||
1113 | |||
1114 | /** |
||
1115 | * Gets the model object corresponding to a relation |
||
1116 | * WARNING no check is used to see if the model returned actually exists. |
||
1117 | * |
||
1118 | * @param string $propertyName property |
||
1119 | * |
||
1120 | * @return \Pulsar\Model model |
||
1121 | */ |
||
1122 | public function relation($propertyName) |
||
1134 | |||
1135 | /** |
||
1136 | * Creates the parent side of a One-To-One relationship. |
||
1137 | * |
||
1138 | * @param string $model foreign model class |
||
1139 | * @param string $foreignKey identifying key on foreign model |
||
1140 | * @param string $localKey identifying key on local model |
||
1141 | * |
||
1142 | * @return Relation |
||
1143 | */ |
||
1144 | View Code Duplication | public function hasOne($model, $foreignKey = '', $localKey = '') |
|
1159 | |||
1160 | /** |
||
1161 | * Creates the child side of a One-To-One or One-To-Many relationship. |
||
1162 | * |
||
1163 | * @param string $model foreign model class |
||
1164 | * @param string $foreignKey identifying key on foreign model |
||
1165 | * @param string $localKey identifying key on local model |
||
1166 | * |
||
1167 | * @return Relation |
||
1168 | */ |
||
1169 | View Code Duplication | public function belongsTo($model, $foreignKey = '', $localKey = '') |
|
1184 | |||
1185 | /** |
||
1186 | * Creates the parent side of a Many-To-One or Many-To-Many relationship. |
||
1187 | * |
||
1188 | * @param string $model foreign model class |
||
1189 | * @param string $foreignKey identifying key on foreign model |
||
1190 | * @param string $localKey identifying key on local model |
||
1191 | * |
||
1192 | * @return Relation |
||
1193 | */ |
||
1194 | View Code Duplication | public function hasMany($model, $foreignKey = '', $localKey = '') |
|
1209 | |||
1210 | /** |
||
1211 | * Creates the child side of a Many-To-Many relationship. |
||
1212 | * |
||
1213 | * @param string $model foreign model class |
||
1214 | * @param string $foreignKey identifying key on foreign model |
||
1215 | * @param string $localKey identifying key on local model |
||
1216 | * |
||
1217 | * @return Relation |
||
1218 | */ |
||
1219 | View Code Duplication | public function belongsToMany($model, $foreignKey = '', $localKey = '') |
|
1234 | |||
1235 | ///////////////////////////// |
||
1236 | // Events |
||
1237 | ///////////////////////////// |
||
1238 | |||
1239 | /** |
||
1240 | * Gets the event dispatcher. |
||
1241 | * |
||
1242 | * @return \Symfony\Component\EventDispatcher\EventDispatcher |
||
1243 | */ |
||
1244 | public static function getDispatcher($ignoreCache = false) |
||
1253 | |||
1254 | /** |
||
1255 | * Subscribes to a listener to an event. |
||
1256 | * |
||
1257 | * @param string $event event name |
||
1258 | * @param callable $listener |
||
1259 | * @param int $priority optional priority, higher #s get called first |
||
1260 | */ |
||
1261 | public static function listen($event, callable $listener, $priority = 0) |
||
1265 | |||
1266 | /** |
||
1267 | * Adds a listener to the model.creating event. |
||
1268 | * |
||
1269 | * @param callable $listener |
||
1270 | * @param int $priority |
||
1271 | */ |
||
1272 | public static function creating(callable $listener, $priority = 0) |
||
1276 | |||
1277 | /** |
||
1278 | * Adds a listener to the model.created event. |
||
1279 | * |
||
1280 | * @param callable $listener |
||
1281 | * @param int $priority |
||
1282 | */ |
||
1283 | public static function created(callable $listener, $priority = 0) |
||
1287 | |||
1288 | /** |
||
1289 | * Adds a listener to the model.updating event. |
||
1290 | * |
||
1291 | * @param callable $listener |
||
1292 | * @param int $priority |
||
1293 | */ |
||
1294 | public static function updating(callable $listener, $priority = 0) |
||
1298 | |||
1299 | /** |
||
1300 | * Adds a listener to the model.updated event. |
||
1301 | * |
||
1302 | * @param callable $listener |
||
1303 | * @param int $priority |
||
1304 | */ |
||
1305 | public static function updated(callable $listener, $priority = 0) |
||
1309 | |||
1310 | /** |
||
1311 | * Adds a listener to the model.deleting event. |
||
1312 | * |
||
1313 | * @param callable $listener |
||
1314 | * @param int $priority |
||
1315 | */ |
||
1316 | public static function deleting(callable $listener, $priority = 0) |
||
1320 | |||
1321 | /** |
||
1322 | * Adds a listener to the model.deleted event. |
||
1323 | * |
||
1324 | * @param callable $listener |
||
1325 | * @param int $priority |
||
1326 | */ |
||
1327 | public static function deleted(callable $listener, $priority = 0) |
||
1331 | |||
1332 | /** |
||
1333 | * Dispatches an event. |
||
1334 | * |
||
1335 | * @param string $eventName |
||
1336 | * |
||
1337 | * @return Model\ModelEvent |
||
1338 | */ |
||
1339 | protected function dispatch($eventName) |
||
1345 | |||
1346 | /** |
||
1347 | * Dispatches the model.creating event. |
||
1348 | * |
||
1349 | * @return bool |
||
1350 | */ |
||
1351 | View Code Duplication | private function beforeCreate() |
|
1365 | |||
1366 | /** |
||
1367 | * Dispatches the model.created event. |
||
1368 | * |
||
1369 | * @return bool |
||
1370 | */ |
||
1371 | View Code Duplication | private function afterCreate() |
|
1385 | |||
1386 | /** |
||
1387 | * Dispatches the model.updating event. |
||
1388 | * |
||
1389 | * @param array $data |
||
1390 | * |
||
1391 | * @return bool |
||
1392 | */ |
||
1393 | View Code Duplication | private function beforeUpdate(array &$data) |
|
1407 | |||
1408 | /** |
||
1409 | * Dispatches the model.updated event. |
||
1410 | * |
||
1411 | * @return bool |
||
1412 | */ |
||
1413 | View Code Duplication | private function afterUpdate() |
|
1427 | |||
1428 | /** |
||
1429 | * Dispatches the model.deleting event. |
||
1430 | * |
||
1431 | * @return bool |
||
1432 | */ |
||
1433 | View Code Duplication | private function beforeDelete() |
|
1447 | |||
1448 | /** |
||
1449 | * Dispatches the model.created event. |
||
1450 | * |
||
1451 | * @return bool |
||
1452 | */ |
||
1453 | View Code Duplication | private function afterDelete() |
|
1467 | |||
1468 | ///////////////////////////// |
||
1469 | // Validation |
||
1470 | ///////////////////////////// |
||
1471 | |||
1472 | /** |
||
1473 | * Validates and marshals a value to storage. |
||
1474 | * |
||
1475 | * @param array $property |
||
1476 | * @param string $propertyName |
||
1477 | * @param mixed $value |
||
1478 | * |
||
1479 | * @return bool |
||
1480 | */ |
||
1481 | private function filterAndValidate(array $property, $propertyName, &$value) |
||
1501 | |||
1502 | /** |
||
1503 | * Validates a value for a property. |
||
1504 | * |
||
1505 | * @param array $property |
||
1506 | * @param string $propertyName |
||
1507 | * @param mixed $value |
||
1508 | * |
||
1509 | * @return bool |
||
1510 | */ |
||
1511 | private function validate(array $property, $propertyName, $value) |
||
1531 | |||
1532 | /** |
||
1533 | * Checks if a value is unique for a property. |
||
1534 | * |
||
1535 | * @param array $property |
||
1536 | * @param string $propertyName |
||
1537 | * @param mixed $value |
||
1538 | * |
||
1539 | * @return bool |
||
1540 | */ |
||
1541 | private function checkUniqueness(array $property, $propertyName, $value) |
||
1555 | |||
1556 | /** |
||
1557 | * Gets the marshaled default value for a property (if set). |
||
1558 | * |
||
1559 | * @param string $property |
||
1560 | * |
||
1561 | * @return mixed |
||
1562 | */ |
||
1563 | private function getPropertyDefault(array $property) |
||
1567 | } |
||
1568 |
PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.
Let’s take a look at an example:
If we look at the
getEmail()
method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:On the hand, if we look at the
setEmail()
, this method _has_ side-effects. In the following case, we could not remove the method call: