diff --git a/composer.json b/composer.json
index ae2297a..504dc99 100644
--- a/composer.json
+++ b/composer.json
@@ -39,7 +39,8 @@
"phpstan/phpstan": "^1.10.56",
"phpstan/phpstan-strict-rules": "^1.5",
"friendsofphp/php-cs-fixer": "^3.48",
- "squizlabs/php_codesniffer": "^3.8"
+ "squizlabs/php_codesniffer": "^3.8",
+ "vimeo/psalm": "^5.20"
},
"autoload": {
"psr-4": {
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
index 394ebee..d0807e9 100644
--- a/phpdoc.dist.xml
+++ b/phpdoc.dist.xml
@@ -23,6 +23,7 @@
extends
implements
phpstan-require-implements
+ psalm-suppress
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..4e9d307
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/DataStructures/StrictList.php b/src/DataStructures/StrictList.php
index f5f80ee..3e9c29f 100644
--- a/src/DataStructures/StrictList.php
+++ b/src/DataStructures/StrictList.php
@@ -23,110 +23,223 @@ declare(strict_types=1);
namespace OCC\Basics\DataStructures;
+use ArrayAccess;
+use Countable;
use InvalidArgumentException;
+use Iterator;
+use OutOfRangeException;
+use RuntimeException;
use SplDoublyLinkedList;
use OCC\Basics\Traits\Getter;
+use Serializable;
/**
* A type-sensitive, taversable list.
*
* Extends [\SplDoublyLinkedList](https://www.php.net/spldoublylinkedlist) with
- * an option to specify the allowed data types for list items.
+ * an option to specify the allowed data types for list values.
*
* @author Sebastian Meyer
* @package Basics\DataStructures
*
- * @property-read string[] $allowedTypes
+ * @property-read string[] $allowedTypes The allowed data types for values.
+ *
+ * @api
*
* @template AllowedType of mixed
* @extends SplDoublyLinkedList
+ * @implements ArrayAccess
+ * @implements Iterator
*/
-class StrictList extends SplDoublyLinkedList
+class StrictList extends SplDoublyLinkedList implements ArrayAccess, Countable, Iterator, Serializable
{
use Getter;
/**
- * Defines the allowed data types for items.
+ * Queue style iterator mode (First In, First Out).
+ */
+ public const IT_MODE_FIFO = 0;
+
+ /**
+ * Stack style iterator mode (Last In, First Out).
+ */
+ public const IT_MODE_LIFO = 2;
+
+ /**
+ * Destructive iterator mode (delete values after iteration).
+ */
+ public const IT_MODE_DELETE = 1;
+
+ /**
+ * Preserving iterator mode (keep values after iteration).
+ */
+ public const IT_MODE_KEEP = 0;
+
+ /**
+ * The allowed data types for values.
*
* @var string[]
+ *
+ * @internal
*/
protected array $allowedTypes = [];
/**
- * Add/insert a new item at the specified index.
+ * Add/insert a new value at the specified offset.
*
- * @param int $index The index where the new item is to be inserted
- * @param AllowedType $item The new item for the index
+ * @param int $offset The offset where the new value is to be inserted
+ * @param AllowedType $value The new value for the offset
*
* @return void
*
* @throws InvalidArgumentException
+ *
+ * @api
*/
- public function add(int $index, mixed $item): void
+ public function add(int $offset, mixed $value): void
{
- if (!$this->isAllowedType($item)) {
+ if (!$this->isAllowedType($value)) {
throw new InvalidArgumentException(
sprintf(
'Parameter 2 must be an allowed type, %s given.',
- get_debug_type($item)
+ get_debug_type($value)
)
);
}
- parent::add($index, $item);
+ parent::add($offset, $value);
}
/**
- * Append items at the end of the list.
+ * Append values at the end of the list.
*
- * @param AllowedType ...$items One or more items to append
+ * @param AllowedType ...$values One or more values to append
*
* @return void
*
* @throws InvalidArgumentException
+ *
+ * @api
*/
- public function append(mixed ...$items): void
+ public function append(mixed ...$values): void
{
- foreach ($items as $count => $item) {
- if (!$this->isAllowedType($item)) {
+ foreach ($values as $count => $value) {
+ if (!$this->isAllowedType($value)) {
throw new InvalidArgumentException(
sprintf(
'Parameter %d must be an allowed type, %s given.',
(int) $count + 1,
- get_debug_type($item)
+ get_debug_type($value)
)
);
}
}
- foreach ($items as $item) {
- parent::push($item);
+ foreach ($values as $value) {
+ parent::push($value);
}
}
/**
- * Check if the item's data type is allowed on the list.
+ * Peek at the value at the beginning of the list.
*
- * @param AllowedType $item The item to check
+ * @return AllowedType The first value of the list
*
- * @return bool Whether the item's data type is allowed
+ * @throws RuntimeException
+ *
+ * @api
*/
- public function isAllowedType(mixed $item): bool
+ public function bottom(): mixed
+ {
+ return parent::bottom();
+ }
+
+ /**
+ * Count the number of values on the list.
+ *
+ * @return int The current number of values
+ *
+ * @api
+ */
+ public function count(): int
+ {
+ return parent::count();
+ }
+
+ /**
+ * Get current list value.
+ *
+ * @return AllowedType The current value
+ *
+ * @api
+ */
+ public function current(): mixed
+ {
+ return parent::current();
+ }
+
+ /**
+ * Get the mode of iteration.
+ *
+ * @return int The set of flags and modes of iteration
+ *
+ * @api
+ */
+ public function getIteratorMode(): int
+ {
+ return parent::getIteratorMode();
+ }
+
+ /**
+ * Check if the value's data type is allowed on the list.
+ *
+ * @param AllowedType $value The value to check
+ *
+ * @return bool Whether the value's data type is allowed
+ *
+ * @api
+ */
+ public function isAllowedType(mixed $value): bool
{
if (count($this->allowedTypes) === 0) {
return true;
}
foreach ($this->allowedTypes as $type) {
$function = 'is_' . $type;
- if (function_exists($function) && $function($item)) {
+ if (function_exists($function) && $function($value)) {
return true;
}
+ /** @var class-string */
$fqcn = ltrim($type, '\\');
- if (is_object($item) && is_a($item, $fqcn)) {
+ if (is_object($value) && is_a($value, $fqcn)) {
return true;
}
}
return false;
}
+ /**
+ * Check if the list is empty.
+ *
+ * @return bool Whether the list is empty
+ *
+ * @api
+ */
+ public function isEmpty(): bool
+ {
+ return parent::isEmpty();
+ }
+
+ /**
+ * Get the current value's offset.
+ *
+ * @return int The current offset
+ *
+ * @api
+ */
+ public function key(): int
+ {
+ return parent::key();
+ }
+
/**
* Magic getter method for $this->allowedTypes.
*
@@ -140,93 +253,275 @@ class StrictList extends SplDoublyLinkedList
}
/**
- * Set the item at the specified index.
- *
- * @param ?int $index The index being set or NULL to append
- * @param AllowedType $item The new item for the index
+ * Move cursor to the next value on the list.
*
* @return void
*
- * @throws InvalidArgumentException
+ * @api
*/
- public function offsetSet(mixed $index, mixed $item): void
+ public function next(): void
{
- if (!$this->isAllowedType($item)) {
- throw new InvalidArgumentException(
- sprintf(
- 'Parameter 2 must be an allowed type, %s given.',
- get_debug_type($item)
- )
- );
- }
- parent::offsetSet($index, $item);
+ parent::next();
}
/**
- * Prepend items at the start of the list.
+ * Check if the specified offset exists.
*
- * @param AllowedType ...$items One or more items to prepend
+ * @param int $offset The offset being checked
+ *
+ * @return bool Whether the offset exists
+ *
+ * @api
+ */
+ public function offsetExists(mixed $offset): bool
+ {
+ return parent::offsetExists($offset);
+ }
+
+ /**
+ * Get the value at the specified offset.
+ *
+ * @param int $offset The offset to get
+ *
+ * @return ?AllowedType The value at the offset or NULL
+ *
+ * @throws OutOfRangeException
+ *
+ * @api
+ */
+ public function offsetGet(mixed $offset): mixed
+ {
+ return parent::offsetGet($offset);
+ }
+
+ /**
+ * Set the value at the specified offset.
+ *
+ * @param ?int $offset The offset being set or NULL to append
+ * @param AllowedType $value The new value for the offset
*
* @return void
*
* @throws InvalidArgumentException
+ *
+ * @api
*/
- public function prepend(mixed ...$items): void
+ public function offsetSet(mixed $offset, mixed $value): void
{
- foreach ($items as $count => $item) {
- if (!$this->isAllowedType($item)) {
+ if (!$this->isAllowedType($value)) {
+ throw new InvalidArgumentException(
+ sprintf(
+ 'Parameter 2 must be an allowed type, %s given.',
+ get_debug_type($value)
+ )
+ );
+ }
+ /** @psalm-suppress PossiblyNullArgument */
+ parent::offsetSet($offset, $value);
+ }
+
+ /**
+ * Unset the specified offset.
+ *
+ * @param int $offset The offset to unset
+ *
+ * @return void
+ *
+ * @throws OutOfRangeException
+ *
+ * @api
+ */
+ public function offsetUnset(mixed $offset): void
+ {
+ parent::offsetUnset($offset);
+ }
+
+ /**
+ * Pops an value from the end of the list.
+ *
+ * @return AllowedType The value from the end of the list
+ *
+ * @throws RuntimeException
+ *
+ * @api
+ */
+ public function pop(): mixed
+ {
+ return parent::pop();
+ }
+
+ /**
+ * Prepend values at the start of the list.
+ *
+ * @param AllowedType ...$values One or more values to prepend
+ *
+ * @return void
+ *
+ * @throws InvalidArgumentException
+ *
+ * @api
+ */
+ public function prepend(mixed ...$values): void
+ {
+ foreach ($values as $count => $value) {
+ if (!$this->isAllowedType($value)) {
throw new InvalidArgumentException(
sprintf(
'Parameter %d must be an allowed type, %s given.',
(int) $count + 1,
- get_debug_type($item)
+ get_debug_type($value)
)
);
}
}
- foreach ($items as $item) {
- parent::unshift($item);
+ foreach ($values as $value) {
+ parent::unshift($value);
}
}
/**
- * Push an item at the end of the list.
+ * Move cursor to the previous value on the list.
*
- * @param AllowedType $item The item to push
+ * @return void
+ *
+ * @api
+ */
+ public function prev(): void
+ {
+ parent::prev();
+ }
+
+ /**
+ * Push an value at the end of the list.
+ *
+ * @param AllowedType $value The value to push
*
* @return void
*
* @throws InvalidArgumentException
+ *
+ * @api
*/
- public function push(mixed $item): void
+ public function push(mixed $value): void
{
- if (!$this->isAllowedType($item)) {
+ if (!$this->isAllowedType($value)) {
throw new InvalidArgumentException(
sprintf(
'Parameter 1 must be an allowed type, %s given.',
- get_debug_type($item)
+ get_debug_type($value)
)
);
}
- parent::push($item);
+ parent::push($value);
+ }
+
+ /**
+ * Move cursor back to the start of the list.
+ *
+ * @return void
+ *
+ * @api
+ */
+ public function rewind(): void
+ {
+ parent::rewind();
}
/**
* Get string representation of $this.
*
* @return string The string representation
+ *
+ * @internal
*/
public function serialize(): string
{
return serialize($this->__serialize());
}
+ /**
+ * Set allowed data types of list values.
+ *
+ * @param string[] $allowedTypes Allowed data types of values
+ *
+ * @return void
+ *
+ * @throws InvalidArgumentException
+ *
+ * @internal
+ */
+ protected function setAllowedTypes(array $allowedTypes = []): void
+ {
+ if (array_sum(array_map('is_string', $allowedTypes)) !== count($allowedTypes)) {
+ throw new InvalidArgumentException(
+ 'Allowed types must be array of strings or empty array.'
+ );
+ }
+ $this->allowedTypes = $allowedTypes;
+ }
+
+ /**
+ * Set the mode of iteration.
+ *
+ * @param int $mode The new iterator mode (0, 1, 2 or 3)
+ *
+ * There are two orthogonal sets of modes that can be set.
+ *
+ * The direction of iteration (either one or the other):
+ * - StrictList::IT_MODE_FIFO (queue style)
+ * - StrictList::IT_MODE_LIFO (stack style)
+ *
+ * The behavior of the iterator (either one or the other):
+ * - StrictList::IT_MODE_DELETE (delete items)
+ * - StrictList::IT_MODE_KEEP (keep items)
+ *
+ * The default mode is: IT_MODE_FIFO | IT_MODE_KEEP
+ *
+ * @return int The set of flags and modes of iteration
+ *
+ * @api
+ */
+ public function setIteratorMode(int $mode): int
+ {
+ return parent::setIteratorMode($mode);
+ }
+
+ /**
+ * Shift an value from the beginning of the list.
+ *
+ * @return AllowedType The first value of the list
+ *
+ * @throws RuntimeException
+ *
+ * @api
+ */
+ public function shift(): mixed
+ {
+ return parent::shift();
+ }
+
+ /**
+ * Peek at the value at the end of the list.
+ *
+ * @return AllowedType The last value of the list
+ *
+ * @throws RuntimeException
+ *
+ * @api
+ */
+ public function top(): mixed
+ {
+ return parent::top();
+ }
+
/**
* Restore $this from string representation.
*
* @param string $data The string representation
*
* @return void
+ *
+ * @internal
*/
public function unserialize($data): void
{
@@ -236,31 +531,46 @@ class StrictList extends SplDoublyLinkedList
}
/**
- * Prepend the list with an item.
+ * Prepend the list with an value.
*
- * @param AllowedType $item The item to unshift
+ * @param AllowedType $value The value to unshift
*
* @return void
*
* @throws InvalidArgumentException
+ *
+ * @api
*/
- public function unshift(mixed $item): void
+ public function unshift(mixed $value): void
{
- if (!$this->isAllowedType($item)) {
+ if (!$this->isAllowedType($value)) {
throw new InvalidArgumentException(
sprintf(
'Parameter 1 must be an allowed type, %s given.',
- get_debug_type($item)
+ get_debug_type($value)
)
);
}
- parent::unshift($item);
+ parent::unshift($value);
}
/**
- * Create a type-sensitive, traversable list of items.
+ * Check if the list contains any more values.
+ *
+ * @return bool Whether the list contains more values
+ *
+ * @api
+ */
+ public function valid(): bool
+ {
+ return parent::valid();
+ }
+
+ /**
+ * Create a type-sensitive, traversable list of values.
+ *
+ * @param string[] $allowedTypes Allowed data types of values (optional)
*
- * @param string[] $allowedTypes Allowed data types of items (optional)
* If empty, all types are allowed.
* Possible values are:
* - "array"
@@ -277,16 +587,13 @@ class StrictList extends SplDoublyLinkedList
* - "scalar"
* - "string"
*
+ * @return void
+ *
* @throws InvalidArgumentException
*/
public function __construct(array $allowedTypes = [])
{
- if (array_sum(array_map('is_string', $allowedTypes)) !== count($allowedTypes)) {
- throw new InvalidArgumentException(
- 'Allowed types must be array of strings or empty array.'
- );
- }
- $this->allowedTypes = $allowedTypes;
+ $this->setAllowedTypes($allowedTypes);
}
/**
@@ -325,15 +632,17 @@ class StrictList extends SplDoublyLinkedList
* @return void
*
* @internal
+ *
+ * @psalm-suppress MethodSignatureMismatch
*/
public function __unserialize(array $data): void
{
/** @var string[] $allowedTypes */
$allowedTypes = $data['StrictList::allowedTypes'];
- $this->__construct($allowedTypes);
- /** @var iterable $items */
- $items = $data['SplDoublyLinkedList::dllist'];
- $this->append(...$items);
+ $this->setAllowedTypes($allowedTypes);
+ /** @var array $values */
+ $values = $data['SplDoublyLinkedList::dllist'];
+ $this->append(...$values);
/** @var int $flags */
$flags = $data['SplDoublyLinkedList::flags'];
$this->setIteratorMode($flags);
diff --git a/src/DataStructures/StrictQueue.php b/src/DataStructures/StrictQueue.php
index 9558b9c..5671087 100644
--- a/src/DataStructures/StrictQueue.php
+++ b/src/DataStructures/StrictQueue.php
@@ -23,10 +23,14 @@ declare(strict_types=1);
namespace OCC\Basics\DataStructures;
+use ArrayAccess;
+use Countable;
+use Iterator;
use RuntimeException;
+use Serializable;
/**
- * A type-sensitive, taversable First In, First Out Queue (FIFO).
+ * A type-sensitive, taversable First In, First Out queue (FIFO).
*
* Extends [\SplQueue](https://www.php.net/splqueue) with an option to specify
* the allowed data types for list items.
@@ -34,12 +38,14 @@ use RuntimeException;
* @author Sebastian Meyer
* @package Basics\DataStructures
*
- * @property-read string[] $allowedTypes
+ * @api
*
* @template AllowedType of mixed
* @extends StrictList
+ * @implements ArrayAccess
+ * @implements Iterator
*/
-class StrictQueue extends StrictList
+class StrictQueue extends StrictList implements ArrayAccess, Countable, Iterator, Serializable
{
/**
* Dequeue an item from the queue.
@@ -70,6 +76,17 @@ class StrictQueue extends StrictList
*
* @param int $mode The new iterator mode (0 or 1)
*
+ * There are two orthogonal sets of modes that can be set.
+ *
+ * The direction of iteration (fixed for StrictQueue):
+ * - StrictQueue::IT_MODE_FIFO (queue style)
+ *
+ * The behavior of the iterator (either one or the other):
+ * - StrictQueue::IT_MODE_DELETE (delete items)
+ * - StrictQueue::IT_MODE_KEEP (keep items)
+ *
+ * The default mode is: IT_MODE_FIFO | IT_MODE_KEEP
+ *
* @return int The set of flags and modes of iteration
*
* @throws RuntimeException
@@ -91,6 +108,7 @@ class StrictQueue extends StrictList
* Create a type-sensitive, traversable queue of items.
*
* @param string[] $allowedTypes Allowed data types of items (optional)
+ *
* If empty, all types are allowed.
* Possible values are:
* - "array"
@@ -107,6 +125,8 @@ class StrictQueue extends StrictList
* - "scalar"
* - "string"
*
+ * @return void
+ *
* @throws \InvalidArgumentException
*/
public function __construct(array $allowedTypes = [])
diff --git a/src/DataStructures/StrictStack.php b/src/DataStructures/StrictStack.php
index e60e50b..1ec41f0 100644
--- a/src/DataStructures/StrictStack.php
+++ b/src/DataStructures/StrictStack.php
@@ -23,10 +23,14 @@ declare(strict_types=1);
namespace OCC\Basics\DataStructures;
+use ArrayAccess;
+use Countable;
+use Iterator;
use RuntimeException;
+use Serializable;
/**
- * A type-sensitive, taversable Last In, First Out Stack (LIFO).
+ * A type-sensitive, taversable Last In, First Out stack (LIFO).
*
* Extends [\SplStack](https://www.php.net/splstack) with an option to specify
* the allowed data types for list items.
@@ -34,12 +38,14 @@ use RuntimeException;
* @author Sebastian Meyer
* @package Basics\DataStructures
*
- * @property-read string[] $allowedTypes
+ * @api
*
* @template AllowedType of mixed
* @extends StrictList
+ * @implements ArrayAccess
+ * @implements Iterator
*/
-class StrictStack extends StrictList
+class StrictStack extends StrictList implements ArrayAccess, Countable, Iterator, Serializable
{
/**
* Add an item to the stack.
@@ -70,6 +76,17 @@ class StrictStack extends StrictList
*
* @param int $mode The new iterator mode (2 or 3)
*
+ * There are two orthogonal sets of modes that can be set.
+ *
+ * The direction of iteration (fixed for StrictStack):
+ * - StrictStack::IT_MODE_LIFO (stack style)
+ *
+ * The behavior of the iterator (either one or the other):
+ * - StrictStack::IT_MODE_DELETE (delete items)
+ * - StrictStack::IT_MODE_KEEP (keep items)
+ *
+ * The default mode is: IT_MODE_LIFO | IT_MODE_KEEP
+ *
* @return int The set of flags and modes of iteration
*
* @throws RuntimeException
@@ -91,6 +108,7 @@ class StrictStack extends StrictList
* Create a type-sensitive, traversable stack of items.
*
* @param string[] $allowedTypes Allowed data types of items (optional)
+ *
* If empty, all types are allowed.
* Possible values are:
* - "array"
@@ -107,6 +125,8 @@ class StrictStack extends StrictList
* - "scalar"
* - "string"
*
+ * @return void
+ *
* @throws \InvalidArgumentException
*/
public function __construct(array $allowedTypes = [])
diff --git a/src/ErrorHandlers/ThrowErrorException.php b/src/ErrorHandlers/ThrowErrorException.php
index 4e366fe..ed7c241 100644
--- a/src/ErrorHandlers/ThrowErrorException.php
+++ b/src/ErrorHandlers/ThrowErrorException.php
@@ -32,6 +32,8 @@ use ErrorException;
*
* @author Sebastian Meyer
* @package Basics\ErrorHandlers
+ *
+ * @api
*/
class ThrowErrorException
{
diff --git a/src/ErrorHandlers/TriggerExceptionError.php b/src/ErrorHandlers/TriggerExceptionError.php
index 62eda21..83b7f8c 100644
--- a/src/ErrorHandlers/TriggerExceptionError.php
+++ b/src/ErrorHandlers/TriggerExceptionError.php
@@ -32,6 +32,8 @@ use Throwable;
*
* @author Sebastian Meyer
* @package Basics\ErrorHandlers
+ *
+ * @api
*/
class TriggerExceptionError
{
diff --git a/src/InterfaceTraits/ArrayAccess.php b/src/InterfaceTraits/ArrayAccessTrait.php
similarity index 75%
rename from src/InterfaceTraits/ArrayAccess.php
rename to src/InterfaceTraits/ArrayAccessTrait.php
index 20e33da..c7010d9 100644
--- a/src/InterfaceTraits/ArrayAccess.php
+++ b/src/InterfaceTraits/ArrayAccessTrait.php
@@ -23,25 +23,32 @@ declare(strict_types=1);
namespace OCC\Basics\InterfaceTraits;
+use ArrayAccess;
+
/**
* A generic implementation of the ArrayAccess interface.
*
* @author Sebastian Meyer
* @package Basics\InterfaceTraits
*
- * @phpstan-require-implements \ArrayAccess
+ * @template TKey of int|string
+ * @template TValue of mixed
+ * @implements ArrayAccess
+ * @phpstan-require-implements ArrayAccess
*/
-trait ArrayAccess
+trait ArrayAccessTrait
{
/**
* Holds the array-accessible data.
+ *
+ * @var array
*/
- private array $data = [];
+ protected array $data = [];
/**
- * Whether the specified offset exists.
+ * Check if the specified offset exists.
*
- * @param mixed $offset The offset to check for
+ * @param TKey $offset The offset to check for
*
* @return bool Whether the offset exists
*/
@@ -53,9 +60,9 @@ trait ArrayAccess
/**
* Retrieve data at the specified offset.
*
- * @param mixed $offset The offset to retrieve at
+ * @param TKey $offset The offset to retrieve at
*
- * @return mixed The value at the offset or NULL
+ * @return ?TValue The value at the offset or NULL
*/
public function offsetGet(mixed $offset): mixed
{
@@ -65,8 +72,8 @@ trait ArrayAccess
/**
* Assign a value to the specified offset.
*
- * @param mixed $offset The offset to assign to or NULL to append
- * @param mixed $value The value to set
+ * @param ?TKey $offset The offset to assign to or NULL to append
+ * @param TValue $value The value to set
*
* @return void
*/
@@ -82,7 +89,7 @@ trait ArrayAccess
/**
* Unset the specified offset.
*
- * @param mixed $offset The offset to unset
+ * @param TKey $offset The offset to unset
*
* @return void
*/
diff --git a/src/InterfaceTraits/Countable.php b/src/InterfaceTraits/CountableTrait.php
similarity index 83%
rename from src/InterfaceTraits/Countable.php
rename to src/InterfaceTraits/CountableTrait.php
index 5eb2660..1e30352 100644
--- a/src/InterfaceTraits/Countable.php
+++ b/src/InterfaceTraits/CountableTrait.php
@@ -23,20 +23,27 @@ declare(strict_types=1);
namespace OCC\Basics\InterfaceTraits;
+use Countable;
+
/**
* A generic implementation of the Countable interface.
*
* @author Sebastian Meyer
* @package Basics\InterfaceTraits
*
- * @phpstan-require-implements \Countable
+ * @template TKey of int|string
+ * @template TValue of mixed
+ * @implements Countable
+ * @phpstan-require-implements Countable
*/
-trait Countable
+trait CountableTrait
{
/**
* Holds the countable data.
+ *
+ * @var array
*/
- private array $data = [];
+ protected array $data = [];
/**
* Count the data items.
diff --git a/src/InterfaceTraits/IteratorAggregate.php b/src/InterfaceTraits/IteratorAggregateTrait.php
similarity index 77%
rename from src/InterfaceTraits/IteratorAggregate.php
rename to src/InterfaceTraits/IteratorAggregateTrait.php
index 571c503..7a7ed58 100644
--- a/src/InterfaceTraits/IteratorAggregate.php
+++ b/src/InterfaceTraits/IteratorAggregateTrait.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace OCC\Basics\InterfaceTraits;
use ArrayIterator;
+use IteratorAggregate;
/**
* A generic implementation of the IteratorAggregate interface.
@@ -31,19 +32,24 @@ use ArrayIterator;
* @author Sebastian Meyer
* @package Basics\InterfaceTraits
*
- * @phpstan-require-implements \IteratorAggregate
+ * @template TKey of int|string
+ * @template TValue of mixed
+ * @implements IteratorAggregate
+ * @phpstan-require-implements IteratorAggregate
*/
-trait IteratorAggregate
+trait IteratorAggregateTrait
{
/**
* Holds the iterable data.
+ *
+ * @var array
*/
- private array $data = [];
+ protected array $data = [];
/**
* Retrieve an external iterator.
*
- * @return ArrayIterator
+ * @return ArrayIterator New array iterator for data array
*/
public function getIterator(): ArrayIterator
{
diff --git a/src/InterfaceTraits/Iterator.php b/src/InterfaceTraits/IteratorTrait.php
similarity index 81%
rename from src/InterfaceTraits/Iterator.php
rename to src/InterfaceTraits/IteratorTrait.php
index 2c71bae..d93099d 100644
--- a/src/InterfaceTraits/Iterator.php
+++ b/src/InterfaceTraits/IteratorTrait.php
@@ -23,25 +23,32 @@ declare(strict_types=1);
namespace OCC\Basics\InterfaceTraits;
+use Iterator;
+
/**
* A generic implementation of the Iterator interface.
*
* @author Sebastian Meyer
* @package Basics\InterfaceTraits
*
- * @phpstan-require-implements \Iterator
+ * @template TKey of int|string
+ * @template TValue of mixed
+ * @implements Iterator
+ * @phpstan-require-implements Iterator
*/
-trait Iterator
+trait IteratorTrait
{
/**
* Holds the iterable data.
+ *
+ * @var array
*/
- private array $data = [];
+ protected array $data = [];
/**
* Return the current item.
*
- * @return mixed The current item or FALSE if invalid
+ * @return TValue|false The current item or FALSE if invalid
*/
public function current(): mixed
{
@@ -51,7 +58,7 @@ trait Iterator
/**
* Return the current key.
*
- * @return mixed The current key or NULL if invalid
+ * @return ?TKey The current key or NULL if invalid
*/
public function key(): mixed
{
@@ -79,7 +86,7 @@ trait Iterator
}
/**
- * Checks if current position is valid.
+ * Check if current position is valid.
*
* @return bool Whether the current position is valid
*/
diff --git a/src/Traits/Getter.php b/src/Traits/Getter.php
index d44013c..5ad7f6d 100644
--- a/src/Traits/Getter.php
+++ b/src/Traits/Getter.php
@@ -75,11 +75,12 @@ trait Getter
public function __isset(string $property): bool
{
try {
+ /** @var mixed $value */
$value = $this->__get($property);
} catch (InvalidArgumentException) {
$value = null;
} finally {
- return (bool) $value !== false;
+ return boolval($value ?? null) !== false;
}
}
}
diff --git a/src/Traits/Singleton.php b/src/Traits/Singleton.php
index 9ce5b30..c6358d5 100644
--- a/src/Traits/Singleton.php
+++ b/src/Traits/Singleton.php
@@ -37,7 +37,7 @@ trait Singleton
/**
* Holds the singleton instance.
*
- * @var array
+ * @var array
*/
private static array $singleton = [];