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 |
||
| 12 | class Menu implements Item |
||
| 13 | { |
||
| 14 | use HtmlAttributes, ParentAttributes; |
||
| 15 | |||
| 16 | /** @var array */ |
||
| 17 | protected $items = []; |
||
| 18 | |||
| 19 | /** @var string */ |
||
| 20 | protected $prepend = ''; |
||
| 21 | |||
| 22 | /** @var string */ |
||
| 23 | protected $append = ''; |
||
| 24 | |||
| 25 | /** @var array */ |
||
| 26 | protected $filters = []; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * @param \Spatie\Menu\Item[] ...$items |
||
| 30 | */ |
||
| 31 | protected function __construct(Item ...$items) |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Create a new menu, optionally prefilled with items. |
||
| 38 | * |
||
| 39 | * @param array $items |
||
| 40 | * |
||
| 41 | * @return static |
||
| 42 | */ |
||
| 43 | public static function new(array $items = []) |
||
| 47 | |||
| 48 | /** |
||
| 49 | * Add an item to the menu. This also applies all registered filters on the item. If a filter |
||
| 50 | * returns false, the item won't be added. |
||
| 51 | * |
||
| 52 | * @param \Spatie\Menu\Item $item |
||
| 53 | * |
||
| 54 | * @return $this |
||
| 55 | */ |
||
| 56 | public function add(Item $item) |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Applies all the currently registered filters to an item. |
||
| 69 | * |
||
| 70 | * @param \Spatie\Menu\Item $item |
||
| 71 | * |
||
| 72 | * @return bool |
||
| 73 | */ |
||
| 74 | protected function applyFilters(Item $item) : bool |
||
| 90 | |||
| 91 | /** |
||
| 92 | * Map through all the items and return an array containing the result. If you typehint the |
||
| 93 | * item parameter in the callable, it wil only be applied to items of that type. |
||
| 94 | * |
||
| 95 | * @param callable $callable |
||
| 96 | * |
||
| 97 | * @return array |
||
| 98 | */ |
||
| 99 | public function map(callable $callable) : array |
||
| 113 | |||
| 114 | /** |
||
| 115 | * Iterate over all the items and apply a callback. If you typehint the |
||
| 116 | * item parameter in the callable, it wil only be applied to items of that type. |
||
| 117 | * |
||
| 118 | * @param callable $callable |
||
| 119 | * |
||
| 120 | * @return $this |
||
| 121 | */ |
||
| 122 | View Code Duplication | public function each(callable $callable) |
|
| 136 | |||
| 137 | /** |
||
| 138 | * Register a filter to the menu. When an item is added, all filters will be applied to the |
||
| 139 | * item. If a filter returns false, the item won't be added. If you typehint the item |
||
| 140 | * parameter in the callable, it wil only be applied to items of that type. |
||
| 141 | * |
||
| 142 | * @param callable $callable |
||
| 143 | * |
||
| 144 | * @return $this |
||
| 145 | */ |
||
| 146 | public function registerFilter(callable $callable) |
||
| 152 | |||
| 153 | /** |
||
| 154 | * Apply a callable to all existing items, and register it as a filter so it will get applied |
||
| 155 | * to all new items too. If you typehint the item parameter in the callable, it wil only be |
||
| 156 | * applied to items of that type. |
||
| 157 | * |
||
| 158 | * @param callable $callable |
||
| 159 | * |
||
| 160 | * @return $this |
||
| 161 | */ |
||
| 162 | public function applyToAll(callable $callable) |
||
| 169 | |||
| 170 | /** |
||
| 171 | * Determine the type of the first parameter of a callable. |
||
| 172 | * |
||
| 173 | * @param callable $callable |
||
| 174 | * |
||
| 175 | * @return string|null |
||
| 176 | */ |
||
| 177 | protected function determineFirstParameterType(callable $callable) |
||
| 178 | { |
||
| 179 | $reflection = new ReflectionFunction($callable); |
||
| 180 | |||
| 181 | $parameterTypes = array_map(function (ReflectionParameter $parameter) { |
||
| 182 | return $parameter->getClass() ? $parameter->getClass()->name : null; |
||
| 183 | }, $reflection->getParameters()); |
||
| 184 | |||
| 185 | return $parameterTypes[0] ?? null; |
||
| 186 | } |
||
| 187 | |||
| 188 | /** |
||
| 189 | * Prepend a string of html to the menu on render. |
||
| 190 | * |
||
| 191 | * @param string $prefix |
||
| 192 | * |
||
| 193 | * @return $this |
||
| 194 | */ |
||
| 195 | public function prefixLinks(string $prefix) |
||
| 201 | |||
| 202 | /** |
||
| 203 | * Prepend the menu with a string of html on render. |
||
| 204 | * |
||
| 205 | * @param string $prepend |
||
| 206 | * |
||
| 207 | * @return $this |
||
| 208 | */ |
||
| 209 | public function prepend(string $prepend) |
||
| 215 | |||
| 216 | /** |
||
| 217 | * Append a string of html to the menu on render. |
||
| 218 | * |
||
| 219 | * @param string $append |
||
| 220 | * |
||
| 221 | * @return $this |
||
| 222 | */ |
||
| 223 | public function append(string $append) |
||
| 229 | |||
| 230 | /** |
||
| 231 | * Determine whether the menu is active. |
||
| 232 | * |
||
| 233 | * @return bool |
||
| 234 | */ |
||
| 235 | public function isActive() : bool |
||
| 245 | |||
| 246 | /** |
||
| 247 | * Set multiple items in the menu as active based on a callable that filters through items. |
||
| 248 | * If you typehint the item parameter in the callable, it wil only be applied to items of |
||
| 249 | * that type. |
||
| 250 | * |
||
| 251 | * @param callable $callable |
||
| 252 | * |
||
| 253 | * @return $this |
||
| 254 | */ |
||
| 255 | View Code Duplication | public function setActive(callable $callable) |
|
| 271 | |||
| 272 | /** |
||
| 273 | * Render the menu in html. |
||
| 274 | * |
||
| 275 | * @return string |
||
| 276 | */ |
||
| 277 | public function render() : string |
||
| 293 | |||
| 294 | public function __toString() : string |
||
| 298 | } |
||
| 299 |
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.