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    #[\ReturnTypeWillChange]
76    public function getIterator()
77    {
78        return new \ArrayIterator($this->elements);
79    }
80
81    /**
82     * @param mixed $element
83     *
84     * @return bool
85     *
86     * @phpstan-param TValue $element
87     *
88     * @deprecated
89     */
90    public function add($element): bool
91    {
92        @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);
93
94        $this->elements[] = $element;
95
96        return true;
97    }
98
99    /**
100     * @param int|string $key
101     * @param mixed      $value
102     *
103     * @return void
104     *
105     * @phpstan-param TKey   $key
106     * @phpstan-param TValue $value
107     *
108     * @deprecated
109     */
110    public function set($key, $value)
111    {
112        @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);
113
114        $this->offsetSet($key, $value);
115    }
116
117    /**
118     * @param int|string $key
119     *
120     * @return mixed
121     *
122     * @phpstan-param TKey $key
123     *
124     * @phpstan-return TValue|null
125     *
126     * @deprecated
127     */
128    public function get($key)
129    {
130        @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);
131
132        return $this->offsetGet($key);
133    }
134
135    /**
136     * @param int|string $key
137     *
138     * @return mixed
139     *
140     * @phpstan-param TKey $key
141     *
142     * @phpstan-return TValue|null
143     *
144     * @deprecated
145     */
146    public function remove($key)
147    {
148        @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);
149
150        if (!\array_key_exists($key, $this->elements)) {
151            return;
152        }
153
154        $removed = $this->elements[$key];
155        unset($this->elements[$key]);
156
157        return $removed;
158    }
159
160    /**
161     * @return bool
162     *
163     * @deprecated
164     */
165    public function isEmpty(): bool
166    {
167        @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);
168
169        return empty($this->elements);
170    }
171
172    /**
173     * @param mixed $element
174     *
175     * @return bool
176     *
177     * @phpstan-param TValue $element
178     *
179     * @deprecated
180     */
181    public function contains($element): bool
182    {
183        @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);
184
185        return \in_array($element, $this->elements, true);
186    }
187
188    /**
189     * @param mixed $element
190     *
191     * @return mixed|false
192     *
193     * @phpstan-param TValue $element
194     *
195     * @deprecated
196     */
197    public function indexOf($element)
198    {
199        @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);
200
201        return \array_search($element, $this->elements, true);
202    }
203
204    /**
205     * @param int|string $key
206     *
207     * @return bool
208     *
209     * @phpstan-param TKey $key
210     *
211     * @deprecated
212     */
213    public function containsKey($key): bool
214    {
215        @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);
216
217        return \array_key_exists($key, $this->elements);
218    }
219
220    /**
221     * Count elements of an object
222     *
223     * @return int The count as an integer.
224     */
225    public function count(): int
226    {
227        return \count($this->elements);
228    }
229
230    /**
231     * Whether an offset exists
232     *
233     * @param int|string $offset An offset to check for.
234     *
235     * @return bool true on success or false on failure.
236     *
237     * @phpstan-param TKey $offset
238     */
239    public function offsetExists($offset): bool
240    {
241        return \array_key_exists($offset, $this->elements);
242    }
243
244    /**
245     * Offset to retrieve
246     *
247     * @param int|string $offset
248     *
249     * @return mixed|null
250     *
251     * @phpstan-param TKey $offset
252     *
253     * @phpstan-return TValue|null
254     */
255    #[\ReturnTypeWillChange]
256    public function offsetGet($offset)
257    {
258        return $this->elements[$offset] ?? null;
259    }
260
261    /**
262     * Offset to set
263     *
264     * @param int|string|null $offset The offset to assign the value to.
265     * @param mixed           $value  The value to set.
266     *
267     * @return void
268     *
269     * @phpstan-param TKey|null $offset
270     * @phpstan-param TValue    $value
271     */
272    #[\ReturnTypeWillChange]
273    public function offsetSet($offset, $value)
274    {
275        if ($offset === null) {
276            $this->elements[] = $value;
277        } else {
278            $this->elements[$offset] = $value;
279        }
280    }
281
282    /**
283     * Offset to unset
284     *
285     * @param int|string $offset The offset to unset.
286     *
287     * @return void
288     *
289     * @phpstan-param TKey $offset
290     */
291    #[\ReturnTypeWillChange]
292    public function offsetUnset($offset)
293    {
294        if (!\array_key_exists($offset, $this->elements)) {
295            return;
296        }
297
298        unset($this->elements[$offset]);
299    }
300
301    /**
302     * Returns a subset of the array
303     *
304     * @param int      $offset
305     * @param int|null $length
306     *
307     * @return array<int|string, mixed>
308     *
309     * @phpstan-return array<TKey, TValue>
310     */
311    public function slice(int $offset, ?int $length = null): array
312    {
313        return \array_slice($this->elements, $offset, $length, true);
314    }
315
316    /**
317     * @return array<int|string, mixed>
318     *
319     * @phpstan-return array<TKey, TValue>
320     */
321    public function toArray(): array
322    {
323        return $this->elements;
324    }
325
326    /**
327     * @param array<int|string, mixed> $elements
328     *
329     * @return $this
330     *
331     * @phpstan-param array<TKey, TValue> $elements
332     *
333     * @deprecated
334     */
335    public function replaceWith(array $elements)
336    {
337        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4.', self::class, 'replaceWith()'), E_USER_DEPRECATED);
338
339        $this->elements = $elements;
340
341        return $this;
342    }
343
344    /**
345     * @deprecated
346     *
347     * @return void
348     */
349    public function removeGaps()
350    {
351        @trigger_error(sprintf('The "%s:%s" method is deprecated since league/commonmark 1.4.', self::class, 'removeGaps()'), E_USER_DEPRECATED);
352
353        $this->elements = \array_filter($this->elements);
354    }
355}
356