Total Complexity | 50 |
Total Lines | 262 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Collection 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.
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 Collection, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable, \Serializable |
||
13 | { |
||
14 | /** @var string */ |
||
15 | private $type = null; |
||
16 | |||
17 | /** @var array */ |
||
18 | protected $container = []; |
||
19 | |||
20 | public function __construct(string $type, iterable ...$iterables) |
||
21 | { |
||
22 | $this->type = $type; |
||
23 | |||
24 | foreach ($iterables as $iterable) { |
||
25 | foreach ($iterable as $item) { |
||
26 | $this->add($item); |
||
27 | } |
||
28 | } |
||
29 | } |
||
30 | |||
31 | final public function type(): string |
||
34 | } |
||
35 | |||
36 | public function offsetExists($offset): bool |
||
39 | } |
||
40 | |||
41 | public function offsetGet($offset) |
||
42 | { |
||
43 | return $this->container[$offset]; |
||
44 | } |
||
45 | |||
46 | public function offsetUnset($offset): void |
||
47 | { |
||
48 | if ($this->offsetExists($offset)) { |
||
49 | unset($this->container[$offset]); |
||
50 | } |
||
51 | } |
||
52 | |||
53 | public function getIterator(): \ArrayIterator |
||
54 | { |
||
55 | return new \ArrayIterator($this->container); |
||
56 | } |
||
57 | |||
58 | public function append(): void |
||
59 | { |
||
60 | $values = func_get_args(); |
||
61 | |||
62 | foreach ($values as $item) { |
||
63 | $this->add($item); |
||
64 | } |
||
65 | } |
||
66 | |||
67 | public static function makeSafe(string $type, iterable ...$iterables) |
||
68 | { |
||
69 | $collection = new Collection($type); |
||
70 | |||
71 | foreach ($iterables as $iterable) { |
||
72 | foreach ($iterable as $key => $item) { |
||
73 | $collection->add($item, $key); |
||
74 | } |
||
75 | } |
||
76 | |||
77 | return $collection; |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * @param mixed $index |
||
82 | * @param mixed $value |
||
83 | * |
||
84 | * @throws InvalidElementException |
||
85 | */ |
||
86 | public function offsetSet($index, $value): void |
||
87 | { |
||
88 | $this->add($value, $index); |
||
89 | } |
||
90 | |||
91 | public function serialize() |
||
92 | { |
||
93 | return serialize($this->container); |
||
94 | } |
||
95 | |||
96 | public function unserialize($serialized, array $options = []) |
||
105 | } |
||
106 | |||
107 | public function join(iterable $iterable, bool $useKeys = false) |
||
108 | { |
||
109 | foreach ($iterable as $key => $item) { |
||
110 | $this->add($item, $useKeys ? $key : null); |
||
111 | } |
||
112 | } |
||
113 | |||
114 | public function jsonSerialize(): array |
||
115 | { |
||
116 | return $this->container; |
||
117 | } |
||
118 | |||
119 | public function isCompatible($element): bool |
||
120 | { |
||
121 | try { |
||
122 | if ($element instanceof self) { |
||
123 | return true; |
||
124 | } elseif (is_array($element)) { |
||
125 | foreach ($element as $item) { |
||
126 | try { |
||
127 | $this->validate($item); |
||
128 | } catch (InvalidElementException $ex) { |
||
129 | return false; |
||
130 | } |
||
131 | } |
||
132 | |||
133 | return true; |
||
134 | } |
||
135 | } catch (\InvalidArgumentException $exception) { |
||
136 | } finally { |
||
137 | return false; |
||
138 | } |
||
139 | } |
||
140 | |||
141 | public function first() |
||
142 | { |
||
143 | reset($this->container); |
||
144 | |||
145 | return $this->container[key($this->container)]; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * @param $item |
||
150 | * |
||
151 | * @throws InvalidElementException |
||
152 | */ |
||
153 | public function validate($item): void |
||
154 | { |
||
155 | $type = $this->type(); |
||
156 | |||
157 | if (!$item instanceof $type) { |
||
158 | throw new InvalidElementException($item, $type); |
||
159 | } |
||
160 | } |
||
161 | |||
162 | public function map(callable $callback): Collection |
||
163 | { |
||
164 | $type = get_class(call_user_func( |
||
165 | $callback, |
||
166 | $this->first() |
||
167 | )); |
||
168 | |||
169 | $elements = array_map($callback, $this->container, array_keys($this->container)); |
||
170 | |||
171 | return Collection::{$type}($elements); |
||
172 | } |
||
173 | |||
174 | public function walk(callable $callback): bool |
||
177 | } |
||
178 | |||
179 | public function chunk(int $size): Collection |
||
195 | } |
||
196 | |||
197 | public function column(string $property, callable $callback = null): Collection |
||
198 | { |
||
199 | $getterType = get_class($this->offsetGet(0)->$property); |
||
200 | |||
201 | if (!is_null($callback)) { |
||
202 | /** @var Collection $collection */ |
||
203 | $collection = Collection::{$getterType}(); |
||
204 | |||
205 | foreach ($this->jsonSerialize() as $item) { |
||
206 | $collection->append(call_user_func($callback, $item->$property)); |
||
207 | } |
||
208 | |||
209 | return $collection; |
||
210 | } else { |
||
211 | return Collection::{$getterType}(array_map( |
||
212 | function ($item) use ($property) { |
||
213 | return $item->$property; |
||
214 | }, |
||
215 | $this->jsonSerialize() |
||
216 | )); |
||
217 | } |
||
218 | } |
||
219 | |||
220 | public function pop() |
||
221 | { |
||
222 | return array_pop($this->container); |
||
223 | } |
||
224 | |||
225 | public function sum(callable $callback) |
||
226 | { |
||
227 | $sum = 0; |
||
228 | |||
229 | foreach ($this as $element) { |
||
230 | $sum += call_user_func($callback, $element); |
||
231 | } |
||
232 | |||
233 | return $sum; |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * @param string $name |
||
238 | * @param array $arguments |
||
239 | * |
||
240 | * @return Collection |
||
241 | */ |
||
242 | public static function __callStatic(string $name, array $arguments = []) |
||
243 | { |
||
244 | if (!empty($arguments) && is_array($arguments[0])) { |
||
245 | $arguments = $arguments[0]; |
||
246 | } |
||
247 | |||
248 | static::validateType($name); |
||
249 | |||
250 | reset($arguments); |
||
251 | |||
252 | if (current($arguments) instanceof Collection) { |
||
253 | return new static($name, ...$arguments); |
||
254 | } else { |
||
255 | return new static($name, $arguments); |
||
256 | } |
||
257 | } |
||
258 | |||
259 | public function count(): int |
||
260 | { |
||
261 | return count($this->container); |
||
262 | } |
||
263 | |||
264 | public function add($item, $index = null): void |
||
265 | { |
||
266 | $this->validate($item); |
||
267 | $this->container[$index ?? $this->count()] = $item; |
||
268 | } |
||
269 | |||
270 | protected static function validateType(string $type): void |
||
274 | } |
||
275 | } |
||
276 | } |
||
277 |
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.