• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

voku / Arrayy / 24327721426

13 Apr 2026 05:45AM UTC coverage: 89.336% (-0.02%) from 89.36%
24327721426

Pull #155

github

web-flow
Merge cbaf5472b into b6ddb08f8
Pull Request #155: Tighten PHPStan ignore handling and replace broad suppressions with targeted fixes

12 of 15 new or added lines in 4 files covered. (80.0%)

87 existing lines in 2 files now uncovered.

2488 of 2785 relevant lines covered (89.34%)

100.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.87
/src/Collection/AbstractCollection.php
1
<?php
2

3
/** @noinspection ClassOverridesFieldOfSuperClassInspection */
4
/** @noinspection PropertyInitializationFlawsInspection */
5
/** @noinspection PhpSuperClassIncompatibleWithInterfaceInspection */
6

7
declare(strict_types=1);
8

9
namespace Arrayy\Collection;
10

11
use Arrayy\Arrayy;
12
use Arrayy\ArrayyIterator;
13
use Arrayy\Type\TypeInterface;
14
use Arrayy\TypeCheck\TypeCheckArray;
15
use Arrayy\TypeCheck\TypeCheckInterface;
16
use Arrayy\TypeCheck\TypeCheckSimple;
17

18
/**
19
 * This class provides a full implementation of `CollectionInterface`, to
20
 * minimize the effort required to implement this interface.
21
 *
22
 * INFO: this collection thingy is inspired by https://github.com/ramsey/collection/
23
 *
24
 * @template   TKey of array-key
25
 * @template   T
26
 * @extends    Arrayy<TKey,T>
27
 * @implements CollectionInterface<TKey,T>
28
 */
