Created
July 31, 2020 14:22
-
-
Save Eyad-Bereh/c0c9d8cdef43d5b55ac72e4841944bea to your computer and use it in GitHub Desktop.
An example demonstrating how to implement SeekableIterator, ArrayAccess, and Countable interfaces in PHP - Exclusive for the group: https://www.facebook.com/groups/HTML.CSSandJavaScript/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php //php 7.2.24 | |
declare(strict_types = 1); // Necessary for type hinting to work | |
class CustomArray implements SeekableIterator, ArrayAccess, Countable { | |
private $arr; /** @var array contains the underlying array */ | |
private $position; /** @var int contains the current position of the iterator */ | |
private $size; /** @var int contains the current size of the array */ | |
/** | |
* *********************************************************************************** | |
* *********************************************************************************** | |
* Just adding the basic functionality | |
* *********************************************************************************** | |
* *********************************************************************************** | |
*/ | |
/** | |
* Initialize class fields | |
* | |
* @return void | |
* | |
*/ | |
public function __construct() { | |
$this->arr = []; | |
$this->position = 0; | |
$this->size = 0; | |
} | |
/** | |
* Append a new element | |
* | |
* This method will add a new element to the end of the array and increase size by 1 | |
* | |
* @param any $element the element to be added | |
* | |
* @return void | |
* | |
*/ | |
public function add($element) : void { | |
$this->arr[] = $element; | |
$this->size++; | |
} | |
/** | |
* Get an element by index | |
* | |
* This method tries to get an element using the supplied index | |
* | |
* @param int $index the index to be passed | |
* | |
* @throws OutOfBoundsException if the given index was outside the array bounds | |
* | |
* @return any | |
* | |
*/ | |
public function get(int $index) { | |
if ($index < 0 || $index >= $this->size) { | |
throw new OutOfBoundsException("CustomArray::get(index = $index) failed because index = $index > size = $this->size"); | |
} | |
return $this->arr[$index]; | |
} | |
/** | |
* Change the value of an existent element | |
* | |
* This method tries to change the value of the element at supplied $index to $value | |
* | |
* @param int $index the index of the element to be changed | |
* @param any $value the new value of the element | |
* | |
* @throws OutOfBoundsException if the given index was outside the array bounds | |
* | |
* @return void | |
* | |
*/ | |
public function set(int $index, $value) : void { | |
if ($index < 0 || $index >= $this->size) { | |
throw new OutOfBoundsException("CustomArray::set(index = $index, value = $value) failed because index = $index > size = $this->size"); | |
} | |
$this->arr[$index] = $value; | |
} | |
/** | |
* Removes an element from the array | |
* | |
* This method tries to remove the element at the specified $index from the array | |
* | |
* @param int $index the index of the element to be removed | |
* | |
* @throws OutOfBoundsException if the given index was outside the array bounds | |
* | |
* @return any the removed element | |
* | |
*/ | |
public function remove(int $index) { | |
if ($index < 0 || $index >= $this->size) { | |
throw new OutOfBoundsException("CustomArray::remove(index = $index) failed because index = $index > size = $this->size"); | |
} | |
$this->size--; | |
return array_splice($this->arr, $index, 1)[0]; | |
} | |
/** | |
* Get the index of a value | |
* | |
* This method search the array and returns the index of the first occurrence of where $value exist | |
* taking into consideration the strict comparison rules which is controlled by $strict parameter | |
* | |
* @param any $value the value to search for | |
* @param bool $strict whether a strict comparison should be used or not | |
* | |
* @return int the index of the found element or -1 if none is found | |
* | |
*/ | |
public function indexOf($value, bool $strict = FALSE) : int { | |
if (!in_array($value, $this->arr, $strict)) { | |
return -1; | |
} | |
return array_search($value, $this->arr, $strict); | |
} | |
/** | |
* Get array size | |
* | |
* @return int the size of the array | |
* | |
*/ | |
public function size() : int { | |
return $this->size; | |
} | |
/** | |
* *********************************************************************************** | |
* *********************************************************************************** | |
* Implementing the SeekableIterator interface | |
* *********************************************************************************** | |
* *********************************************************************************** | |
*/ | |
/** | |
* Seek the iterator | |
* | |
* This method tries to seek the position of the internal pointer to the specified $position | |
* | |
* @param int $position the new position of the iterator | |
* | |
* @throws UnexpectedValueException if the given position isn't an integer | |
* @throws OutOfBoundsException if the given position was outside the array bounds | |
* | |
* @return void | |
* | |
*/ | |
public function seek($position) : void { | |
if (!is_int($position)) { | |
$type = gettype($position); | |
throw new UnexpectedValueException("CustomArray::seek(position = $position) failed because position is expected to be an integer but $type was given"); | |
} | |
else if ($position < 0 || $position >= $this->size) { | |
throw new OutOfBoundsException("CustomArray::seek(position = $position) failed because position = $position > size = $this->size"); | |
} | |
$this->position = $position; | |
} | |
/** | |
* Get the current element | |
* | |
* This method gets the value corresponding to the current location of the iterator | |
* | |
* @return any the value where the iterator at | |
* | |
*/ | |
public function current() { | |
return $this->arr[$this->position]; | |
} | |
/** | |
* Advance iterator | |
* | |
* This method advances the iterator by 1 | |
* | |
* @return void | |
* | |
*/ | |
public function next() : void { | |
++$this->position; | |
} | |
/** | |
* Get the current position | |
* | |
* This method gets the current position of the iterator | |
* | |
* @return int the current position of the iterator | |
* | |
*/ | |
public function key() : int { | |
return $this->position; | |
} | |
/** | |
* Validates the current iterator | |
* | |
* This method validates whether the iterator is currently in a valid location by checking whether | |
* it has exceeded the length of the array or not | |
* | |
* @return bool the validity of the iterator | |
* | |
*/ | |
public function valid() : bool { | |
return ($this->position < $this->size); | |
} | |
/** | |
* Rewinds the iterator | |
* | |
* This method rewinds the iterator to the first element by setting $position = 0 | |
* | |
* @return void | |
* | |
*/ | |
public function rewind() : void { | |
$this->position = 0; | |
} | |
/** | |
* *********************************************************************************** | |
* *********************************************************************************** | |
* Implementing the ArrayAccess interface | |
* *********************************************************************************** | |
* *********************************************************************************** | |
*/ | |
/** | |
* Validates the existence of the offset | |
* | |
* This method tries to validate the existence of the supplied $offset, if $offset is out of | |
* array bounds then FALSE is returned, else TRUE | |
* | |
* @param int $offset the offset to validate | |
* | |
* @throws UnexpectedValueException if the given offset isn't an integer | |
* | |
* @return bool the validity of the offset | |
* | |
*/ | |
public function offsetExists($offset) : bool { | |
if (!is_int($offset)) { | |
$type = gettype($offset); | |
throw new UnexpectedValueException("CustomArray::offsetExists(offset = $offset) failed because offset is expected to be an integer but $type was given"); | |
} | |
else if ($offset < 0 || $offset >= $this->size) { | |
return FALSE; | |
} | |
return TRUE; | |
} | |
/** | |
* Get value of the specified $offset | |
* | |
* This method tries to get the value of the corresponding $offset | |
* | |
* @param int $offset the offset of the element | |
* | |
* @throws UnexpectedValueException if the given offset isn't an integer | |
* @throws OutOfBoundsException if the given offset was outside array bounds | |
* | |
* @return any the value that corresponds to the given $offset | |
* | |
*/ | |
public function offsetGet($offset) { | |
if (!is_int($offset)) { | |
$type = gettype($offset); | |
throw new UnexpectedValueException("CustomArray::offsetGet(offset = $offset) failed because offset is expected to be an integer but $type was given"); | |
} | |
else if ($offset < 0 || $offset >= $this->size) { | |
throw new OutOfBoundsException("CustomArray::offsetGet(offset = $offset) failed because offset = $offset > size = $this->size"); | |
} | |
return $this->arr[$offset]; | |
} | |
/** | |
* Change the value at the specified offset | |
* | |
* This method tries to change the value at the specified $offset to another value supplied by $value | |
* | |
* @param int $offset the offset of the element to be changed | |
* @param any $value the new value to assign at that offset | |
* | |
* @throws UnexpectedValueException if the given offset isn't an integer | |
* @throws OutOfBoundsException if the given offset was outside array bounds | |
* | |
* @return void | |
* | |
*/ | |
public function offsetSet($offset, $value) : void { | |
if (!is_int($offset)) { | |
$type = gettype($offset); | |
throw new UnexpectedValueException("CustomArray::offsetSet(offset = $offset, value = $value) failed because offset is expected to be an integer but $type was given"); | |
} | |
else if ($offset < 0 || $offset >= $this->size) { | |
throw new OutOfBoundsException("CustomArray::offsetSet(offset = $offset, value = $value) failed because offset = $offset > size = $this->size"); | |
} | |
$this->arr[$offset] = $value; | |
} | |
/** | |
* Unsets the value at the specified offset | |
* | |
* This method tries to unset the value at the specified $offset | |
* | |
* @param int $offset the offset of the element to be unset | |
* | |
* @return void | |
* | |
*/ | |
public function offsetUnset($offset) : void { | |
if (!is_int($offset)) { | |
$type = gettype($offset); | |
throw new UnexpectedValueException("CustomArray::offsetUnset(offset = $offset) failed because offset is expected to be an integer but $type was given"); | |
} | |
else if ($offset < 0 || $offset >= $this->size) { | |
throw new OutOfBoundsException("CustomArray::offsetSet(offset = $offset) failed because offset = $offset > size = $this->size"); | |
} | |
unset($this->arr[$offset]); | |
array_splice($this->arr, $offset, 0); | |
$this->size--; | |
} | |
/** | |
* *********************************************************************************** | |
* *********************************************************************************** | |
* Implementing the Countable interface | |
* *********************************************************************************** | |
* *********************************************************************************** | |
*/ | |
/** | |
* Get the total number of elements | |
* | |
* This method returns the total number of elements inside the underlying array | |
* | |
* @return int the total length of the array | |
* | |
*/ | |
public function count() : int { | |
return $this->size; | |
} | |
} | |
$arr = new CustomArray(); | |
$arr->add(2); | |
$arr->add(4); | |
$arr->add(7); | |
$arr->add(11); | |
$arr->add(13); | |
$arr->add(16); | |
$arr->add(19); | |
// Let us test how SeekableIterator interface works | |
foreach ($arr as $index => $value) { | |
echo "arr[$index] => $value\n"; | |
} | |
echo "--------------------------------------------------\n"; | |
// Now let's test how ArrayAccess interface works | |
$arr[0] = 3; // Change the value of the first element | |
echo "arr[0] = $arr[0]\n"; // Print it | |
unset($arr[0]); // Delete it | |
echo "--------------------------------------------------\n"; | |
// Now let's test how Countable interface works | |
echo "Array length = " . count($arr) . "\n"; | |
echo "--------------------------------------------------\n"; | |
// Now let's put them all together | |
for ($i = 0; $i < count($arr); $i++) { | |
$arr[$i] = $arr[$i] * 2; // Double the elements | |
} | |
for ($i = 0; $i < count($arr); $i++) { | |
echo "arr[$i] = " . $arr[$i] . "\n"; | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment