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 = [];