A two array data structure implementation in PHP, version 2

In the previous version of two dimentional array data structure in PHP programming language, we developed a simple data structure to add support for simple two dimentional array in PHP. But as you may noticed, we tries not to use any advanced feature of PHP.
In this article we use a lovely feature in PHP to make our implementation neater. Before, we used to implement getter and setter methods with public methods Get and Set, but that is not much like normal array in many programming languages. We like to have the [] operator like in C.
Fortunately, there is a nice feature in PHP help us to add such a thing to our class. The interface ArrayAccess has four method declaratoin for this. First we need to change our class definition like this:

abstract class AbstractTwoDimArray implements \ArrayAccess

Then we implement the interface operations, the first one is offsetExists:

public offsetExists(mixed $offset): bool

This method used (as it's name shows) to check whether a row exists in the array or not. Our implemention for this method is like this:

public function offsetExists($row)
{
    if (gettype($row) != gettype(0))
        throw new Exception('The index must be of type ' . gettype(0));
    return ($row >=0 && $row _size[0]);
}

The second method is offsetGet that replaces our getter method.

public offsetGet(mixed $offset): mixed

Our getter implementation changes to:

public function offsetGet($row)
{
    if (gettype($row) != gettype(0))
        throw new Exception('The index must be of type ' . gettype(0));
    return $this->_rows[$row];
}

The other method is offsetSet that replaces our setter method.

public offsetSet(mixed $offset, mixed $value): void

Our setter implementation changes to:

public function offsetSet($row, $value)
{
    if (gettype($row) != gettype(0))
        throw new Exception('The index must be of type ' . gettype(0));
    if ($row = $this->_size[0])
        throw new Exception('The index must be in the range (0, ' . ($this->_size[0] -1) . ')');
    if (!($value instanceof OneDimArrayInterface)) // TODO: check more accurate constraint
        throw new Exception('The value must be of type OneDimArrayInterface');
    if ($value->Size() != $this->_size[1])
        throw new Exception('The value size does not match.');
    $this->_rows[$row] = $value;
}

And the last method is offsetUnset used to remove a row from the matrix and fired whenever PHP encounter a usage of unset() method.

public offsetSet(mixed $offset, mixed $value): void

Our implementation changes to:

public function offsetUnset($row)
{
    if (gettype($row) != gettype(0))
        throw new Exception('The index must be of type ' . gettype(0));
    $this->_rows[$row] = OneDimArrayFactory::Make($this->getValueType, $this->_size[1]);
}

Now, we could test our implementation like this:

$rows = 5;
$cols = 5;
$intMatrix = new IntTwoDimArray($rows, $cols);
for ($row = 0; $row Size()[0]; $row++) {
    for ($col = 0; $col Size()[1]; $col++)
        echo $intMatrix[$row][$col] . ' ';
    echo PHP_EOL;
}
echo PHP_EOL;
for ($row = 0; $row Size()[0]; $row++) {
    for ($col = 0; $col Size()[1]; $col++)
        $intMatrix[$row][$col] = $row + $col;
}
for ($row = 0; $row Size()[0]; $row++) {
    for ($col = 0; $col Size()[1]; $col++)
        echo $intMatrix[$row][$col] . ' ';
    echo PHP_EOL;
}
echo PHP_EOL;

Isn't this neater and more beautiful?

Code

<?php

namespace Techanic\CS\DS\Linear\Vector;

use Exception;

abstract class AbstractTwoDimArray implements \ArrayAccess
{
    /**
     *
     * @var array
     */
    private /*array*/ $_size = [0, 0];

    /**
     *
     * @var array
     */
    private /*array*/ $_rows = [];

    protected abstract function getValueType() : string;
    protected abstract function getDefaultValue();

    public function __construct(int $rows, int $cols)
    {
        if ($rows < 0)
            throw new Exception('rows must be positive number.');
        if ($cols < 0)
            throw new Exception('cols must be positive number.');
        $this->_size = [$rows, $cols];
        $defaultValue = $this->getDefaultValue();
        if (gettype($defaultValue) != $this->getValueType())
            throw new Exception('Return type of the getDefaultValue() does not match getValueType().');
        for ($row = 0; $row < $this->_size[0]; $row++)
        {
            $this->_rows[$row] = OneDimArrayFactory::Make($this->getValueType(), $this->_size[1]);
            for ($col = 0; $col < $this->_size[1]; $col++)
                ($this->_rows[$row])[$col] = $defaultValue;
        }
    }

    public function Size(): array
    {
        return $this->_size;
    }

    public function offsetSet($row, $value)
    {
        if (gettype($row) != gettype(0))
            throw new Exception('The index must be of type ' . gettype(0));
        if ($row < 0 || $row >= $this->_size[0])
            throw new Exception('The index must be in the range (0, ' . ($this->_size[0] -1) . ')');
        if (!($value instanceof OneDimArrayInterface)) // TODO: check more accurate constraint
            throw new Exception('The value must be of type OneDimArrayInterface');
        if ($value->Size() != $this->_size[1])
            throw new Exception('The value size does not match.');
        $this->_rows[$row] = $value;
    }

    public function offsetExists($row)
    {
        if (gettype($row) != gettype(0))
            throw new Exception('The index must be of type ' . gettype(0));
        return ($row >=0 && $row < $this->_size[0]);
    }

    public function offsetGet($row)
    {
        if (gettype($row) != gettype(0))
            throw new Exception('The index must be of type ' . gettype(0));
        return $this->_rows[$row];
    }

    public function offsetUnset($row)
    {
        if (gettype($row) != gettype(0))
            throw new Exception('The index must be of type ' . gettype(0));
        $this->_rows[$row] = OneDimArrayFactory::Make($this->getValueType, $this->_size[1]);
    }
}

class IntTwoDimArray extends AbstractTwoDimArray
{
    protected function getValueType() : string
    {
        return gettype(0);
    }

    protected function getDefaultValue()
    {
        return 0;
    }
}

$rows = 5;
$cols = 5;
$intMatrix = new IntTwoDimArray($rows, $cols);
for ($row = 0; $row < $intMatrix->Size()[0]; $row++) {
    for ($col = 0; $col < $intMatrix->Size()[1]; $col++)
        echo $intMatrix[$row][$col] . ' ';
    echo PHP_EOL;
}
echo PHP_EOL;
for ($row = 0; $row < $intMatrix->Size()[0]; $row++) {
    for ($col = 0; $col < $intMatrix->Size()[1]; $col++)
        $intMatrix[$row][$col] = $row + $col;
}
for ($row = 0; $row < $intMatrix->Size()[0]; $row++) {
    for ($col = 0; $col < $intMatrix->Size()[1]; $col++)
        echo $intMatrix[$row][$col] . ' ';
    echo PHP_EOL;
}
echo PHP_EOL;

two dimensional array data structure in PHP programming language

A two array data structure implementation in PHP, version 1

A two array data structure implementation in PHP, version 2

A two array data structure implementation in PHP, version 3