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 Path 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 Path, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class Path extends Shape implements ContainerInterface |
||
18 | { |
||
19 | use ElementTrait; |
||
20 | |||
21 | /** |
||
22 | * The path points positions |
||
23 | * |
||
24 | * @var array |
||
25 | */ |
||
26 | public $data; |
||
27 | |||
28 | /** |
||
29 | * Path constructor. |
||
30 | * |
||
31 | * @param ElementInterface $parent |
||
32 | * @param float $x |
||
33 | * @param float $y |
||
34 | * @param bool $absolute |
||
35 | */ |
||
36 | public function __construct(ElementInterface $parent, $x, $y, $absolute = true) |
||
42 | |||
43 | /** |
||
44 | * Start a new sub-path at the given (x,y) coordinate. M (uppercase) indicates that absolute coordinates will |
||
45 | * follow; m (lowercase) indicates that relative coordinates will follow. If a moveto is followed by multiple pairs |
||
46 | * of coordinates, the subsequent pairs are treated as implicit lineto commands. Hence, implicit lineto commands |
||
47 | * will be relative if the moveto is relative, and absolute if the moveto is absolute. If a relative moveto (m) |
||
48 | * appears as the first element of the path, then it is treated as a pair of absolute coordinates. In this case, |
||
49 | * subsequent pairs of coordinates are treated as relative even though the initial moveto is interpreted as an |
||
50 | * absolute moveto. |
||
51 | * |
||
52 | * @link https://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands |
||
53 | * |
||
54 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
55 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
56 | * @param bool $absolute |
||
57 | * |
||
58 | * @return $this |
||
59 | */ |
||
60 | public function moveTo($x, $y, $absolute = true) |
||
68 | |||
69 | /** |
||
70 | * @param string $type |
||
71 | */ |
||
72 | private function buildPath($type) |
||
90 | |||
91 | private function addData($type, array $params) |
||
95 | |||
96 | /** |
||
97 | * Draw a line from the current point to the given (x,y) coordinate which becomes the new current point. L |
||
98 | * (uppercase) indicates that absolute coordinates will follow; l (lowercase) indicates that relative coordinates |
||
99 | * will follow. A number of coordinates pairs may be specified to draw a polyline. At the end of the command, the |
||
100 | * new current point is set to the final set of coordinates provided. |
||
101 | * |
||
102 | * @link https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands |
||
103 | * |
||
104 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
105 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
106 | * @param bool $absolute |
||
107 | * |
||
108 | * @return $this |
||
109 | */ |
||
110 | public function lineTo($x, $y, $absolute = true) |
||
116 | |||
117 | /** |
||
118 | * Draws a horizontal line from the current point (cpx, cpy) to (x, cpy). H (uppercase) indicates that absolute |
||
119 | * coordinates will follow; h (lowercase) indicates that relative coordinates will follow. Multiple x values can be |
||
120 | * provided (although usually this doesn't make sense). At the end of the command, the new current point becomes |
||
121 | * (x, cpy) for the final value of x. |
||
122 | * |
||
123 | * @link https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands |
||
124 | * |
||
125 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
126 | * |
||
127 | * @param bool $absolute |
||
128 | * |
||
129 | * @return $this |
||
130 | */ |
||
131 | public function hLineTo($x, $absolute = true) |
||
137 | |||
138 | /** |
||
139 | * Draws a vertical line from the current point (cpx, cpy) to (cpx, y). V (uppercase) indicates that absolute |
||
140 | * coordinates will follow; v (lowercase) indicates that relative coordinates will follow. Multiple y values can be |
||
141 | * provided (although usually this doesn't make sense). At the end of the command, the new current point becomes |
||
142 | * (cpx, y) for the final value of y. |
||
143 | * |
||
144 | * @link https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands |
||
145 | * |
||
146 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
147 | * |
||
148 | * @param bool $absolute |
||
149 | * |
||
150 | * @return $this |
||
151 | */ |
||
152 | public function vLineTo($y, $absolute = true) |
||
158 | |||
159 | /** |
||
160 | * Draws a cubic Bézier curve from the current point to (x,y) using (x1,y1) as the control point at the beginning |
||
161 | * of the curve and (x2,y2) as the control point at the end of the curve. |
||
162 | * |
||
163 | * @link https://www.w3.org/TR/SVG11/paths.html#PathDataCurveCommands |
||
164 | * |
||
165 | * @param float $x1 The absolute (relative) X coordinate for the first control point. |
||
166 | * @param float $y1 The absolute (relative) Y coordinate for the first control point. |
||
167 | * @param float $x2 The absolute (relative) X coordinate for the second control point. |
||
168 | * @param float $y2 The absolute (relative) Y coordinate for the second control point. |
||
169 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
170 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
171 | * |
||
172 | * @param bool $absolute |
||
173 | * |
||
174 | * @return $this |
||
175 | */ |
||
176 | public function curveTo($x1, $y1, $x2, $y2, $x, $y, $absolute = true) |
||
182 | |||
183 | /** |
||
184 | * Draws a cubic Bézier curve from the current point to (x,y). The first control point is assumed to be the |
||
185 | * reflection of the second control point on the previous command relative to the current point. (If there is no |
||
186 | * previous command or if the previous command was not an C, c, S or s, assume the first control point is |
||
187 | * coincident with the current point.) (x2,y2) is the second control point (i.e., the control point at the end of |
||
188 | * the curve). S (uppercase) indicates that absolute coordinates will follow; s (lowercase) indicates that relative |
||
189 | * coordinates will follow. Multiple sets of coordinates may be specified to draw a polybézier. At the end of the |
||
190 | * command, the new current point becomes the final (x,y) coordinate pair used in the polybézier. |
||
191 | * |
||
192 | * @link https://www.w3.org/TR/SVG11/paths.html#PathDataCurveCommands |
||
193 | * |
||
194 | * @param float $x2 The absolute (relative) X coordinate for the second control point. |
||
195 | * @param float $y2 The absolute (relative) Y coordinate for the second control point. |
||
196 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
197 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
198 | * |
||
199 | * @param bool $absolute |
||
200 | * |
||
201 | * @return $this |
||
202 | */ |
||
203 | public function smoothCurveTo($x2, $y2, $x, $y, $absolute = true) |
||
209 | |||
210 | /** |
||
211 | * Draws a quadratic Bézier curve from the current point to (x,y) using (x1,y1) as the control point. Q (uppercase) |
||
212 | * indicates that absolute coordinates will follow; q (lowercase) indicates that relative coordinates will follow. |
||
213 | * Multiple sets of coordinates may be specified to draw a polybézier. At the end of the command, the new current |
||
214 | * point becomes the final (x,y) coordinate pair used in the polybézier. |
||
215 | * |
||
216 | * @link https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands |
||
217 | * |
||
218 | * @param float $x1 The absolute (relative) X coordinate for the first control point. |
||
219 | * @param float $y1 The absolute (relative) Y coordinate for the first control point. |
||
220 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
221 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
222 | * |
||
223 | * @param bool $absolute |
||
224 | * |
||
225 | * @return $this |
||
226 | */ |
||
227 | public function quadraticCurveTo($x1, $y1, $x, $y, $absolute = true) |
||
233 | |||
234 | /** |
||
235 | * Draws a quadratic Bézier curve from the current point to (x,y). The control point is assumed to be the |
||
236 | * reflection of the control point on the previous command relative to the current point. (If there is no previous |
||
237 | * command or if the previous command was not a Q, q, T or t, assume the control point is coincident with the |
||
238 | * current point.) T (uppercase) indicates that absolute coordinates will follow; t (lowercase) indicates that |
||
239 | * relative coordinates will follow. At the end of the command, the new current point becomes the final (x,y) |
||
240 | * coordinate pair used in the polybézier. |
||
241 | * |
||
242 | * @link https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands |
||
243 | * |
||
244 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
245 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
246 | * |
||
247 | * @param bool $absolute |
||
248 | * |
||
249 | * @return $this |
||
250 | */ |
||
251 | public function smoothQuadraticCurveTo($x, $y, $absolute = true) |
||
257 | |||
258 | /** |
||
259 | * Draws an elliptical arc from the current point to (x, y). The size and orientation of the ellipse are defined by |
||
260 | * two radii (rx, ry) and an x-axis-rotation, which indicates how the ellipse as a whole is rotated relative to the |
||
261 | * current coordinate system. The center (cx, cy) of the ellipse is calculated automatically to satisfy the |
||
262 | * constraints imposed by the other parameters. large-arc-flag and sweep-flag contribute to the automatic |
||
263 | * calculations and help determine how the arc is drawn. |
||
264 | * |
||
265 | * @link https://www.w3.org/TR/SVG11/paths.html#PathDataEllipticalArcCommands |
||
266 | * |
||
267 | * @param float $rx The x-axis radius for the ellipse (i.e., r1). |
||
268 | * @param float $ry The y-axis radius for the ellipse |
||
269 | * @param float $xRotation The rotation angle in degrees for the ellipse's x-axis relative to the x-axis of |
||
270 | * the user coordinate system. |
||
271 | * @param boolean $largeArcFlag The value of the large-arc-flag parameter. |
||
272 | * @param boolean $sweepFlag The value of the sweep-flag parameter. |
||
273 | * @param float $x The absolute (relative) X coordinate for the end point of this path segment. |
||
274 | * @param float $y The absolute (relative) Y coordinate for the end point of this path segment. |
||
275 | * @param bool $absolute |
||
276 | * |
||
277 | * @return $this |
||
278 | */ |
||
279 | public function arcTo($rx, $ry, $xRotation, $largeArcFlag, $sweepFlag, $x, $y, $absolute = true) |
||
285 | |||
286 | /** |
||
287 | * Close the current subpath by drawing a straight line from the current point to current subpath's initial point. |
||
288 | * Since the Z and z commands take no parameters, they have an identical effect. |
||
289 | * |
||
290 | * @link https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand |
||
291 | * |
||
292 | * @param bool $absolute |
||
293 | */ |
||
294 | public function closePath($absolute = true) |
||
298 | |||
299 | public function getName() |
||
303 | |||
304 | public function getBoundingBox() |
||
372 | |||
373 | protected function getCenterX() |
||
377 | |||
378 | protected function getCenterY() |
||
382 | |||
383 | /** |
||
384 | * @param $value |
||
385 | */ |
||
386 | private function addArrayToPath(array $value) |
||
393 | |||
394 | /** |
||
395 | * |
||
396 | */ |
||
397 | private function checkFirstModifier() |
||
403 | } |
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.