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 |
||
32 | class GeometryProxy |
||
33 | { |
||
34 | /** |
||
35 | * Cache the area to not have to loop through the calculations each time that it is needed. |
||
36 | * |
||
37 | * @var float |
||
38 | */ |
||
39 | protected $cached_area = null; |
||
40 | |||
41 | /** |
||
42 | * The geometry to proxy. |
||
43 | * |
||
44 | * @var Geometry |
||
45 | */ |
||
46 | protected $geometry; |
||
47 | |||
48 | /** |
||
49 | * Cached array version of the geometry. |
||
50 | * |
||
51 | * @var array | null |
||
52 | */ |
||
53 | protected $geometry_array = null; |
||
54 | |||
55 | /** |
||
56 | * Instance of TypeMapper. |
||
57 | * |
||
58 | * @var TypeMapper |
||
59 | */ |
||
60 | protected $mapper; |
||
61 | |||
62 | /** |
||
63 | * Polygon constructor. |
||
64 | * |
||
65 | * @param mixed $geometry |
||
66 | * @param TypeMapper $mapper |
||
67 | */ |
||
68 | 27 | public function __construct($geometry, TypeMapper $mapper) |
|
69 | { |
||
70 | 27 | $this->geometry = $geometry; |
|
71 | 27 | $this->mapper = $mapper; |
|
72 | 27 | } |
|
73 | |||
74 | /** |
||
75 | * Magic method to allow methods that are not specifically defined. |
||
76 | * |
||
77 | * This is where we look to see if the class that we are proxing has the method that is being called, and if it |
||
78 | * does, then pass the call to the class under proxy. If a method is defined in our class, then it gets called |
||
79 | * first, so you can "extend" the classes by defining methods that overwrite the "parent" there. |
||
80 | * |
||
81 | * @param string $name |
||
82 | * @param array $arguments |
||
83 | * |
||
84 | * @return mixed |
||
85 | * @throws InvalidArgumentException |
||
86 | */ |
||
87 | 10 | public function __call($name, $arguments) |
|
88 | { |
||
89 | // Sugar to make to<Format>() work |
||
90 | 10 | View Code Duplication | if (preg_match("/^to([A-Z][A-z]*)/u", $name, $parts) && 0 === count($arguments)) { |
|
|||
91 | 7 | return $this->geometry->out($this->mapper->map($parts[1])); |
|
92 | } |
||
93 | |||
94 | // Call the method on the class being proxied |
||
95 | 3 | if (method_exists($this->geometry, $name)) { |
|
96 | 2 | return call_user_func_array( |
|
97 | 2 | [$this->geometry, $name], array_map([$this, 'exposeRawIfAvailable'], $arguments) |
|
98 | ); |
||
99 | } |
||
100 | |||
101 | 1 | throw new RuntimeException(sprintf("Call to undefined method %s::%s().", __CLASS__, $name)); |
|
102 | } |
||
103 | |||
104 | /** |
||
105 | * @param string $name |
||
106 | * |
||
107 | * @return mixed |
||
108 | */ |
||
109 | 4 | public function __get($name) |
|
110 | { |
||
111 | // Properties on the geometry |
||
112 | 4 | if (isset($this->toArray()[$name])) { |
|
113 | 3 | return $this->toArray()[$name]; |
|
114 | } |
||
115 | |||
116 | // Shortcut to the getters |
||
117 | 3 | if (method_exists($this, 'get' . Str::studly($name))) { |
|
118 | 2 | return $this->{'get' . Str::studly($name)}(); |
|
119 | } |
||
120 | |||
121 | 1 | throw new RuntimeException(sprintf("Undefined property: %s", $name)); |
|
122 | } |
||
123 | |||
124 | /** |
||
125 | * If using the object as a string, just return the json. |
||
126 | * |
||
127 | * @return string |
||
128 | */ |
||
129 | 1 | public function __toString() |
|
130 | { |
||
131 | 1 | return $this->toJson(); |
|
132 | } |
||
133 | |||
134 | /** |
||
135 | * Figure out what index to use in the ringArea calculation |
||
136 | * |
||
137 | * @param int $index |
||
138 | * @param int $length |
||
139 | * |
||
140 | * @return array |
||
141 | */ |
||
142 | 1 | private function determineCoordinateIndices($index, $length) |
|
143 | { |
||
144 | // i = N-2 |
||
145 | 1 | View Code Duplication | if ($index === ($length - 2)) { |
146 | 1 | return [$length - 2, $length - 1, 0]; |
|
147 | } |
||
148 | |||
149 | // i = N-1 |
||
150 | 1 | View Code Duplication | if ($index === ($length - 1)) { |
151 | 1 | return [$length - 1, 0, 1]; |
|
152 | } |
||
153 | |||
154 | // i = 0 to N-3 |
||
155 | 1 | return [$index, $index + 1, $index + 2]; |
|
156 | } |
||
157 | |||
158 | /** |
||
159 | * If the object passed in has a getRawGeometry, call it |
||
160 | * |
||
161 | * @param $argument |
||
162 | * |
||
163 | * @return mixed |
||
164 | */ |
||
165 | 1 | protected function exposeRawIfAvailable($argument) |
|
171 | |||
172 | /** |
||
173 | * Calculate the acres |
||
174 | * |
||
175 | * @return float |
||
176 | */ |
||
177 | 2 | public function getAcres() |
|
178 | { |
||
179 | 2 | return $this->square_meters * 0.000247105381; |
|
180 | } |
||
181 | |||
182 | /** |
||
183 | * Expose the underlying Geometry object |
||
184 | * |
||
185 | * @return Geometry |
||
186 | */ |
||
187 | 2 | public function getRawGeometry() |
|
191 | |||
192 | /** |
||
193 | * Calculate the square meters |
||
194 | * |
||
195 | * @return float |
||
196 | */ |
||
197 | 2 | public function getSquareMeters() |
|
211 | |||
212 | /** |
||
213 | * Convert degrees to radians |
||
214 | * |
||
215 | * I know that there is a built in function, but I read that it was very slow & to use this. |
||
216 | * |
||
217 | * @param $degrees |
||
218 | * |
||
219 | * @return float |
||
220 | */ |
||
221 | 1 | private function radians($degrees) |
|
225 | |||
226 | /** |
||
227 | * Estimate the area of a ring |
||
228 | * |
||
229 | * Calculate the approximate area of the polygon were it projected onto |
||
230 | * the earth. Note that this area will be positive if ring is oriented |
||
231 | * clockwise, otherwise it will be negative. |
||
232 | * |
||
233 | * Reference: |
||
234 | * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for |
||
235 | * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion |
||
236 | * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 |
||
237 | * |
||
238 | * @return float |
||
239 | * @see https://github.com/mapbox/geojson-area/blob/master/index.js#L55 |
||
240 | */ |
||
241 | 2 | public function ringArea($coordinates) |
|
263 | |||
264 | /** |
||
265 | * Build array of the object |
||
266 | * |
||
267 | * Cache the result, so that we don't decode it on every call. |
||
268 | * |
||
269 | * @return array |
||
270 | */ |
||
271 | 5 | public function toArray() |
|
279 | } |
||
280 |
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.