29
abstract class AbstractCollection extends Arrayy implements CollectionInterface
30
{
31
    /**
32
     * @var bool
33
     */
34
    protected $checkPropertyTypes = true;
35

36
    /**
37
     * @var bool
38
     */
39
    protected $checkPropertiesMismatch = false;
40

41
    /**
42
     * @var bool
43
     */
44
    protected $checkForMissingPropertiesInConstructor = true;
45

46
    /**
47
     * Constructs a collection object of the specified type, optionally with the
48
     * specified data.
49
     *
50
     * @param mixed  $data
51
     *                                             <p>
52
     *                                             The initial items to store in the collection.
53
     *                                             </p>
54
     * @param string $iteratorClass                optional <p>
55
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
56
     *                                             need this option.
57
     *                                             </p>
58
     * @param bool   $checkPropertiesInConstructor optional <p>
59
     *                                             You need to extend the "Arrayy"-class and you need to set
60
     *                                             the $checkPropertiesMismatchInConstructor class property
61
     *                                             to
62
     *                                             true, otherwise this option didn't not work anyway.
63
     *                                             </p>
64
     *
65
     * @phpstan-param array<TKey,T>|\Arrayy\Arrayy<TKey,T>|\Closure():array<TKey,T>|mixed $data
66
     * @phpstan-param class-string<\Arrayy\ArrayyIterator<TKey,T>> $iteratorClass
67
     */
68
    public function __construct(
69
        $data = [],
70
        string $iteratorClass = ArrayyIterator::class,
71
        bool $checkPropertiesInConstructor = true
72
    ) {
73
        $type = $this->getType();
336✔
74

75
        $type = self::convertIntoTypeCheckArray($type);
336✔
76

77
        $this->properties = $type;
336✔
78

79
        // cast into array, if needed
80
        if (
81
            !\is_array($data)
336✔
82
            &&
83
            !($data instanceof \Traversable)
336✔
84
            &&
85
            !($data instanceof \Closure)
336✔
86
        ) {
87
            $data = [$data];
6✔
88
        }
89

90
        parent::__construct(
336✔
91
            $data,
336✔
92
            $iteratorClass,
336✔
93
            $checkPropertiesInConstructor
336✔
94
        );
336✔
95
    }
96

97
    /**
98
     * Append a (key) + value to the current array.
99
     *
100
     * @param mixed $value
101
     * @param mixed $key
102
     *
103
     * @return $this
104
     *               <p>(Mutable) Return this CollectionInterface object, with the appended values.</p>
105
     *
106
     * @phpstan-param T|static $value
107
     * @phpstan-param TKey|null $key
108
     * @phpstan-return static<TKey,T>
109
     */
110
    public function append($value, $key = null): Arrayy
111
    {
112
        if (
113
            $value instanceof self
21✔
114
            &&
115
            !$value instanceof TypeInterface
21✔
116
        ) {
117
            foreach ($value as $valueTmp) {
3✔
118
                parent::append($valueTmp, $key);
3✔
119
            }
120

121
            return $this;
3✔
122
        }
123

124
        /* @phpstan-ignore-next-line | special? */
125
        $return = parent::append($value, $key);
18✔
126
        $this->array = $return->array;
15✔
127
        $this->generator = null;
15✔
128

129
        return $this;
15✔
130
    }
131

132
    /**
133
     * Assigns a value to the specified offset + check the type.
134
     *
135
     * @param int|string|null $offset
136
     * @param mixed           $value
137
     *
138
     * @return void
139
     *
140
     * @phpstan-param T $value
141
     */
142
    #[\ReturnTypeWillChange]
143
    public function offsetSet($offset, $value)
144
    {
145
        if (
146
            $value instanceof self
12✔
147
            &&
148
            !$value instanceof TypeInterface
12✔
149
        ) {
150
            foreach ($value as $valueTmp) {
×
151
                parent::offsetSet($offset, $valueTmp);
×
152
            }
153

154
            return;
×
155
        }
156

157
        parent::offsetSet($offset, $value);
12✔
158
    }
159

160
    /**
161
     * Prepend a (key) + value to the current array.
162
     *
163
     * @param mixed $value
164
     * @param mixed $key
165
     *
166
     * @return $this
167
     *               <p>(Mutable) Return this CollectionInterface object, with the prepended value.</p>
168
     *
169
     * @phpstan-param T|static $value
170
     * @phpstan-param TKey|null $key
171
     * @phpstan-return static<TKey,T>
172
     */
173
    public function prepend($value, $key = null): Arrayy
174
    {
175
        if (
176
            $value instanceof self
9✔
177
            &&
178
            !$value instanceof TypeInterface
9✔
179
        ) {
180
            foreach ($value as $valueTmp) {
×
181
                parent::prepend($valueTmp, $key);
×
182
            }
183

184
            return $this;
×
185
        }
186

187
        /* @phpstan-ignore-next-line | special? */
188
        $return = parent::prepend($value, $key);
9✔
189
        $this->array = $return->array;
3✔
190
        $this->generator = null;
3✔
191

192
        return $this;
3✔
193
    }
194

195
    /**
196
     * {@inheritdoc}
197
     */
198
    public function column(string $keyOrPropertyOrMethod): array
199
    {
200
        // init
201
        $temp = [];
3✔
202

203
        foreach ($this->getGenerator() as $item) {
3✔
204
            $temp[] = $this->extractValue($item, $keyOrPropertyOrMethod);
3✔
205
        }
206

207
        return $temp;
3✔
208
    }
209

210
    /**
211
     * @return array
212
     *
213
     * @phpstan-return array<T>
214
     */
215
    public function getCollection(): array
216
    {
217
        return $this->getArray();
21✔
218
    }
219

220
    /**
221
     * The type (FQCN) associated with this collection.
222
     *
223
     * @return string|string[]|TypeCheckArray|TypeCheckInterface[]
224
     *
225
     * @phpstan-return string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|TypeCheckInterface[]
226
     */
227
    abstract public function getType();
228

229
    /**
230
     * Merge current items and items of given collections into a new one.
231
     *
232
     * @param CollectionInterface|static ...$collections
233
     *                                                   <p>The collections to merge.</p>
234
     *
235
     *@throws \InvalidArgumentException if any of the given collections are not of the same type
236
     *
237
     * @return $this
238
     *
239
     * @phpstan-param CollectionInterface<TKey,T> ...$collections
240
     * @phpstan-return static<TKey,T>
241
     */
242
    public function merge(CollectionInterface ...$collections): self
243
    {
244
        foreach ($collections as $collection) {
3✔
245
            foreach ($collection as $item) {
3✔
246
                $this->append($item);
3✔
247
            }
248
        }
249

250
        return $this;
3✔
251
    }
252

253
    /**
254
     * Creates an CollectionInterface object.
255
     *
256
     * @param mixed  $data
257
     * @param string $iteratorClass
258
     * @param bool   $checkPropertiesInConstructor
259
     *
260
     * @return static
261
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
262
     *
263
     * @template TKeyCreate as TKey
264
     * @template TCreate as T
265
     * @phpstan-param array<TKeyCreate,TCreate> $data
266
     * @phpstan-param  class-string<\Arrayy\ArrayyIterator<TKeyCreate,TCreate>> $iteratorClass
267
     * @phpstan-return static<TKeyCreate,TCreate>
268
     *
269
     * @psalm-mutation-free
270
     */
271
    public static function create(
272
        $data = [],
273
        string $iteratorClass = ArrayyIterator::class,
274
        bool $checkPropertiesInConstructor = true
275
    ) {
276
        // @phpstan-ignore-next-line
277
        return new static(
84✔
278
            $data,
84✔
279
            $iteratorClass,
84✔
280
            $checkPropertiesInConstructor
84✔
281
        );
84✔
282
    }
283

284
    /**
285
     * @param string $json
286
     *
287
     * @return static
288
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
289
     *
290
     * @phpstan-return static<int,T>
291
     *
292
     * @psalm-mutation-free
293
     */
294
    public static function createFromJsonMapper(string $json)
295
    {
296
        // init
297
        $return = static::create();
24✔
298

299
        $jsonObject = \json_decode($json, false);
24✔
300

301
        $mapper = new \Arrayy\Mapper\Json();
24✔
302
        $mapper->undefinedPropertyHandler = static function ($object, $key, $jsonValue) use ($return) {
24✔
303
            if ($return->checkForMissingPropertiesInConstructor) {
3✔
304
                throw new \TypeError('Property mismatch - input: ' . \print_r(['key' => $key, 'jsonValue' => $jsonValue], true) . ' for object: ' . \get_class($object));
3✔
305
            }
306
        };
24✔
307

308
        $type = $return->getType();
24✔
309

310
        if (
311
            \is_string($type)
24✔
312
            &&
313
            \class_exists($type)
24✔
314
        ) {
315
            if (\is_array($jsonObject)) {
12✔
316
                foreach ($jsonObject as $jsonObjectSingle) {
6✔
317
                    $collectionData = $mapper->map($jsonObjectSingle, $type);
6✔
318
                    $return->add($collectionData);
6✔
319
                }
320
            } else {
321
                $collectionData = $mapper->map($jsonObject, $type);
6✔
322
                $return->add($collectionData);
9✔
323
            }
324
        } else {
325
            foreach ($jsonObject as $key => $jsonValue) {
12✔
326
                $return->add($jsonValue, $key);
12✔
327
            }
328
        }
329

330
        /** @phpstan-var static<int,T> */
331
        return $return;
15✔
332
    }
333

334
    /**
335
     * Internal mechanic of set method.
336
     *
337
     * @param int|string|null $key
338
     * @param mixed           $value
339
     * @param bool            $checkProperties
340
     *
341
     * @return bool
342
     */
343
    protected function internalSet(
344
        $key,
345
        &$value,
346
        bool $checkProperties = true
347
    ): bool {
348
        if (
349
            $value instanceof self
315✔
350
            &&
351
            !$value instanceof TypeInterface
315✔
352
        ) {
353
            foreach ($value as $valueTmp) {
×
354
                parent::internalSet(
×
355
                    $key,
×
356
                    $valueTmp,
×
357
                    $checkProperties
×
UNCOV
358
                );
×
359
            }
360

UNCOV
361
            return true;
×
362
        }
363

364
        return parent::internalSet(
315✔
365
            $key,
315✔
366
            $value,
315✔
367
            $checkProperties
315✔
368
        );
315✔
369
    }
370

371
    /**
372
     * @param string|string[]|TypeCheckArray|TypeCheckInterface[]|null $type
373
     *
374
     * @return TypeCheckArray
375
     *
376
     * @phpstan-param null|string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|array<array-key,TypeCheckInterface>|mixed $type
377
     * @phpstan-return TypeCheckArray<array-key,TypeCheckInterface>
378
     */
379
    protected static function convertIntoTypeCheckArray($type): TypeCheckArray
380
    {
381
        $is_array = false;
336✔
382
        if (
383
            \is_scalar($type)
336✔
384
            ||
385
            $is_array = \is_array($type)
336✔
386
        ) {
387
            $type = TypeCheckArray::create(
318✔
388
                [
318✔
389
                    Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckSimple($is_array ? $type : (string) $type),
318✔
390
                ]
318✔
391
            );
318✔
392
        }
393

394
        return $type;
336✔
395
    }
396
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc