Skip to content

Instantly share code, notes, and snippets.

@Eyad-Bereh
Created July 31, 2020 14:22
Show Gist options
  • Save Eyad-Bereh/c0c9d8cdef43d5b55ac72e4841944bea to your computer and use it in GitHub Desktop.
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/
<?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