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 WC_Customer 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 WC_Customer, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | class WC_Customer { |
||
35 | |||
36 | /** |
||
37 | * Stores customer data. |
||
38 | * |
||
39 | * @var array |
||
40 | */ |
||
41 | protected $_data = array(); |
||
42 | |||
43 | /** |
||
44 | * Stores bool when data is changed. |
||
45 | * |
||
46 | * @var bool |
||
47 | */ |
||
48 | private $_changed = false; |
||
49 | |||
50 | /** |
||
51 | * Constructor for the customer class loads the customer data. |
||
52 | * |
||
53 | */ |
||
54 | public function __construct() { |
||
65 | |||
66 | /** |
||
67 | * Save data function. |
||
68 | */ |
||
69 | public function save_data() { |
||
74 | |||
75 | /** |
||
76 | * __set function. |
||
77 | * |
||
78 | * @param mixed $property |
||
79 | * @return bool |
||
80 | */ |
||
81 | View Code Duplication | public function __isset( $property ) { |
|
90 | |||
91 | /** |
||
92 | * __get function. |
||
93 | * |
||
94 | * @param string $property |
||
95 | * @return string |
||
96 | */ |
||
97 | View Code Duplication | public function __get( $property ) { |
|
106 | |||
107 | /** |
||
108 | * __set function. |
||
109 | * |
||
110 | * @param mixed $property |
||
111 | * @param mixed $value |
||
112 | */ |
||
113 | public function __set( $property, $value ) { |
||
123 | |||
124 | /** |
||
125 | * Get default country for a customer. |
||
126 | * |
||
127 | * @return string |
||
128 | */ |
||
129 | public function get_default_country() { |
||
133 | |||
134 | /** |
||
135 | * Get default state for a customer. |
||
136 | * |
||
137 | * @return string |
||
138 | */ |
||
139 | public function get_default_state() { |
||
143 | |||
144 | /** |
||
145 | * Has calculated shipping? |
||
146 | * |
||
147 | * @return bool |
||
148 | */ |
||
149 | public function has_calculated_shipping() { |
||
152 | |||
153 | /** |
||
154 | * Set customer address to match shop base address. |
||
155 | */ |
||
156 | public function set_to_base() { |
||
162 | |||
163 | /** |
||
164 | * Set customer shipping address to base address. |
||
165 | */ |
||
166 | public function set_shipping_to_base() { |
||
172 | |||
173 | /** |
||
174 | * Is customer outside base country (for tax purposes)? |
||
175 | * |
||
176 | * @return bool |
||
177 | */ |
||
178 | public function is_customer_outside_base() { |
||
197 | |||
198 | /** |
||
199 | * Is the user a paying customer? |
||
200 | * |
||
201 | * @return bool |
||
202 | */ |
||
203 | public function is_paying_customer( $user_id ) { |
||
206 | |||
207 | /** |
||
208 | * Is customer VAT exempt? |
||
209 | * |
||
210 | * @return bool |
||
211 | */ |
||
212 | public function is_vat_exempt() { |
||
215 | |||
216 | /** |
||
217 | * Gets the state from the current session. |
||
218 | * |
||
219 | * @return string |
||
220 | */ |
||
221 | public function get_state() { |
||
224 | |||
225 | /** |
||
226 | * Gets the country from the current session. |
||
227 | * |
||
228 | * @return string |
||
229 | */ |
||
230 | public function get_country() { |
||
233 | |||
234 | /** |
||
235 | * Gets the postcode from the current session. |
||
236 | * |
||
237 | * @return string |
||
238 | */ |
||
239 | public function get_postcode() { |
||
242 | |||
243 | /** |
||
244 | * Get the city from the current session. |
||
245 | * |
||
246 | * @return string |
||
247 | */ |
||
248 | public function get_city() { |
||
251 | |||
252 | /** |
||
253 | * Gets the address from the current session. |
||
254 | * |
||
255 | * @return string |
||
256 | */ |
||
257 | public function get_address() { |
||
260 | |||
261 | /** |
||
262 | * Gets the address_2 from the current session. |
||
263 | * |
||
264 | * @return string |
||
265 | */ |
||
266 | public function get_address_2() { |
||
269 | |||
270 | /** |
||
271 | * Gets the state from the current session. |
||
272 | * |
||
273 | * @return string |
||
274 | */ |
||
275 | public function get_shipping_state() { |
||
278 | |||
279 | /** |
||
280 | * Gets the country from the current session. |
||
281 | * |
||
282 | * @return string |
||
283 | */ |
||
284 | public function get_shipping_country() { |
||
287 | |||
288 | /** |
||
289 | * Gets the postcode from the current session. |
||
290 | * |
||
291 | * @return string |
||
292 | */ |
||
293 | public function get_shipping_postcode() { |
||
296 | |||
297 | /** |
||
298 | * Gets the city from the current session. |
||
299 | * |
||
300 | * @return string |
||
301 | */ |
||
302 | public function get_shipping_city() { |
||
305 | |||
306 | /** |
||
307 | * Gets the address from the current session. |
||
308 | * |
||
309 | * @return string |
||
310 | */ |
||
311 | public function get_shipping_address() { |
||
314 | |||
315 | /** |
||
316 | * Gets the address_2 from the current session. |
||
317 | * |
||
318 | * @return string |
||
319 | */ |
||
320 | public function get_shipping_address_2() { |
||
323 | |||
324 | /** |
||
325 | * Get taxable address. |
||
326 | * |
||
327 | * @return array |
||
328 | */ |
||
329 | public function get_taxable_address() { |
||
330 | $tax_based_on = get_option( 'woocommerce_tax_based_on' ); |
||
331 | |||
332 | // Check shipping method at this point to see if we need special handling |
||
333 | if ( true === apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) && sizeof( array_intersect( WC()->session->get( 'chosen_shipping_methods', array() ), apply_filters( 'woocommerce_local_pickup_methods', array( 'legacy_local_pickup', 'local_pickup' ) ) ) ) > 0 ) { |
||
334 | $tax_based_on = 'base'; |
||
335 | } |
||
336 | |||
337 | if ( 'base' === $tax_based_on ) { |
||
338 | |||
339 | $country = WC()->countries->get_base_country(); |
||
340 | $state = WC()->countries->get_base_state(); |
||
341 | $postcode = WC()->countries->get_base_postcode(); |
||
342 | $city = WC()->countries->get_base_city(); |
||
343 | |||
344 | } elseif ( 'billing' === $tax_based_on ) { |
||
345 | $country = $this->get_country(); |
||
346 | $state = $this->get_state(); |
||
347 | $postcode = $this->get_postcode(); |
||
348 | $city = $this->get_city(); |
||
349 | |||
350 | } else { |
||
351 | $country = $this->get_shipping_country(); |
||
352 | $state = $this->get_shipping_state(); |
||
353 | $postcode = $this->get_shipping_postcode(); |
||
354 | $city = $this->get_shipping_city(); |
||
355 | } |
||
356 | |||
357 | return apply_filters( 'woocommerce_customer_taxable_address', array( $country, $state, $postcode, $city ) ); |
||
358 | } |
||
359 | |||
360 | /** |
||
361 | * Set default data for a customer. |
||
362 | */ |
||
363 | public function set_default_data( $get_user_profile_data = true ) { |
||
404 | |||
405 | /** |
||
406 | * Sets session data for the location. |
||
407 | * |
||
408 | * @param string $country |
||
409 | * @param string $state |
||
410 | * @param string $postcode (default: '') |
||
411 | * @param string $city (default: '') |
||
412 | */ |
||
413 | public function set_location( $country, $state, $postcode = '', $city = '' ) { |
||
419 | |||
420 | /** |
||
421 | * Sets session data for the country. |
||
422 | * |
||
423 | * @param mixed $country |
||
424 | */ |
||
425 | public function set_country( $country ) { |
||
428 | |||
429 | /** |
||
430 | * Sets session data for the state. |
||
431 | * |
||
432 | * @param mixed $state |
||
433 | */ |
||
434 | public function set_state( $state ) { |
||
437 | |||
438 | /** |
||
439 | * Sets session data for the postcode. |
||
440 | * |
||
441 | * @param mixed $postcode |
||
442 | */ |
||
443 | public function set_postcode( $postcode ) { |
||
446 | |||
447 | /** |
||
448 | * Sets session data for the city. |
||
449 | * |
||
450 | * @param mixed $city |
||
451 | */ |
||
452 | public function set_city( $city ) { |
||
455 | |||
456 | /** |
||
457 | * Sets session data for the address. |
||
458 | * |
||
459 | * @param mixed $address |
||
460 | */ |
||
461 | public function set_address( $address ) { |
||
464 | |||
465 | /** |
||
466 | * Sets session data for the $address. |
||
467 | * |
||
468 | * @param mixed $address |
||
469 | */ |
||
470 | public function set_address_2( $address ) { |
||
473 | |||
474 | /** |
||
475 | * Sets session data for the location. |
||
476 | * |
||
477 | * @param string $country |
||
478 | * @param string $state (default: '') |
||
479 | * @param string $postcode (default: '') |
||
480 | * @param string $city (default: '') |
||
481 | */ |
||
482 | public function set_shipping_location( $country, $state = '', $postcode = '', $city = '' ) { |
||
488 | |||
489 | /** |
||
490 | * Sets session data for the country. |
||
491 | * |
||
492 | * @param string $country |
||
493 | */ |
||
494 | public function set_shipping_country( $country ) { |
||
497 | |||
498 | /** |
||
499 | * Sets session data for the state. |
||
500 | * |
||
501 | * @param string $state |
||
502 | */ |
||
503 | public function set_shipping_state( $state ) { |
||
506 | |||
507 | /** |
||
508 | * Sets session data for the postcode. |
||
509 | * |
||
510 | * @param string $postcode |
||
511 | */ |
||
512 | public function set_shipping_postcode( $postcode ) { |
||
515 | |||
516 | /** |
||
517 | * Sets session data for the city. |
||
518 | * |
||
519 | * @param string $city |
||
520 | */ |
||
521 | public function set_shipping_city( $city ) { |
||
524 | |||
525 | /** |
||
526 | * Sets session data for the address. |
||
527 | * |
||
528 | * @param string $address |
||
529 | */ |
||
530 | public function set_shipping_address( $address ) { |
||
533 | |||
534 | /** |
||
535 | * Sets session data for the address_2. |
||
536 | * |
||
537 | * @param string $address |
||
538 | */ |
||
539 | public function set_shipping_address_2( $address ) { |
||
542 | |||
543 | /** |
||
544 | * Sets session data for the tax exemption. |
||
545 | * |
||
546 | * @param bool $is_vat_exempt |
||
547 | */ |
||
548 | public function set_is_vat_exempt( $is_vat_exempt ) { |
||
551 | |||
552 | /** |
||
553 | * Calculated shipping. |
||
554 | * |
||
555 | * @param boolean $calculated |
||
556 | */ |
||
557 | public function calculated_shipping( $calculated = true ) { |
||
560 | |||
561 | /** |
||
562 | * Gets a user's downloadable products if they are logged in. |
||
563 | * |
||
564 | * @return array Array of downloadable products |
||
565 | */ |
||
566 | public function get_downloadable_products() { |
||
575 | } |
||
576 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.