1<?php
2
3/*
4 * This file is part of the league/commonmark package.
5 *
6 * (c) Colin O'Dell <colinodell@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace League\CommonMark\Util;
13
14/**
15 * Array collection
16 *
17 * Provides a wrapper around a standard PHP array.
18 *
19 * @internal
20 *
21 * @phpstan-template TKey
22 * @phpstan-template TValue
23 * @phpstan-implements \IteratorAggregate<TKey, TValue>
24 * @phpstan-implements \ArrayAccess<TKey, TValue>
25 */
26class ArrayCollection implements \IteratorAggregate, \Countable, \ArrayAccess
27{
28    /**
29     * @var array<int|string, mixed>
30     * @phpstan-var array<TKey, TValue>
31     */
32    private $elements;
33
34    /**
35     * Constructor
36     *
37     * @param array<int|string, mixed> $elements
38     *
39     * @phpstan-param array<TKey, TValue> $elements
40     */
41    public function __construct(array $elements = [])
42    {
43        $this->elements = $elements;
44
45        if (self::class !== static::class) {
46            @\trigger_error('Extending the ArrayCollection class is deprecated in league/commonmark 1.6 and will not be allowed in 2.0', \E_USER_DEPRECATED);
47        }
48    }
49
50    /**
51     * @return mixed|false
52     *
53     * @phpstan-return TValue|false
54     */
55    public function first()
56    {
57        return \reset($this->elements);
58    }
59
60    /**
61     * @return mixed|false
62     *
63     * @phpstan-return TValue|false
64     */
65    public function last()
66    {
67        return \end($this->elements);
68    }
69
70    /**
71     * Retrieve an external iterator
72     *
73     * @return \ArrayIterator<int|string, mixed>
74     */
75    public function getIterator()
76    {
77        return new \ArrayIterator($this->elements);
78    }
79
80    /**
81     * @param mixed $element
82     *
83     * @return bool
84     *
85     * @phpstan-param TValue $element
86     *
87     * @deprecated
88     */
89    public function add($element): bool
90    {
91        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'add()', '$collection[] = $value'), E_USER_DEPRECATED);
92
93        $this->elements[] = $element;
94
95        return true;
96    }
97
98    /**
99     * @param int|string $key
100     * @param mixed      $value
101     *
102     * @return void
103     *
104     * @phpstan-param TKey   $key
105     * @phpstan-param TValue $value
106     *
107     * @deprecated
108     */
109    public function set($key, $value)
110    {
111        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'set()', '$collection[$key] = $value'), E_USER_DEPRECATED);
112
113        $this->offsetSet($key, $value);
114    }
115
116    /**
117     * @param int|string $key
118     *
119     * @return mixed
120     *
121     * @phpstan-param TKey $key
122     *
123     * @phpstan-return TValue|null
124     *
125     * @deprecated
126     */
127    public function get($key)
128    {
129        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'get()', '$collection[$key]'), E_USER_DEPRECATED);
130
131        return $this->offsetGet($key);
132    }
133
134    /**
135     * @param int|string $key
136     *
137     * @return mixed
138     *
139     * @phpstan-param TKey $key
140     *
141     * @phpstan-return TValue|null
142     *
143     * @deprecated
144     */
145    public function remove($key)
146    {
147        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'remove()', 'unset($collection[$key])'), E_USER_DEPRECATED);
148
149        if (!\array_key_exists($key, $this->elements)) {
150            return;
151        }
152
153        $removed = $this->elements[$key];
154        unset($this->elements[$key]);
155
156        return $removed;
157    }
158
159    /**
160     * @return bool
161     *
162     * @deprecated
163     */
164    public function isEmpty(): bool
165    {
166        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'isEmpty()', 'count($collection) === 0'), E_USER_DEPRECATED);
167
168        return empty($this->elements);
169    }
170
171    /**
172     * @param mixed $element
173     *
174     * @return bool
175     *
176     * @phpstan-param TValue $element
177     *
178     * @deprecated
179     */
180    public function contains($element): bool
181    {
182        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'contains()', 'in_array($value, $collection->toArray(), true)'), E_USER_DEPRECATED);
183
184        return \in_array($element, $this->elements, true);
185    }
186
187    /**
188     * @param mixed $element
189     *
190     * @return mixed|false
191     *
192     * @phpstan-param TValue $element
193     *
194     * @deprecated
195     */
196    public function indexOf($element)
197    {
198        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'indexOf()', 'array_search($value, $collection->toArray(), true)'), E_USER_DEPRECATED);
199
200        return \array_search($element, $this->elements, true);
201    }
202
203    /**
204     * @param int|string $key
205     *
206     * @return bool
207     *
208     * @phpstan-param TKey $key
209     *
210     * @deprecated
211     */
212    public function containsKey($key): bool
213    {
214        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4, use "%s" instead.', self::class, 'containsKey()', 'isset($collection[$key])'), E_USER_DEPRECATED);
215
216        return \array_key_exists($key, $this->elements);
217    }
218
219    /**
220     * Count elements of an object
221     *
222     * @return int The count as an integer.
223     */
224    public function count(): int
225    {
226        return \count($this->elements);
227    }
228
229    /**
230     * Whether an offset exists
231     *
232     * @param int|string $offset An offset to check for.
233     *
234     * @return bool true on success or false on failure.
235     *
236     * @phpstan-param TKey $offset
237     */
238    public function offsetExists($offset): bool
239    {
240        return \array_key_exists($offset, $this->elements);
241    }
242
243    /**
244     * Offset to retrieve
245     *
246     * @param int|string $offset
247     *
248     * @return mixed|null
249     *
250     * @phpstan-param TKey $offset
251     *
252     * @phpstan-return TValue|null
253     */
254    public function offsetGet($offset)
255    {
256        return $this->elements[$offset] ?? null;
257    }
258
259    /**
260     * Offset to set
261     *
262     * @param int|string|null $offset The offset to assign the value to.
263     * @param mixed           $value  The value to set.
264     *
265     * @return void
266     *
267     * @phpstan-param TKey|null $offset
268     * @phpstan-param TValue    $value
269     */
270    public function offsetSet($offset, $value)
271    {
272        if ($offset === null) {
273            $this->elements[] = $value;
274        } else {
275            $this->elements[$offset] = $value;
276        }
277    }
278
279    /**
280     * Offset to unset
281     *
282     * @param int|string $offset The offset to unset.
283     *
284     * @return void
285     *
286     * @phpstan-param TKey $offset
287     */
288    public function offsetUnset($offset)
289    {
290        if (!\array_key_exists($offset, $this->elements)) {
291            return;
292        }
293
294        unset($this->elements[$offset]);
295    }
296
297    /**
298     * Returns a subset of the array
299     *
300     * @param int      $offset
301     * @param int|null $length
302     *
303     * @return array<int|string, mixed>
304     *
305     * @phpstan-return array<TKey, TValue>
306     */
307    public function slice(int $offset, ?int $length = null): array
308    {
309        return \array_slice($this->elements, $offset, $length, true);
310    }
311
312    /**
313     * @return array<int|string, mixed>
314     *
315     * @phpstan-return array<TKey, TValue>
316     */
317    public function toArray(): array
318    {
319        return $this->elements;
320    }
321
322    /**
323     * @param array<int|string, mixed> $elements
324     *
325     * @return $this
326     *
327     * @phpstan-param array<TKey, TValue> $elements
328     *
329     * @deprecated
330     */
331    public function replaceWith(array $elements)
332    {
333        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4.', self::class, 'replaceWith()'), E_USER_DEPRECATED);
334
335        $this->elements = $elements;
336
337        return $this;
338    }
339
340    /**
341     * @deprecated
342     *
343     * @return void
344     */
345    public function removeGaps()
346    {
347        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4.', self::class, 'removeGaps()'), E_USER_DEPRECATED);
348
349        $this->elements = \array_filter($this->elements);
350    }
351}
352