Extract interface and use trait for implementation

2.x
Julien Rosset 3 years ago
parent d56366fbfb
commit 096d4bc3ed

@ -2,60 +2,16 @@
namespace jrosset\ArrayClasses;
use OutOfRangeException;
/**
* An array
*/
class ArrayClass extends ImmutableArrayClass {
/**
* Set or replace a cell value
*
* @param mixed $offset The cell offset
* @param mixed $value The cell new value
*
* @return $this
*/
public function set ($offset, $value): self {
$this->array[$offset] = $value;
return $this;
}
/**
* Remove a cell
*
* @param mixed $offset The cell offset
* @param bool|null $throwsForNonExistentElement If set, temporarily override {@see ImmutableArrayClass::$throwsForNonExistentElement}
*
* @return $this
*/
public function del ($offset, ?bool $throwsForNonExistentElement = null): self {
if ($throwsForNonExistentElement ?? $this->throwsForNonExistentElement() && !$this->has($offset)) {
throw new OutOfRangeException();
}
unset($this->array[$offset]);
return $this;
}
class ArrayClass extends ImmutableArrayClass implements IArrayClass {
use TInternalArray;
/**
* Create an immutable copy
*
* @return ImmutableArrayClass The immutable copy
*/
public function toImmutableArrayClass (): ImmutableArrayClass {
return new ImmutableArrayClass($this);
}
/**
* @inheritDoc
*/
public function offsetSet ($offset, $value): void {
$this->set($offset, $value);
}
/**
* @inheritDoc
*/
public function offsetUnset ($offset): void {
$this->del($offset);
public function toImmutable (): IImmutableArrayClass {
return new ImmutableArrayClass($this->array, $this->throwsForNonExistentElement());
}
}

@ -0,0 +1,30 @@
<?php
namespace jrosset\ArrayClasses;
interface IArrayClass extends IImmutableArrayClass {
/**
* Create or replace a cell
*
* @param mixed $cellName The cell name/offset
* @param mixed $cellValue The cell new value
*
* @return $this
*/
public function set ($cellName, $cellValue): self;
/**
* Remove a cell
*
* @param mixed $cellName The cell name/offset
*
* @return $this
*/
public function del ($cellName): self;
/**
* Create an immutable copy
*
* @return IImmutableArrayClass The immutable copy
*/
public function toImmutable (): IImmutableArrayClass;
}

@ -0,0 +1,35 @@
<?php
namespace jrosset\ArrayClasses;
use ArrayAccess;
use Countable;
use IteratorAggregate;
use JsonSerializable;
use Serializable;
interface IImmutableArrayClass extends IteratorAggregate, JsonSerializable, Serializable, Countable, ArrayAccess, IArrayCast {
/**
* Check if a cell exists
*
* @param mixed $cellName The cell name/offset
*
* @return bool Is the cell exists ?
*/
public function has ($cellName): bool;
/**
* Get the value of a cell
*
* @param mixed $cellName The cell name/offset
*
* @return mixed The cell value
*/
public function get ($cellName);
/**
* Create a mutable copy
*
* @return IArrayClass The mutable copy
*/
public function toMutable (): IArrayClass;
}

@ -2,193 +2,16 @@
namespace jrosset\ArrayClasses;
use ArrayAccess;
use ArrayIterator;
use Countable;
use InvalidArgumentException;
use IteratorAggregate;
use JsonSerializable;
use OutOfRangeException;
use Serializable;
use Traversable;
/**
* An immutable array
*/
class ImmutableArrayClass implements IteratorAggregate, JsonSerializable, Serializable, Countable, ArrayAccess, IArrayCast {
/**
* @var array The internal array
*/
protected array $array;
/**
* @var bool Throws an exception for nonexistent elements ?
*/
private bool $throwsForNonExistentElement;
/**
* Initialize the array
*
* @param IArrayCast|array|null $initial The initial value
* @param bool $throwsForNonExistentElement Throws an exception for nonexistent elements ?
*/
public function __construct ($initial = null, bool $throwsForNonExistentElement = true) {
$this->setThrowsForNonExistentElement($throwsForNonExistentElement);
if (is_array($initial)) {
$this->array = $initial;
}
elseif (is_null($initial)) {
$this->array = [];
}
elseif ($initial instanceof IArrayCast) {
$this->array = $initial->toArray();
}
else {
throw new InvalidArgumentException('The initial value is not valid: null, array or ' . IArrayCast::class);
}
}
/**
* Get the value of a cell
*
* @param mixed $offset The cell offset
*
* @return mixed|null The cell value
*/
public function __invoke ($offset) {
return $this->get($offset);
}
/**
* Set information to dump
*
* @return array The information to dump
*
* @see https://www.php.net/manual/function.var-dump.php
*/
public function __debugInfo (): array {
return [
'array' => $this->array,
];
}
/**
* Check if a cell offset exists
*
* @param mixed $offset The cell offset
*
* @return bool True if the cell offset exists
*/
public function has ($offset): bool {
return array_key_exists($offset, $this->array);
}
/**
* Get the value of a cell
*
* @param mixed $offset The cell offset
* @param bool|null $throwsForNonExistentElement If set, temporarily override {@see ImmutableArrayClass::$throwsForNonExistentElement}
*
* @return mixed|null The cell value
*/
public function get ($offset, ?bool $throwsForNonExistentElement = null) {
if ($this->has($offset)) {
return $this->array[$offset];
}
if ($throwsForNonExistentElement ?? $this->throwsForNonExistentElement()) {
throw new OutOfRangeException();
}
return null;
}
/**
* @inheritDoc
*/
public function toArray (): array {
return $this->array;
}
/**
* Create a mutable copy
*
* @return ArrayClass The mutable copy
*/
public function toMutableArrayClass (): ArrayClass {
return new ArrayClass($this);
}
/**
* @inheritDoc
*/
public function count (): int {
return count($this->array);
}
/**
* @inheritDoc
*/
public function getIterator (): Traversable {
return new ArrayIterator($this->array);
}
class ImmutableArrayClass implements IImmutableArrayClass {
use TImmutableInternalArray;
/**
* @inheritDoc
*/
public function offsetExists ($offset): bool {
return $this->has($offset);
}
/**
* @inheritDoc
*/
public function offsetGet ($offset) {
return $this->get($offset);
}
/**
* @inheritDoc
*/
public function offsetSet ($offset, $value): void {
throw new ImmutableException();
}
/**
* @inheritDoc
*/
public function offsetUnset ($offset): void {
throw new ImmutableException();
}
/**
* @inheritDoc
*/
public function serialize (): string {
return serialize($this->array);
}
/**
* @inheritDoc
*/
public function unserialize ($data): void {
$this->array = unserialize($data);
}
/**
* @inheritDoc
*/
public function jsonSerialize () {
return $this->array;
}
/**
* Throws an exception for nonexistent elements ?
*
* @return bool Throws an exception for nonexistent elements ?
*/
public function throwsForNonExistentElement (): bool {
return $this->throwsForNonExistentElement;
}
/**
* Set if throws an exception for nonexistent elements
*
* @param bool $throwsForNonExistentElement Throws an exception for nonexistent elements ?
*
* @return $this
*/
public function setThrowsForNonExistentElement (bool $throwsForNonExistentElement): self {
$this->throwsForNonExistentElement = $throwsForNonExistentElement;
return $this;
public function toMutable (): IArrayClass {
return new ArrayClass($this->array, $this->throwsForNonExistentElement());
}
}

@ -0,0 +1,168 @@
<?php
namespace jrosset\ArrayClasses;
use ArrayIterator;
use InvalidArgumentException;
use OutOfRangeException;
use Traversable;
trait TImmutableInternalArray {
/**
* @var array The internal array
*/
protected array $array = [];
/**
* @var bool Throws an exception for nonexistent elements ?
*/
private bool $throwsForNonExistentElement = true;
/**
* Initialize the array
*
* @param IArrayCast|array|null $initial The initial value
* @param bool $throwsForNonExistentElement Throws an exception for nonexistent elements ?
*/
public function __construct ($initial = null, bool $throwsForNonExistentElement = true) {
$this->setThrowsForNonExistentElement($throwsForNonExistentElement);
if (is_array($initial)) {
$this->array = $initial;
}
elseif (is_null($initial)) {
$this->array = [];
}
elseif ($initial instanceof IArrayCast) {
$this->array = $initial->toArray();
}
else {
throw new InvalidArgumentException('The initial value is not valid: null, array or ' . IArrayCast::class);
}
}
/**
* Set information to dump
*
* @return array The information to dump
*
* @see https://www.php.net/manual/function.var-dump.php
*/
public function __debugInfo (): array {
return [
'array' => $this->array,
];
}
/**
* Check if a cell offset exists
*
* @param mixed $offset The cell offset
*
* @return bool True if the cell offset exists
*/
public function has ($offset): bool {
return array_key_exists($offset, $this->array);
}
/**
* Get the value of a cell
*
* @param mixed $offset The cell offset
* @param bool|null $throwsForNonExistentElement If set, temporarily override {@see ImmutableArrayClass::$throwsForNonExistentElement}
*
* @return mixed|null The cell value
*/
public function get ($offset, ?bool $throwsForNonExistentElement = null) {
if ($this->has($offset)) {
return $this->array[$offset];
}
if ($throwsForNonExistentElement ?? $this->throwsForNonExistentElement()) {
throw new OutOfRangeException();
}
return null;
}
/**
* @inheritDoc
*/
public function toArray (): array {
return $this->array;
}
/**
* @inheritDoc
*/
public function count (): int {
return count($this->array);
}
/**
* @inheritDoc
*/
public function getIterator (): Traversable {
return new ArrayIterator($this->array);
}
/**
* @inheritDoc
*/
public function offsetExists ($offset): bool {
return $this->has($offset);
}
/**
* @inheritDoc
*/
public function offsetGet ($offset) {
return $this->get($offset);
}
/**
* @inheritDoc
*/
public function offsetSet ($offset, $value): void {
throw new ImmutableException();
}
/**
* @inheritDoc
*/
public function offsetUnset ($offset): void {
throw new ImmutableException();
}
/**
* @inheritDoc
*/
public function serialize (): string {
return serialize($this->array);
}
/**
* @inheritDoc
*/
public function unserialize ($data): void {
$this->array = unserialize($data);
}
/**
* @inheritDoc
*/
public function jsonSerialize () {
return $this->array;
}
/**
* Throws an exception for nonexistent elements ?
*
* @return bool Throws an exception for nonexistent elements ?
*/
public function throwsForNonExistentElement (): bool {
return $this->throwsForNonExistentElement;
}
/**
* Set if throws an exception for nonexistent elements
*
* @param bool $throwsForNonExistentElement Throws an exception for nonexistent elements ?
*
* @return $this
*/
public function setThrowsForNonExistentElement (bool $throwsForNonExistentElement): self {
$this->throwsForNonExistentElement = $throwsForNonExistentElement;
return $this;
}
}

@ -0,0 +1,49 @@
<?php
namespace jrosset\ArrayClasses;
use OutOfRangeException;
trait TInternalArray {
/**
* Set or replace a cell value
*
* @param mixed $offset The cell offset
* @param mixed $value The cell new value
*
* @return $this
*/
public function set ($offset, $value): self {
$this->array[$offset] = $value;
return $this;
}
/**
* Remove a cell
*
* @param mixed $offset The cell offset
* @param bool|null $throwsForNonExistentElement If set, temporarily override {@see ImmutableArrayClass::$throwsForNonExistentElement}
*
* @return $this
*/
public function del ($offset, ?bool $throwsForNonExistentElement = null): self {
if ($throwsForNonExistentElement ?? $this->throwsForNonExistentElement() && !$this->has($offset)) {
throw new OutOfRangeException();
}
unset($this->array[$offset]);
return $this;
}
/**
* @inheritDoc
*/
public function offsetSet ($offset, $value): void {
$this->set($offset, $value);
}
/**
* @inheritDoc
*/
public function offsetUnset ($offset): void {
$this->del($offset);
}
}
Loading…
Cancel
Save