diff --git a/src/Collections/Collection.php b/src/Collections/Collection.php index c4e7d57..14ff3a4 100644 --- a/src/Collections/Collection.php +++ b/src/Collections/Collection.php @@ -88,6 +88,27 @@ class Collection extends ImmutableCollection implements ICollection { return $this; } + /** + * @inheritDoc + */ + public function removeFirst () { + $firstKey = $this->firstKey(); + $firstValue = $this->get($firstKey); + + $this->remove($firstKey); + return $firstValue; + } + /** + * @inheritDoc + */ + public function removeLast () { + $lastKey = $this->lastKey(); + $lastValue = $this->get($lastKey); + + $this->remove($lastKey); + return $lastValue; + } + /** * @inheritDoc */ @@ -105,6 +126,8 @@ class Collection extends ImmutableCollection implements ICollection { * @inheritDoc */ public function sliceSelf (int $offset, ?int $length = null) { + $this->_checkOffset($offset); + $this->elements = array_slice($this->elements, $offset, $length, true); return $this; } diff --git a/src/Collections/ICollection.php b/src/Collections/ICollection.php index ac5dd94..993d44e 100644 --- a/src/Collections/ICollection.php +++ b/src/Collections/ICollection.php @@ -4,6 +4,7 @@ namespace jrosset\Collections; use Closure; use Exception; +use OutOfBoundsException; /** * Interface for a collection @@ -108,6 +109,23 @@ interface ICollection extends IImmutableCollection { */ public function removeValue ($value, bool $strict = false); + /** + * Get and remove the first element + * + * @return TValue The value + * + * @throws OutOfBoundsException If the collection is empty + */ + public function removeFirst (); + /** + * Get and remove the last element + * + * @return TValue The value + * + * @throws OutOfBoundsException If the collection is empty + */ + public function removeLast (); + /** * Keep only a slice of the collection * @@ -118,6 +136,8 @@ interface ICollection extends IImmutableCollection { * * @return $this * + * @throws OutOfBoundsException If the offset is not valid + * * @noinspection PhpMissingReturnTypeInspection */ public function sliceSelf (int $offset, ?int $length = null); diff --git a/src/Collections/IImmutableCollection.php b/src/Collections/IImmutableCollection.php index c2eb358..3088898 100644 --- a/src/Collections/IImmutableCollection.php +++ b/src/Collections/IImmutableCollection.php @@ -7,6 +7,7 @@ use Closure; use Countable; use IteratorAggregate; use JsonSerializable; +use OutOfBoundsException; use Serializable; use Throwable; @@ -54,6 +55,17 @@ interface IImmutableCollection extends IteratorAggregate, JsonSerializable, Seri * @return TValue|null The value */ public function get ($key); + /** + * Get the value at an offset + * + * @param int $offset The offset + * + * @return TValue The value + * + * @throws OutOfBoundsException If the offset is not valid + */ + public function getFromOffset (int $offset); + /** * Get the first key of a value or null if not found * @@ -63,6 +75,50 @@ interface IImmutableCollection extends IteratorAggregate, JsonSerializable, Seri * @return TKey|null */ public function key ($value, bool $strict = false); + /** + * Get the key at an offset + * + * @param int $offset The offset + * + * @return TKey The key + * + * @throws OutOfBoundsException If the offset is not valid + */ + public function keyFromOffset (int $offset); + + /** + * Get the value of the first element + * + * @return TValue The value + * + * @throws OutOfBoundsException If the collection is empty + */ + public function first (); + /** + * Get the key of the first element + * + * @return TKey The key + * + * @throws OutOfBoundsException If the collection is empty + */ + public function firstKey (); + + /** + * Get the value of the last element + * + * @return TValue The value + * + * @throws OutOfBoundsException If the collection is empty + */ + public function last (); + /** + * Get the key of the last element + * + * @return TKey The key + * + * @throws OutOfBoundsException If the collection is empty + */ + public function lastKey (); /** * Extract a slice of the collection @@ -74,6 +130,8 @@ interface IImmutableCollection extends IteratorAggregate, JsonSerializable, Seri * * @return static The result collection * + * @throws OutOfBoundsException If the offset is not valid + * * @noinspection PhpMissingReturnTypeInspection */ public function slice (int $offset, ?int $length = null); diff --git a/src/Collections/ImmutableCollection.php b/src/Collections/ImmutableCollection.php index d881f32..a70430e 100644 --- a/src/Collections/ImmutableCollection.php +++ b/src/Collections/ImmutableCollection.php @@ -5,6 +5,7 @@ namespace jrosset\Collections; use ArrayIterator; use Closure; use InvalidArgumentException; +use OutOfBoundsException; use Traversable; /** @@ -132,6 +133,20 @@ class ImmutableCollection implements IImmutableCollection { protected function _normalizeKey ($key) { return $key; } + /** + * Vérifie un offset (≥ 0, < {@see static::count()}) + * + * @param int $offset L'offset à vérifier + * + * @return void + * + * @throws OutOfBoundsException Si l'offset est invalide + */ + protected function _checkOffset (int $offset): void { + if ($offset < 0 || $offset >= $this->count()) { + throw new OutOfBoundsException('The offset must be between 0 and ' . ($this->count() - 1)); + } + } /** * @inheritDoc @@ -227,6 +242,14 @@ class ImmutableCollection implements IImmutableCollection { public function get ($key) { return $this->elements[$this->_normalizeKey($key)] ?? null; } + /** + * @inheritDoc + */ + public function getFromOffset (int $offset) { + $this->_checkOffset($offset); + return array_values($this->elements)[$offset]; + } + /** * @inheritDoc */ @@ -238,11 +261,46 @@ class ImmutableCollection implements IImmutableCollection { } return null; } + /** + * @inheritDoc + */ + public function keyFromOffset (int $offset) { + $this->_checkOffset($offset); + return array_keys($this->elements)[$offset]; + } + + /** + * @inheritDoc + */ + public function first () { + return $this->getFromOffset(0); + } + /** + * @inheritDoc + */ + public function firstKey () { + return $this->keyFromOffset(0); + } + + /** + * @inheritDoc + */ + public function last () { + return $this->getFromOffset($this->count() - 1); + } + /** + * @inheritDoc + */ + public function lastKey () { + return $this->keyFromOffset($this->count() - 1); + } /** * @inheritDoc */ public function slice (int $offset, ?int $length = null) { + $this->_checkOffset($offset); + $output = new static(); $currentIndex = 0;