diff --git a/README.md b/README.md index 7f0f8cf..a490fd3 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ A PHP array manipulation library. Compatible with PHP 8+ * [Installation](#installation-via-composer-require) * [Multidimensional ArrayAccess](#multidimensional-arrayaccess) -* [PhpDoc @property checking](#phpdoc-property-checking) +* [PhpDoc array-shape / property checking](#phpdoc-array-shape--property-checking) * [OO and Chaining](#oo-and-chaining) * [Collections](#collections) * [Pre-Defined Typified Collections](#pre-defined-typified-collections) @@ -116,18 +116,14 @@ $arrayy->Lars = array('lastname' => 'Müller'); $arrayy->Lars->lastname; // 'Müller' ``` -## PhpDoc @property checking +## PhpDoc array-shape / property checking -The library offers type checking for `@property` phpdoc-class-comments and native declared properties. +The library offers type checking for phpdoc array-shape annotations, legacy `@property` phpdoc-class-comments, and native declared properties. Prefer the array-shape form because it can reuse the `Arrayy` template for IDE autocompletion and static-analysis support. When you want PHPStan to check reads precisely, prefer array-like access with literal keys (for example `$user['lastName']`) on these array-shape-based models. Do not combine array-shape annotations and `@property` tags on the same model. ```php /** - * @property int $id - * @property int|string $firstName - * @property string $lastName - * @property null|City $city - * - * @extends \Arrayy\Arrayy + * @template T of array{id: int, firstName: int|string, lastName: string, city?: City|null} + * @extends \Arrayy\Arrayy,value-of,T> */ class User extends \Arrayy\Arrayy { @@ -137,11 +133,8 @@ class User extends \Arrayy\Arrayy } /** - * @property string|null $plz - * @property string $name - * @property string[] $infos - * - * @extends \Arrayy\Arrayy + * @template T of array{plz: string|null, name: string, infos: string[]} + * @extends \Arrayy\Arrayy,value-of,T> */ class City extends \Arrayy\Arrayy { @@ -169,7 +162,7 @@ $user = new User( ] ); -var_dump($user['lastName']); // 'Moelleken' +var_dump($user['lastName']); // 'Moelleken' // preferred for PHPStan-checked reads var_dump($user[$userMeta->lastName]); // 'Moelleken' var_dump($user->lastName); // Moelleken @@ -201,7 +194,7 @@ NativeCity::createFromJsonMapper( var_dump($nativeMeta->infos); // 'infos' ``` -- "checkPropertyTypes": activate the type checking for all defined `@property` tags and native declared properties +- "checkPropertyTypes": activate the type checking for all defined array-shape keys, `@property` tags, and native declared properties - "checkPropertiesMismatchInConstructor": activate the property mismatch check, so you can only add an array with all needed properties (or an empty array) into the constructor - use a property-level `@var` annotation such as `/** @var string[] */` if a native `array` property needs element-type validation @@ -218,11 +211,8 @@ echo a(['fòô', 'bàř', 'bàř'])->unique()->reverse()->implode(','); // 'bà complex example: ```php /** - * @property int $id - * @property string $firstName - * @property string $lastName - * - * @extends \Arrayy\Arrayy + * @template T of array{id: int, firstName: string, lastName: string} + * @extends \Arrayy\Arrayy,value-of,T> */ class User extends \Arrayy\Arrayy { @@ -486,12 +476,8 @@ Create an new Arrayy object via JSON and fill sub-objects is possible. namespace Arrayy\tests; /** - * @property int $id - * @property int|string $firstName - * @property string $lastName - * @property \Arrayy\tests\CityData|null $city - * - * @extends \Arrayy\Arrayy + * @template T of array{id: int, firstName: int|string, lastName: string, city?: \Arrayy\tests\CityData|null} + * @extends \Arrayy\Arrayy,value-of,T> */ class UserData extends \Arrayy\Arrayy { @@ -501,11 +487,8 @@ class UserData extends \Arrayy\Arrayy } /** - * @property string|null $plz - * @property string $name - * @property string[] $infos - * - * @extends \Arrayy\Arrayy + * @template T of array{plz: string|null, name: string, infos: string[]} + * @extends \Arrayy\Arrayy,value-of,T> */ class CityData extends \Arrayy\Arrayy { @@ -802,7 +785,7 @@ foreach ($arrayy) as $key => $value) { randomMutable randomValue randomValues -randomWeighted +randomWeighted reduce reduce_dimension reindex @@ -1369,8 +1352,8 @@ Create an new Arrayy object via JSON. Create an instance from JSON using the built-in mapper. -For Arrayy models with property checks enabled, both phpdoc `@property` -definitions and native declared properties are used for metadata and type checks. +For Arrayy models with property checks enabled, phpdoc array-shape annotations, +legacy `@property` definitions, and native declared properties are used for metadata and type checks. Add a property-level `@var` annotation if a native `array` property also needs element-type validation. @@ -2833,8 +2816,8 @@ a($array1)->mergePrependNewIndex($array2); // Arrayy[0 => 'foo', 1 => 'bar2', 2 ## static meta(): ArrayyMeta|mixed|static -Return a meta object with property names from phpdoc `@property` tags and -native declared properties. +Return a meta object with property names from phpdoc array-shape annotations, +`@property` tags, and native declared properties. **Parameters:** __nothing__ @@ -3286,7 +3269,7 @@ a([1 => 'one', 2 => 'two'])->randomValues(); // e.g. Arrayy['one', 'two'] -------- -## randomWeighted(array $array, int|null $number): static +## randomWeighted(array $array, int|null $number): static Get a random value from an array, with the ability to skew the results. @@ -3299,7 +3282,7 @@ a([0 => 3, 1 => 4])->randomWeighted([1 => 4]); // e.g.: Arrayy[4] (has a 66% cha - `int|null $number

How many values you will take?

` **Return:** -- `static

(Immutable)

` +- `static

(Immutable)

` -------- diff --git a/build/docs/base.md b/build/docs/base.md index 1051533..b182a06 100644 --- a/build/docs/base.md +++ b/build/docs/base.md @@ -22,7 +22,7 @@ A PHP array manipulation library. Compatible with PHP 8+ * [Installation](#installation-via-composer-require) * [Multidimensional ArrayAccess](#multidimensional-arrayaccess) -* [PhpDoc @property checking](#phpdoc-property-checking) +* [PhpDoc array-shape / property checking](#phpdoc-array-shape--property-checking) * [OO and Chaining](#oo-and-chaining) * [Collections](#collections) * [Pre-Defined Typified Collections](#pre-defined-typified-collections) @@ -115,18 +115,14 @@ $arrayy->Lars = array('lastname' => 'Müller'); $arrayy->Lars->lastname; // 'Müller' ``` -## PhpDoc @property checking +## PhpDoc array-shape / property checking -The library offers type checking for `@property` phpdoc-class-comments and native declared properties. +The library offers type checking for phpdoc array-shape annotations, legacy `@property` phpdoc-class-comments, and native declared properties. Prefer the array-shape form because it can reuse the `Arrayy` template for IDE autocompletion and static-analysis support. When you want PHPStan to check reads precisely, prefer array-like access with literal keys (for example `$user['lastName']`) on these array-shape-based models. Do not combine array-shape annotations and `@property` tags on the same model. ```php /** - * @property int $id - * @property int|string $firstName - * @property string $lastName - * @property null|City $city - * - * @extends \Arrayy\Arrayy + * @template T of array{id: int, firstName: int|string, lastName: string, city?: City|null} + * @extends \Arrayy\Arrayy,value-of,T> */ class User extends \Arrayy\Arrayy { @@ -136,11 +132,8 @@ class User extends \Arrayy\Arrayy } /** - * @property string|null $plz - * @property string $name - * @property string[] $infos - * - * @extends \Arrayy\Arrayy + * @template T of array{plz: string|null, name: string, infos: string[]} + * @extends \Arrayy\Arrayy,value-of,T> */ class City extends \Arrayy\Arrayy { @@ -168,7 +161,7 @@ $user = new User( ] ); -var_dump($user['lastName']); // 'Moelleken' +var_dump($user['lastName']); // 'Moelleken' // preferred for PHPStan-checked reads var_dump($user[$userMeta->lastName]); // 'Moelleken' var_dump($user->lastName); // Moelleken @@ -200,7 +193,7 @@ NativeCity::createFromJsonMapper( var_dump($nativeMeta->infos); // 'infos' ``` -- "checkPropertyTypes": activate the type checking for all defined `@property` tags and native declared properties +- "checkPropertyTypes": activate the type checking for all defined array-shape keys, `@property` tags, and native declared properties - "checkPropertiesMismatchInConstructor": activate the property mismatch check, so you can only add an array with all needed properties (or an empty array) into the constructor - use a property-level `@var` annotation such as `/** @var string[] */` if a native `array` property needs element-type validation @@ -217,11 +210,8 @@ echo a(['fòô', 'bàř', 'bàř'])->unique()->reverse()->implode(','); // 'bà complex example: ```php /** - * @property int $id - * @property string $firstName - * @property string $lastName - * - * @extends \Arrayy\Arrayy + * @template T of array{id: int, firstName: string, lastName: string} + * @extends \Arrayy\Arrayy,value-of,T> */ class User extends \Arrayy\Arrayy { @@ -485,12 +475,8 @@ Create an new Arrayy object via JSON and fill sub-objects is possible. namespace Arrayy\tests; /** - * @property int $id - * @property int|string $firstName - * @property string $lastName - * @property \Arrayy\tests\CityData|null $city - * - * @extends \Arrayy\Arrayy + * @template T of array{id: int, firstName: int|string, lastName: string, city?: \Arrayy\tests\CityData|null} + * @extends \Arrayy\Arrayy,value-of,T> */ class UserData extends \Arrayy\Arrayy { @@ -500,11 +486,8 @@ class UserData extends \Arrayy\Arrayy } /** - * @property string|null $plz - * @property string $name - * @property string[] $infos - * - * @extends \Arrayy\Arrayy + * @template T of array{plz: string|null, name: string, infos: string[]} + * @extends \Arrayy\Arrayy,value-of,T> */ class CityData extends \Arrayy\Arrayy { diff --git a/phpstan.neon b/phpstan.neon index 6faf6f5..d865762 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,10 +4,3 @@ parameters: paths: - %currentWorkingDirectory%/src/ - %currentWorkingDirectory%/tests/ - ignoreErrors: - - - identifier: missingType.return - path: %currentWorkingDirectory%/tests/* - - - message: '#assertContains|assertInternalType|assertStringContainsString|assertIsArray|expectExceptionMessage#' - path: %currentWorkingDirectory%/tests/* diff --git a/src/Arrayy.php b/src/Arrayy.php index 4a060eb..105d428 100644 --- a/src/Arrayy.php +++ b/src/Arrayy.php @@ -32,6 +32,7 @@ * * @template TKey of array-key * @template T + * @template TData of array * @extends \ArrayObject * @implements \IteratorAggregate * @implements \ArrayAccess @@ -93,6 +94,11 @@ class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \ */ protected $properties = []; + /** + * @var array + */ + protected $optionalProperties = []; + /** * Initializes * @@ -230,8 +236,9 @@ public function __unset($key) * @return mixed *

Get a Value from the current array.

* - * @phpstan-param TKey $key - * @phpstan-return null|self|T + * @template TAccessKey of key-of + * @phpstan-param TAccessKey $key + * @phpstan-return TData[TAccessKey]|null|self> */ public function &__get($key) { @@ -259,7 +266,7 @@ public function &__get($key) * * @phpstan-param T $value * @phpstan-param TKey $key - * @phpstan-return static + * @phpstan-return static * * @psalm-mutation-free */ @@ -297,7 +304,7 @@ public function add($value, $key = null) * * @phpstan-param T $value * @phpstan-param TKey|null $key - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function append($value, $key = null): self @@ -340,7 +347,7 @@ public function append($value, $key = null): self * * @phpstan-param T $value * @phpstan-param TKey $key - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function appendImmutable($value, $key = null): self @@ -383,7 +390,7 @@ public function appendImmutable($value, $key = null): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function asort(int $sort_flags = 0): self @@ -407,7 +414,7 @@ public function asort(int $sort_flags = 0): self * @return $this *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function asortImmutable(int $sort_flags = 0): self @@ -465,6 +472,10 @@ public function asortImmutable(int $sort_flags = 0): self */ public function count(int $mode = \COUNT_NORMAL): int { + if ($mode !== \COUNT_NORMAL && $mode !== \COUNT_RECURSIVE) { + throw new \ValueError('count(): Argument #2 ($mode) must be either COUNT_NORMAL or COUNT_RECURSIVE'); + } + if ( $this->generator && @@ -491,7 +502,7 @@ public function count(int $mode = \COUNT_NORMAL): int * * @return array * - * @phpstan-param T|array|self $data + * @phpstan-param T|array|self $data * @phpstan-return array */ public function exchangeArray($data): array @@ -585,7 +596,7 @@ public function getIteratorClass(): string * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function ksort(int $sort_flags = 0): self @@ -609,7 +620,7 @@ public function ksort(int $sort_flags = 0): self * @return $this *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function ksortImmutable(int $sort_flags = 0): self { @@ -629,7 +640,7 @@ public function ksortImmutable(int $sort_flags = 0): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function natcasesort(): self @@ -647,7 +658,7 @@ public function natcasesort(): self * @return $this *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function natcasesortImmutable(): self @@ -668,7 +679,7 @@ public function natcasesortImmutable(): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function natsort(): self @@ -686,7 +697,7 @@ public function natsort(): self * @return $this *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function natsortImmutable(): self @@ -738,22 +749,20 @@ public function offsetExists($offset): bool \strpos($offset, $this->pathSeparator) !== false ) { $explodedPath = \explode($this->pathSeparator, (string) $offset); - if ($explodedPath !== false) { - /** @var string $lastOffset - helper for phpstan */ - $lastOffset = \array_pop($explodedPath); - $containerPath = \implode($this->pathSeparator, $explodedPath); + /** @var string $lastOffset - helper for phpstan */ + $lastOffset = \array_pop($explodedPath); + $containerPath = \implode($this->pathSeparator, $explodedPath); - /** - * @psalm-suppress MissingClosureReturnType - * @psalm-suppress MissingClosureParamType - */ - $this->callAtPath( - $containerPath, - static function ($container) use ($lastOffset, &$offsetExists) { - $offsetExists = \array_key_exists($lastOffset, $container); - } - ); - } + /** + * @psalm-suppress MissingClosureReturnType + * @psalm-suppress MissingClosureParamType + */ + $this->callAtPath( + $containerPath, + static function ($container) use ($lastOffset, &$offsetExists) { + $offsetExists = \array_key_exists($lastOffset, $container); + } + ); } return $offsetExists; @@ -767,7 +776,9 @@ static function ($container) use ($lastOffset, &$offsetExists) { * @return mixed *

Will return null if the offset did not exists.

* - * @phpstan-param TKey $offset + * @template TOffset of key-of + * @phpstan-param TOffset $offset + * @phpstan-return TData[TOffset]|null */ #[\ReturnTypeWillChange] public function &offsetGet($offset) @@ -847,25 +858,22 @@ public function offsetUnset($offset) \strpos($offset, $this->pathSeparator) !== false ) { $path = \explode($this->pathSeparator, (string) $offset); + $pathToUnset = \array_pop($path); - if ($path !== false) { - $pathToUnset = \array_pop($path); - - /** - * @psalm-suppress MissingClosureReturnType - * @psalm-suppress MissingClosureParamType - */ - $this->callAtPath( - \implode($this->pathSeparator, $path), - static function (&$offset) use ($pathToUnset) { - if (\is_array($offset)) { - unset($offset[$pathToUnset]); - } else { - $offset = null; - } + /** + * @psalm-suppress MissingClosureReturnType + * @psalm-suppress MissingClosureParamType + */ + $this->callAtPath( + \implode($this->pathSeparator, $path), + static function (&$offset) use ($pathToUnset) { + if (\is_array($offset)) { + unset($offset[$pathToUnset]); + } else { + $offset = null; } - ); - } + } + ); } unset($this->array[$offset]); @@ -884,10 +892,6 @@ public function serialize(): string { $this->generatorToArray(); - if (\PHP_VERSION_ID < 70400) { - return parent::serialize(); - } - return \serialize($this); } @@ -938,15 +942,11 @@ public function setIteratorClass($iteratorClass) *

(Mutable) Return this Arrayy object.

* * @phpstan-param callable(T,T):int $callable - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function uasort($callable): self { - if (!\is_callable($callable)) { - throw new \InvalidArgumentException('Passed function must be callable'); - } - $this->generatorToArray(); \uasort($this->array, $callable); @@ -965,7 +965,7 @@ public function uasort($callable): self *

(Immutable) Return this Arrayy object.

* * @phpstan-param callable(T,T):int $callable - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function uasortImmutable($callable): self @@ -991,7 +991,7 @@ public function uasortImmutable($callable): self *

(Mutable) Return this Arrayy object.

* * @phpstan-param callable(TKey,TKey):int $callable - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function uksort($callable): self @@ -1010,7 +1010,7 @@ public function uksort($callable): self *

(Immutable) Return this Arrayy object.

* * @phpstan-param callable(TKey,TKey):int $callable - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function uksortImmutable($callable): self @@ -1030,17 +1030,11 @@ public function uksortImmutable($callable): self * * @return $this * - * @phpstan-return static + * @phpstan-return static */ #[\ReturnTypeWillChange] public function unserialize($string): self { - if (\PHP_VERSION_ID < 70400) { - parent::unserialize($string); - - return $this; - } - return \unserialize($string, ['allowed_classes' => [__CLASS__, TypeCheckPhpDoc::class]]); } @@ -1059,7 +1053,7 @@ public function unserialize($string): self * * @phpstan-param array $values * @phpstan-param TKey|null $key - * @phpstan-return static + * @phpstan-return static */ public function appendArrayValues(array $values, $key = null) { @@ -1096,7 +1090,7 @@ public function appendArrayValues(array $values, $key = null) * @return static *

(Immutable) Return an Arrayy object, with the prefixed keys.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function appendToEachKey($prefix): self @@ -1131,7 +1125,7 @@ public function appendToEachKey($prefix): self * @return static *

(Immutable) Return an Arrayy object, with the prefixed values.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function appendToEachValue($prefix): self @@ -1160,7 +1154,7 @@ public function appendToEachValue($prefix): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function arsort(): self { @@ -1177,7 +1171,7 @@ public function arsort(): self * @return $this *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function arsortImmutable(): self @@ -1208,7 +1202,7 @@ public function arsortImmutable(): self *

(Immutable)

* * @phpstan-param \Closure(T,TKey):mixed $closure

INFO: \Closure result is not used, but void is not supported in PHP 7.0

- * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function at(\Closure $closure): self @@ -1279,7 +1273,7 @@ public function average($decimals = 0) * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function changeKeyCase(int $case = \CASE_LOWER): self @@ -1328,7 +1322,7 @@ public function changeKeyCase(int $case = \CASE_LOWER): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function changeSeparator($separator): self { @@ -1350,7 +1344,7 @@ public function changeSeparator($separator): self * @return static|static[] *

(Immutable) A new array of chunks from the original array.

* - * @phpstan-return static> + * @phpstan-return static * @psalm-mutation-free */ public function chunk($size, $preserveKeys = false): self @@ -1414,7 +1408,7 @@ public function chunk($size, $preserveKeys = false): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function clean(): self @@ -1438,7 +1432,7 @@ static function ($value) { * @return $this *

(Mutable) Return this Arrayy object, with an empty array.

* - * @phpstan-return static + * @phpstan-return static */ public function clear($key = null): self { @@ -1737,12 +1731,12 @@ public function containsValues(array $needles): bool * keys and their count as value. *

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function countValues(): self { - /** @phpstan-var static $return - help for phpstan */ + /** @phpstan-var static $return - help for phpstan */ $return = self::create(\array_count_values($this->toArray()), $this->iteratorClass); return $return; @@ -1759,7 +1753,7 @@ public function countValues(): self *

(Immutable) Returns an new instance of the Arrayy object.

* * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function create( @@ -1767,11 +1761,14 @@ public static function create( string $iteratorClass = ArrayyIterator::class, bool $checkPropertiesInConstructor = true ) { - return new static( // @phpstan-ignore new.static + /** @var static $instance */ + $instance = new static( // @phpstan-ignore new.static $data, $iteratorClass, $checkPropertiesInConstructor ); + + return $instance; } /** @@ -1789,6 +1786,9 @@ public static function create( * @param array|null $items * * @return array + * + * @phpstan-param array|null $items + * @phpstan-return array */ public function flatten($delimiter = '.', $prepend = '', $items = null) { @@ -1823,7 +1823,7 @@ public function flatten($delimiter = '.', $prepend = '', $items = null) *

(Mutable) Return this Arrayy object.

* * @phpstan-param array $array - * @phpstan-return $this + * @phpstan-return $this * * @internal this will not check any types because it's set directly as reference */ @@ -1844,7 +1844,7 @@ public function createByReference(array &$array = []): self *

(Immutable) Returns an new instance of the Arrayy object.

* * @phpstan-param callable():\Generator $generatorFunction - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromGeneratorFunction(callable $generatorFunction): self @@ -1861,7 +1861,7 @@ public static function createFromGeneratorFunction(callable $generatorFunction): *

(Immutable) Returns an new instance of the Arrayy object.

* * @phpstan-param \Generator $generator - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromGeneratorImmutable(\Generator $generator): self @@ -1877,7 +1877,7 @@ public static function createFromGeneratorImmutable(\Generator $generator): self * @return static *

(Immutable) Returns an new instance of the Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromJson(string $json): self @@ -1894,7 +1894,7 @@ public static function createFromJson(string $json): self *

(Immutable) Returns an new instance of the Arrayy object.

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromArray(array $array): self @@ -1911,7 +1911,7 @@ public static function createFromArray(array $array): self *

(Immutable) Returns an new instance of the Arrayy object.

* * @phpstan-param \Traversable $object - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromObject(\Traversable $object): self @@ -1943,7 +1943,7 @@ public static function createFromObject(\Traversable $object): self * @return static *

(Immutable) Returns an new instance of the Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromObjectVars($object): self @@ -1962,7 +1962,7 @@ public static function createFromObjectVars($object): self * @return static *

(Immutable) Returns an new instance of the Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromString(string $str, ?string $delimiter = null, ?string $regEx = null): self @@ -1995,7 +1995,7 @@ static function (&$val) { } ); - /** @var static $return - help for phpstan */ + /** @var static $return - help for phpstan */ $return = static::create($array); return $return; @@ -2013,7 +2013,7 @@ static function (&$val) { *

(Immutable) Returns an new instance of the Arrayy object.

* * @phpstan-param \Traversable $traversable - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createFromTraversableImmutable(\Traversable $traversable, bool $use_keys = true): self @@ -2031,12 +2031,12 @@ public static function createFromTraversableImmutable(\Traversable $traversable, * @return static *

(Immutable) Returns an new instance of the Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public static function createWithRange($low, $high, $step = 1): self { - /** @phpstan-var static $return - help for phpstan */ + /** @phpstan-var static $return - help for phpstan */ $return = static::create(\range($low, $high, $step)); return $return; @@ -2082,7 +2082,7 @@ public function current() *

(Mutable) Return this Arrayy object.

* * @phpstan-param callable(TKey,TKey):int $callable - * @phpstan-return static + * @phpstan-return static */ public function customSortKeys(callable $callable): self { @@ -2106,7 +2106,7 @@ public function customSortKeys(callable $callable): self *

(Immutable) Return this Arrayy object.

* * @phpstan-param callable(TKey,TKey):int $callable - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function customSortKeysImmutable(callable $callable): self @@ -2145,7 +2145,7 @@ public function customSortKeysImmutable(callable $callable): self *

(Mutable) Return this Arrayy object.

* * @phpstan-param callable(T,T):int $callable - * @phpstan-return static + * @phpstan-return static */ public function customSortValues(callable $callable): self { @@ -2169,7 +2169,7 @@ public function customSortValues(callable $callable): self *

(Immutable) Return this Arrayy object.

* * @phpstan-param callable(T,T):int $callable - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function customSortValuesImmutable($callable): self @@ -2213,7 +2213,7 @@ public function delete($keyOrKeys) *

(Immutable)

* * @phpstan-param array ...$array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function diff(array ...$array): self @@ -2248,7 +2248,7 @@ public function diff(array ...$array): self *

(Immutable)

* * @phpstan-param array ...$array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function diffKey(array ...$array): self @@ -2283,7 +2283,7 @@ public function diffKey(array ...$array): self *

(Immutable)

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function diffKeyAndValue(array ...$array): self @@ -2330,7 +2330,7 @@ public function diffKeyAndValue(array ...$array): self * * @phpstan-param array $array * @phpstan-param null|array|\Generator $helperVariableForRecursion - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self @@ -2382,7 +2382,7 @@ public function diffRecursive(array $array = [], $helperVariableForRecursion = n *

(Immutable)

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function diffReverse(array $array = []): self @@ -2404,7 +2404,7 @@ public function diffReverse(array $array = []): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function divide(): self @@ -2436,7 +2436,7 @@ public function divide(): self *

(Immutable)

* * @phpstan-param \Closure(T,?TKey):T $closure - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function each(\Closure $closure): self @@ -2529,7 +2529,7 @@ public function exists(\Closure $closure): bool *

(Immutable)

* * @phpstan-param T $default - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function fillWithDefaults(int $num, $default = null): self @@ -2593,7 +2593,7 @@ public function fillWithDefaults(int $num, $default = null): self *

(Immutable)

* * @phpstan-param null|(\Closure(T,TKey=):bool)|(\Closure(T):bool)|(\Closure(TKey):bool) $closure - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH) @@ -2662,8 +2662,8 @@ public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH) * @return static *

(Immutable)

* - * @phpstan-param array|T $value - * @phpstan-return static + * @phpstan-param array|T $value + * @phpstan-return static * @psalm-mutation-free * * @psalm-suppress MissingClosureReturnType @@ -2820,8 +2820,8 @@ public function findKey(\Closure $closure) * @return static *

(Immutable)

* - * @phpstan-param array|T $value - * @phpstan-return static + * @phpstan-param array|T $value + * @phpstan-return static * @psalm-mutation-free */ public function findBy(string $property, $value, string $comparisonOp = 'eq'): self @@ -2885,7 +2885,7 @@ public function firstKey() * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function firstsImmutable(?int $number = null): self @@ -2914,7 +2914,7 @@ public function firstsImmutable(?int $number = null): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function firstsKeys(?int $number = null): self @@ -2947,7 +2947,7 @@ public function firstsKeys(?int $number = null): self * @return $this *

(Mutable)

* - * @phpstan-return ($number is null ? static : static) + * @phpstan-return ($number is null ? static : static) */ public function firstsMutable(?int $number = null): self { @@ -2955,7 +2955,7 @@ public function firstsMutable(?int $number = null): self if ($number === null) { $shift = \array_shift($this->array); - /* @phpstan-ignore-next-line | I am not sure if "array" is an error here? */ + /* @phpstan-ignore assign.propertyType */ $this->array = $shift !== null ? [$shift] : []; } else { $splice = \array_splice($this->array, 0, $number); @@ -2975,7 +2975,7 @@ public function firstsMutable(?int $number = null): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function flip(): self @@ -3062,7 +3062,7 @@ public function get( } // php cast "bool"-index into "int"-index - /* @phpstan-ignore-next-line | this is only a fallback */ + /* @phpstan-ignore identical.alwaysFalse */ if ((bool) $key === $key) { $key = (int) $key; } @@ -3089,88 +3089,80 @@ public function get( \strpos($key, $this->pathSeparator) !== false ) { $segments = \explode($this->pathSeparator, (string) $key); - if ($segments !== false) { - $usePath = true; - $usedArrayTmp = $usedArray; // do not use the reference for dot-annotations + $usePath = true; + $usedArrayTmp = $usedArray; // do not use the reference for dot-annotations - foreach ($segments as $segment) { - if ( - ( - \is_array($usedArrayTmp) - || - $usedArrayTmp instanceof \ArrayAccess - ) - && - isset($usedArrayTmp[$segment]) - ) { - $usedArrayTmp = $usedArrayTmp[$segment]; + foreach ($segments as $segment) { + if ( + ( + \is_array($usedArrayTmp) + || + $usedArrayTmp instanceof \ArrayAccess + ) + && + isset($usedArrayTmp[$segment]) + ) { + $usedArrayTmp = $usedArrayTmp[$segment]; - continue; - } + continue; + } - if ( - \is_object($usedArrayTmp) === true - && - \property_exists($usedArrayTmp, $segment) - ) { - $usedArrayTmp = $usedArrayTmp->{$segment}; + if ( + \is_object($usedArrayTmp) === true + && + \property_exists($usedArrayTmp, $segment) + ) { + $usedArrayTmp = $usedArrayTmp->{$segment}; - continue; - } + continue; + } - if (isset($segments[0]) && $segments[0] === '*') { - $segmentsTmp = $segments; - unset($segmentsTmp[0]); - $keyTmp = \implode('.', $segmentsTmp); - $returnTmp = static::create( - [], - $this->iteratorClass, - false - ); - foreach ($this->getAll() as $dataTmp) { - if ($dataTmp instanceof self) { - $returnTmp->add($dataTmp->get($keyTmp)); - - continue; - } + if ($segments[0] === '*') { + $segmentsTmp = $segments; + unset($segmentsTmp[0]); + $keyTmp = \implode('.', $segmentsTmp); + $returnTmp = static::create( + [], + $this->iteratorClass, + false + ); + foreach ($this->getAll() as $dataTmp) { + if ($dataTmp instanceof self) { + $returnTmp->add($dataTmp->get($keyTmp)); - if ( - ( - \is_array($dataTmp) - || - $dataTmp instanceof \ArrayAccess - ) - && - isset($dataTmp[$keyTmp]) - ) { - $returnTmp->add($dataTmp[$keyTmp]); - - continue; - } + continue; + } - if ( - \is_object($dataTmp) === true - && - \property_exists($dataTmp, $keyTmp) - ) { - $returnTmp->add($dataTmp->{$keyTmp}); + if ( + ( + \is_array($dataTmp) + || + $dataTmp instanceof \ArrayAccess + ) + && + isset($dataTmp[$keyTmp]) + ) { + $returnTmp->add($dataTmp[$keyTmp]); - continue; - } + continue; } - if ($returnTmp->count() > 0) { - return $returnTmp; + if ( + \is_object($dataTmp) === true + && + \property_exists($dataTmp, $keyTmp) + ) { + $returnTmp->add($dataTmp->{$keyTmp}); + + continue; } } - return $fallback instanceof \Closure ? $fallback() : $fallback; + if ($returnTmp->count() > 0) { + return $returnTmp; + } } - } - } - if (isset($usedArrayTmp)) { - if (!$usePath && !isset($usedArrayTmp[$key])) { return $fallback instanceof \Closure ? $fallback() : $fallback; } @@ -3185,7 +3177,7 @@ public function get( return $usedArrayTmp; } - if (!$usePath && !isset($usedArray[$key])) { + if (!isset($usedArray[$key])) { return $fallback instanceof \Closure ? $fallback() : $fallback; } @@ -3246,8 +3238,8 @@ public function getArray( /** * Create an instance from JSON using the built-in mapper. * - * For Arrayy models with property checks enabled, both phpdoc `@property` - * definitions and native declared properties are used for metadata and type checks. + * For Arrayy models with property checks enabled, phpdoc array-shape annotations, + * legacy `@property` definitions, and native declared properties are used for metadata and type checks. * Add a property-level `@var` annotation if a native `array` property also needs * element-type validation. * @@ -3328,7 +3320,7 @@ public function getList(bool $convertAllArrayyElements = false): array * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function getColumn($columnKey = null, $indexKey = null): self @@ -3456,7 +3448,7 @@ public function getBackwardsGenerator(): \Generator * * @see Arrayy::keys() * - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function getKeys() @@ -3482,7 +3474,7 @@ public function getObject(): \stdClass * * @see Arrayy::randomImmutable() * - * @phpstan-return static + * @phpstan-return static */ public function getRandom(): self { @@ -3514,7 +3506,7 @@ public function getRandomKey() * * @see Arrayy::randomKeys() * - * @phpstan-return static + * @phpstan-return static */ public function getRandomKeys(int $number): self { @@ -3546,7 +3538,7 @@ public function getRandomValue() * * @see Arrayy::randomValues() * - * @phpstan-return static + * @phpstan-return static */ public function getRandomValues(int $number): self { @@ -3560,7 +3552,7 @@ public function getRandomValues(int $number): self *

The values of all elements in this array, in the order they * appear in the array.

* - * @phpstan-return static + * @phpstan-return static */ public function getValues() { @@ -3597,7 +3589,7 @@ public function getValuesYield(): \Generator *

(Immutable)

* * @phpstan-param \Closure(T,TKey):TKey|TKey $grouper - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function group($grouper, bool $saveKeys = false): self @@ -3736,7 +3728,7 @@ public function implodeKeys(string $glue = ''): string *

(Immutable)

* * @phpstan-param array-key $key - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function indexBy($key): self @@ -3787,7 +3779,7 @@ public function indexOf($value) * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function initial(int $to = 1): self @@ -3809,7 +3801,7 @@ public function initial(int $to = 1): self *

(Immutable)

* * @phpstan-param array $search - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function intersection(array $search, bool $keepKeys = false): self @@ -3848,7 +3840,7 @@ static function ($a, $b) { *

(Immutable)

* * @phpstan-param array> ...$array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function intersectionMulti(...$array): self @@ -3888,7 +3880,7 @@ public function intersects(array $search): bool *

(Immutable)

* * @phpstan-param callable(T,mixed=):mixed $callable - * @phpstan-return static|static + * @phpstan-return static|static * @psalm-mutation-free */ public function invoke($callable, $arguments = []): self @@ -4144,7 +4136,7 @@ public function keyExists($key): bool *

(Immutable) An array of all the keys in input.

* * @phpstan-param null|T|T[] $search_values - * @phpstan-return static + * @phpstan-return static * * @psalm-mutation-free */ @@ -4231,7 +4223,7 @@ public function keys( * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function krsort(int $sort_flags = 0): self { @@ -4254,7 +4246,7 @@ public function krsort(int $sort_flags = 0): self * @return $this *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function krsortImmutable(int $sort_flags = 0): self @@ -4323,7 +4315,7 @@ public function lastKey() * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function lastsImmutable(?int $number = null): self @@ -4369,7 +4361,7 @@ public function lastsImmutable(?int $number = null): self * @return $this *

(Mutable)

* - * @phpstan-return static + * @phpstan-return static */ public function lastsMutable(?int $number = null): self { @@ -4418,7 +4410,7 @@ public function length(int $mode = \COUNT_NORMAL): int *

The output value type.

* * @phpstan-param callable(T,TKey=,mixed=):T2 $callable - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function map( @@ -4574,7 +4566,7 @@ public function max() *

(Immutable)

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function mergeAppendKeepIndex(array $array = [], bool $recursive = false): self @@ -4616,7 +4608,7 @@ public function mergeAppendKeepIndex(array $array = [], bool $recursive = false) *

(Immutable)

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function mergeAppendNewIndex(array $array = [], bool $recursive = false): self @@ -4657,7 +4649,7 @@ public function mergeAppendNewIndex(array $array = [], bool $recursive = false): *

(Immutable)

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function mergePrependKeepIndex(array $array = [], bool $recursive = false): self @@ -4699,7 +4691,7 @@ public function mergePrependKeepIndex(array $array = [], bool $recursive = false *

(Immutable)

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function mergePrependNewIndex(array $array = [], bool $recursive = false): self @@ -4719,8 +4711,8 @@ public function mergePrependNewIndex(array $array = [], bool $recursive = false) } /** - * Return a meta object with property names from phpdoc `@property` tags and - * native declared properties. + * Return a meta object with property names from phpdoc array-shape annotations, + * `@property` tags, and native declared properties. * * @return ArrayyMeta|mixed|static */ @@ -4773,7 +4765,7 @@ public function min() */ public function mostUsedValue() { - /* @phpstan-ignore-next-line | false-positive? maybe because we switch key-value via "countValues"? */ + /* @phpstan-ignore return.type */ return $this->countValues()->arsortImmutable()->firstKey(); } @@ -4785,7 +4777,7 @@ public function mostUsedValue() * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function mostUsedValues(?int $number = null): self @@ -4807,7 +4799,7 @@ public function mostUsedValues(?int $number = null): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function moveElement($from, $to): self @@ -4855,7 +4847,7 @@ public function moveElement($from, $to): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function moveElementToFirstPlace($key): self @@ -4886,7 +4878,7 @@ public function moveElementToFirstPlace($key): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function moveElementToLastPlace($key): self @@ -4934,7 +4926,7 @@ public function next() * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function nth(int $step, int $offset = 0): self @@ -4966,7 +4958,7 @@ public function nth(int $step, int $offset = 0): self *

(Immutable)

* * @phpstan-param array-key[] $keys - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function only(array $keys): self @@ -4997,7 +4989,7 @@ public function only(array $keys): self * @return static *

(Immutable) Arrayy object padded to $size with $value.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function pad(int $size, $value): self @@ -5022,7 +5014,7 @@ public function pad(int $size, $value): self * contains the array of elements where the predicate returned FALSE.

* * @phpstan-param \Closure(T,TKey):bool $closure - * @phpstan-return array> + * @phpstan-return array */ public function partition(\Closure $closure): array { @@ -5071,7 +5063,7 @@ public function pop() * * @phpstan-param T $value * @phpstan-param TKey|null $key - * @phpstan-return static + * @phpstan-return static */ public function prepend($value, $key = null) { @@ -5105,7 +5097,7 @@ public function prepend($value, $key = null) * * @phpstan-param T $value * @phpstan-param TKey $key - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function prependImmutable($value, $key = null) @@ -5141,7 +5133,7 @@ public function prependImmutable($value, $key = null) * @return static *

(Immutable) Return an Arrayy object, with the prepended keys.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function prependToEachKey($suffix): self @@ -5179,7 +5171,7 @@ public function prependToEachKey($suffix): self * @return static *

(Immutable) Return an Arrayy object, with the prepended values.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function prependToEachValue($suffix): self @@ -5259,7 +5251,7 @@ public function pull($keyOrKeys = null, $fallback = null) * @noinspection ReturnTypeCanBeDeclaredInspection * * @phpstan-param array ...$args - * @phpstan-return static + * @phpstan-return static */ public function push(...$args) { @@ -5292,7 +5284,7 @@ public function push(...$args) * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static */ public function randomImmutable(?int $number = null): self { @@ -5366,7 +5358,7 @@ public function randomKey() * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static */ public function randomKeys(int $number): self { @@ -5409,7 +5401,7 @@ public function randomKeys(int $number): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function randomMutable(?int $number = null): self { @@ -5470,7 +5462,7 @@ public function randomValue() * @return static *

(Mutable)

* - * @phpstan-return static + * @phpstan-return static */ public function randomValues(int $number): self { @@ -5487,11 +5479,11 @@ public function randomValues(int $number): self * @param array $array * @param int|null $number

How many values you will take?

* - * @return static + * @return static *

(Immutable)

* * @phpstan-param array<(int&T)|(string&T),int> $array - * @phpstan-return static + * @phpstan-return static */ public function randomWeighted(array $array, ?int $number = null): self { @@ -5499,7 +5491,6 @@ public function randomWeighted(array $array, ?int $number = null): self $options = []; foreach ($array as $option => $weight) { - /** @phpstan-var T $option - hack: we protect this method via (int&T)|(string&T) */ if ($this->searchIndex($option) !== false) { for ($i = 0; $i < $weight; ++$i) { $options[] = $option; @@ -5534,7 +5525,7 @@ public function randomWeighted(array $array, ?int $number = null): self * @phpstan-param callable(T2, T, TKey): T2 $callable * @phpstan-param T2 $initial * - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function reduce($callable, $initial = []): self @@ -5543,7 +5534,7 @@ public function reduce($callable, $initial = []): self $initial = $callable($initial, $value, $key); } - /** @var static $return - help for phpstan */ + /** @var static $return - help for phpstan */ $return = static::create( $initial, $this->iteratorClass, @@ -5559,7 +5550,7 @@ public function reduce($callable, $initial = []): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function reduce_dimension(bool $unique = true): self @@ -5596,7 +5587,7 @@ public function reduce_dimension(bool $unique = true): self * @return $this *

(Mutable) Return this Arrayy object, with re-indexed array-elements.

* - * @phpstan-return static + * @phpstan-return static */ public function reindex(): self { @@ -5623,7 +5614,7 @@ public function reindex(): self *

(Immutable)

* * @phpstan-param \Closure(T,TKey):bool $closure - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function reject(\Closure $closure): self @@ -5657,7 +5648,7 @@ public function reject(\Closure $closure): self *

(Mutable)

* * @phpstan-param TKey|TKey[] $key - * @phpstan-return static + * @phpstan-return static */ public function remove($key) { @@ -5692,7 +5683,7 @@ public function remove($key) *

(Immutable)

* * @phpstan-param T $element - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function removeElement($element) @@ -5710,7 +5701,7 @@ public function removeElement($element) * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function removeFirst(): self @@ -5736,7 +5727,7 @@ public function removeFirst(): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function removeLast(): self @@ -5765,7 +5756,7 @@ public function removeLast(): self *

(Immutable)

* * @phpstan-param T $value - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function removeValue($value): self @@ -5800,7 +5791,7 @@ public function removeValue($value): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function repeat($times): self @@ -5834,7 +5825,7 @@ public function repeat($times): self * @phpstan-param TKey $oldKey * @phpstan-param TKey $newKey * @phpstan-param T $newValue - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function replace($oldKey, $newKey, $newValue): self @@ -5874,13 +5865,13 @@ public function replace($oldKey, $newKey, $newValue): self *

* * @phpstan-param array $keys - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function replaceAllKeys(array $keys): self { $data = \array_combine($keys, $this->toArray()); - /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */ + /* @phpstan-ignore identical.alwaysFalse */ if ($data === false) { $data = []; } @@ -5918,13 +5909,13 @@ public function replaceAllKeys(array $keys): self *

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function replaceAllValues(array $array): self { $data = \array_combine($this->toArray(), $array); - /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */ + /* @phpstan-ignore identical.alwaysFalse */ if ($data === false) { $data = []; } @@ -5949,14 +5940,14 @@ public function replaceAllValues(array $array): self *

(Immutable)

* * @phpstan-param array $keys - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function replaceKeys(array $keys): self { $values = \array_values($this->toArray()); $result = \array_combine($keys, $values); - /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */ + /* @phpstan-ignore identical.alwaysFalse */ if ($result === false) { $result = []; } @@ -5984,7 +5975,7 @@ public function replaceKeys(array $keys): self * * @phpstan-param T $search * @phpstan-param T $replacement - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function replaceOneValue($search, $replacement = ''): self @@ -6017,7 +6008,7 @@ public function replaceOneValue($search, $replacement = ''): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function replaceValues($search, $replacement = ''): self @@ -6026,7 +6017,7 @@ public function replaceValues($search, $replacement = ''): self return \str_replace($search, $replacement, $value); }; - /* @phpstan-ignore-next-line | ignore Closure with one or two parameters, is this a bug in phpstan? */ + /* @phpstan-ignore argument.type */ return $this->each($callable); } @@ -6042,7 +6033,7 @@ public function replaceValues($search, $replacement = ''): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function rest(int $from = 1): self @@ -6066,7 +6057,7 @@ public function rest(int $from = 1): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function reverse(): self { @@ -6087,7 +6078,7 @@ public function reverse(): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function reverseKeepIndex(): self { @@ -6110,7 +6101,7 @@ public function reverseKeepIndex(): self * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function rsort(int $sort_flags = 0): self { @@ -6133,7 +6124,7 @@ public function rsort(int $sort_flags = 0): self * @return $this *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function rsortImmutable(int $sort_flags = 0): self @@ -6189,7 +6180,7 @@ public function searchIndex($value) *

(Immutable) Will return a empty Arrayy if the value wasn't found.

* * @phpstan-param TKey $index - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function searchValue($index): self @@ -6208,7 +6199,7 @@ public function searchValue($index): self } // php cast "bool"-index into "int"-index - /* @phpstan-ignore-next-line | array-key helper */ + /* @phpstan-ignore identical.alwaysFalse */ if ((bool) $index === $index) { $index = (int) $index; } @@ -6240,7 +6231,7 @@ public function searchValue($index): self * * @phpstan-param TKey $key * @phpstan-param T $value - * @phpstan-return static + * @phpstan-return static */ public function set($key, $value): self { @@ -6310,7 +6301,7 @@ public function shift() *

(Immutable)

* * @phpstan-param array $array - * @phpstan-return static + * @phpstan-return static */ public function shuffle(bool $secure = false, ?array $array = null): self { @@ -6515,7 +6506,7 @@ public function sizeRecursive(): int * @return static *

(Immutable) A slice of the original array with length $length.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function slice(int $offset, ?int $length = null, bool $preserveKeys = false) @@ -6549,7 +6540,7 @@ public function slice(int $offset, ?int $length = null, bool $preserveKeys = fal * @return static *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function sort( $direction = \SORT_ASC, @@ -6577,7 +6568,7 @@ public function sort( * @return static *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function sortImmutable( $direction = \SORT_ASC, @@ -6613,7 +6604,7 @@ public function sortImmutable( * @return $this *

(Mutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static */ public function sortKeys( $direction = \SORT_ASC, @@ -6639,7 +6630,7 @@ public function sortKeys( * @return $this *

(Immutable) Return this Arrayy object.

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function sortKeysImmutable( @@ -6670,7 +6661,7 @@ public function sortKeysImmutable( * @return static *

(Mutable)

* - * @phpstan-return static + * @phpstan-return static */ public function sortValueKeepIndex( $direction = \SORT_ASC, @@ -6693,7 +6684,7 @@ public function sortValueKeepIndex( * @return static *

(Mutable)

* - * @phpstan-return static + * @phpstan-return static */ public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self { @@ -6726,7 +6717,7 @@ public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_ *

(Immutable)

* * @pslam-param callable|T|null $sorter - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self @@ -6780,7 +6771,7 @@ static function ($value) use ($sorter) { *

(Immutable)

* * @phpstan-param array $replacement - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function splice(int $offset, ?int $length = null, $replacement = []): self @@ -6814,7 +6805,7 @@ public function splice(int $offset, ?int $length = null, $replacement = []): sel * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function split(int $numberOfPieces = 2, bool $keepKeys = false): self @@ -6884,19 +6875,27 @@ public function split(int $numberOfPieces = 2, bool $keepKeys = false): self * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function stripEmpty(): self { - return $this->filter( - static function ($item) { + $generator = function () { + foreach ($this->getGenerator() as $key => $item) { if ($item === null) { - return false; + continue; } - return (bool) \trim((string) $item); + if ((bool) \trim((string) $item)) { + yield $key => $item; + } } + }; + + return static::create( + $generator(), + $this->iteratorClass, + false ); } @@ -6913,7 +6912,7 @@ static function ($item) { * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function swap($swapA, $swapB): self @@ -6969,7 +6968,7 @@ public function toArray( } } - /* @phpstan-ignore-next-line - depends on the $convertAllArrayyElements parameter :/ */ + /* @phpstan-ignore return.type */ return $array; } @@ -7029,7 +7028,7 @@ public function toJson(int $options = 0, int $depth = 512): string * * @return static|static[] * - * @phpstan-return static> + * @phpstan-return static */ public function toPermutation(?array $items = null, array $helper = []): self { @@ -7058,7 +7057,7 @@ public function toPermutation(?array $items = null, array $helper = []): self } } - /** @var static> $return - help for phpstan */ + /** @var static $return - help for phpstan */ $return = static::create( $return, $this->iteratorClass, @@ -7091,7 +7090,7 @@ public function toString(string $separator = ','): string * @return $this *

(Mutable)

* - * @phpstan-return static + * @phpstan-return static */ public function uniqueNewIndex(): self { @@ -7122,7 +7121,7 @@ static function ($resultArray, $value, $key) { * @return $this *

(Mutable)

* - * @phpstan-return static + * @phpstan-return static */ public function uniqueKeepIndex(): self { @@ -7159,7 +7158,7 @@ static function ($resultArray, $key) use ($array) { * * @see Arrayy::unique() * - * @phpstan-return static + * @phpstan-return static */ public function unique(): self { @@ -7175,7 +7174,7 @@ public function unique(): self *

(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.

* * @phpstan-param array ...$args - * @phpstan-return static + * @phpstan-return static */ public function unshift(...$args): self { @@ -7228,7 +7227,7 @@ public function validate(\Closure $closure): bool * @return static *

(Immutable)

* - * @phpstan-return static + * @phpstan-return static * @psalm-mutation-free */ public function values(): self @@ -7272,7 +7271,7 @@ function () { * * @phostan-param TExtra $userData * @phpstan-param callable(T,TKey,?TExtra):void $callable - * @phpstan-return static + * @phpstan-return static */ public function walk( $callable, @@ -7292,7 +7291,7 @@ public function walk( if ($userData !== self::ARRAYY_HELPER_WALK) { \array_walk($this->array, $callable, $userData); } else { - /* @phpstan-ignore-next-line | callback with no arguments is ok here */ + /* @phpstan-ignore argument.type */ \array_walk($this->array, $callable); } } @@ -7313,7 +7312,7 @@ public function walk( * * @return static * - * @phpstan-return static + * @phpstan-return static */ public function where(string $keyOrPropertyOrMethod, $value): self { @@ -7462,7 +7461,7 @@ protected function callAtPath($path, $callable, &$currentOffset = null) } $explodedPath = \explode($this->pathSeparator, $path); - /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */ + /* @phpstan-ignore identical.alwaysFalse */ if ($explodedPath === false) { return; } @@ -7486,7 +7485,7 @@ protected function callAtPath($path, $callable, &$currentOffset = null) /** * Extracts the value of the given property or method from the object. * - * @param static $object + * @param static $object *

The object to extract the value from.

* @param string $keyOrPropertyOrMethod *

The property or method for which the @@ -7497,7 +7496,7 @@ protected function callAtPath($path, $callable, &$currentOffset = null) * @return mixed *

The value extracted from the specified property or method.

* - * @phpstan-param self $object + * @phpstan-param self $object */ final protected function extractValue(self $object, string $keyOrPropertyOrMethod) { @@ -7614,34 +7613,25 @@ protected function getDirection($direction): int protected function getPropertiesFromPhpDoc() { static $PROPERTY_CACHE = []; + static $OPTIONAL_PROPERTY_CACHE = []; $cacheKey = 'Class::' . static::class; if (isset($PROPERTY_CACHE[$cacheKey])) { + $this->optionalProperties = $OPTIONAL_PROPERTY_CACHE[$cacheKey] ?? []; + return $PROPERTY_CACHE[$cacheKey]; } $properties = $this->getPropertiesFromNativeDefinitions(); + $optionalProperties = []; + $phpDocPropertyAnnotationStyle = null; $reflector = new \ReflectionClass($this); $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance(); $docComment = $reflector->getDocComment(); if ($docComment) { $docblock = $factory->create($docComment); - /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */ - foreach ($docblock->getTagsByName('property') as $tag) { - $typeName = $tag->getVariableName(); - /** @var string|null $typeName */ - if ( - $typeName !== null - && - isset($properties[$typeName]) === false - ) { - $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName); - if ($typeCheckPhpDoc !== null) { - $properties[$typeName] = $typeCheckPhpDoc; - } - } - } + $this->addPropertiesFromDocBlock($docblock, $properties, $optionalProperties, $phpDocPropertyAnnotationStyle); } /** @noinspection PhpAssignmentInConditionInspection */ @@ -7649,25 +7639,165 @@ protected function getPropertiesFromPhpDoc() $docComment = $reflector->getDocComment(); if ($docComment) { $docblock = $factory->create($docComment); - /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */ - foreach ($docblock->getTagsByName('property') as $tag) { - $typeName = $tag->getVariableName(); - /** @var string|null $typeName */ - if ($typeName !== null) { - if (isset($properties[$typeName])) { - continue; - } + $this->addPropertiesFromDocBlock($docblock, $properties, $optionalProperties, $phpDocPropertyAnnotationStyle); + } + } - $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName); - if ($typeCheckPhpDoc !== null) { - $properties[$typeName] = $typeCheckPhpDoc; - } + $this->optionalProperties = $optionalProperties; + $OPTIONAL_PROPERTY_CACHE[$cacheKey] = $optionalProperties; + + return $PROPERTY_CACHE[$cacheKey] = $properties; + } + + /** + * Merge property definitions from a docblock into the collected property map. + * + * @param \phpDocumentor\Reflection\DocBlock $docblock + * @param TypeCheckInterface[] $properties + * @param array $optionalProperties + * @param 'array-shape'|'property'|null $phpDocPropertyAnnotationStyle + * + * @return void + */ + private function addPropertiesFromDocBlock($docblock, array &$properties, array &$optionalProperties, ?string &$phpDocPropertyAnnotationStyle): void + { + $propertyTags = $docblock->getTagsByName('property'); + $arrayShapeItems = $this->getArrayShapeItemsFromDocBlock($docblock); + + if ($propertyTags !== [] && $arrayShapeItems !== []) { + throw new \TypeError('Use either @property tags or array-shape annotations for Arrayy property definitions, not both.'); + } + + $currentPhpDocPropertyAnnotationStyle = null; + if ($propertyTags !== []) { + $currentPhpDocPropertyAnnotationStyle = 'property'; + } elseif ($arrayShapeItems !== []) { + $currentPhpDocPropertyAnnotationStyle = 'array-shape'; + } + + if ( + $currentPhpDocPropertyAnnotationStyle !== null + && + $phpDocPropertyAnnotationStyle !== null + && + $phpDocPropertyAnnotationStyle !== $currentPhpDocPropertyAnnotationStyle + ) { + throw new \TypeError('Use either @property tags or array-shape annotations for Arrayy property definitions, not both.'); + } + + if ($currentPhpDocPropertyAnnotationStyle !== null) { + $phpDocPropertyAnnotationStyle = $currentPhpDocPropertyAnnotationStyle; + } + + /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */ + foreach ($propertyTags as $tag) { + $typeName = $tag->getVariableName(); + /** @var string|null $typeName */ + if ( + $typeName !== null + && + isset($properties[$typeName]) === false + ) { + $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName); + if ($typeCheckPhpDoc !== null) { + $properties[$typeName] = $typeCheckPhpDoc; + unset($optionalProperties[$typeName]); + } + } + } + + foreach ($arrayShapeItems as $item) { + $typeName = (string) $item->getKey(); + if ($typeName === '') { + continue; + } + + $typeName = \trim($typeName, '\'"'); + if (isset($properties[$typeName])) { + continue; + } + + $typeCheckPhpDoc = TypeCheckPhpDoc::fromDocTypeObject($typeName, $item->getValue()); + $properties[$typeName] = $typeCheckPhpDoc; + if ($item->isOptional()) { + $optionalProperties[$typeName] = true; + } + } + } + + /** + * Extract array-shape items from supported @template and @extends annotations. + * + * @param \phpDocumentor\Reflection\DocBlock $docblock + * + * @return \phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem[] + */ + private function getArrayShapeItemsFromDocBlock($docblock): array + { + if (!\class_exists('\phpDocumentor\Reflection\PseudoTypes\ArrayShape')) { + return []; + } + + $items = []; + foreach ($docblock->getTagsByName('template') as $tag) { + if ( + $tag instanceof \phpDocumentor\Reflection\DocBlock\Tags\Template + && + $tag->getTemplateName() === 'T' + && + $tag->getBound() instanceof \phpDocumentor\Reflection\PseudoTypes\ArrayShape + ) { + foreach ($tag->getBound()->getItems() as $item) { + $items[] = $item; + } + } + } + + foreach ($docblock->getTagsByName('extends') as $tag) { + if (!$tag instanceof \phpDocumentor\Reflection\DocBlock\Tags\Extends_) { + continue; + } + + $type = $tag->getType(); + if ( + !$type instanceof \phpDocumentor\Reflection\PseudoTypes\Generic + || + !$this->isArrayyGenericTarget((string) $type->getFqsen()) + ) { + continue; + } + + foreach ($type->getTypes() as $genericType) { + if ($genericType instanceof \phpDocumentor\Reflection\PseudoTypes\ArrayShape) { + foreach ($genericType->getItems() as $item) { + $items[] = $item; } } } } - return $PROPERTY_CACHE[$cacheKey] = $properties; + return $items; + } + + /** + * Check whether a generic annotation target is Arrayy, ArrayyStrict, or an Arrayy subclass. + * + * @param string $fqcn + * + * @return bool + */ + private function isArrayyGenericTarget(string $fqcn): bool + { + $fqcn = \ltrim($fqcn, '\\'); + if ($fqcn === '') { + return false; + } + + if (\in_array($fqcn, [self::class, ArrayyStrict::class], true)) { + return true; + } + + return \class_exists($fqcn) && \is_a($fqcn, self::class, true); } /** @@ -7768,7 +7898,7 @@ protected function implode_recursive( if ( \is_scalar($pieces) === true || - (\is_object($pieces) && \method_exists($pieces, '__toString')) + $pieces instanceof \Stringable ) { return (string) $pieces; } @@ -7797,7 +7927,7 @@ protected function implode_recursive( * @return bool *

true if needle is found in the array, false otherwise

* - * @phpstan-param (array&T)|array|\Generator|null $haystack + * @phpstan-param array|array|\Generator|null $haystack * * @psalm-mutation-free */ @@ -7903,21 +8033,18 @@ protected function internalRemove($key): bool \strpos($key, $this->pathSeparator) !== false ) { $path = \explode($this->pathSeparator, (string) $key); + // crawl though the keys + while (\count($path, \COUNT_NORMAL) > 1) { + $key = \array_shift($path); - if ($path !== false) { - // crawl though the keys - while (\count($path, \COUNT_NORMAL) > 1) { - $key = \array_shift($path); - - if (!$this->has($key)) { - return false; - } - - $this->array = &$this->array[$key]; + if (!$this->has($key)) { + return false; } - $key = \array_shift($path); + $this->array = &$this->array[$key]; } + + $key = \array_shift($path); } unset($this->array[$key]); @@ -7972,17 +8099,14 @@ protected function internalSet( \strpos($key, $this->pathSeparator) !== false ) { $path = \explode($this->pathSeparator, (string) $key); - - if ($path !== false) { - // crawl through the keys - while (\count($path, \COUNT_NORMAL) > 1) { - $key = \array_shift($path); - - $array = &$array[$key]; - } - + // crawl through the keys + while (\count($path, \COUNT_NORMAL) > 1) { $key = \array_shift($path); + + $array = &$array[$key]; } + + $key = \array_shift($path); } if ($array === null) { @@ -8044,15 +8168,16 @@ protected function setInitialValuesAndProperties(array &$data, bool $checkProper /** @var TypeCheckInterface[] $properties */ $properties = $this->properties; + $requiredProperties = \array_diff_key($properties, $this->optionalProperties); if ( $this->checkPropertiesMismatchInConstructor === true && \count($data) !== 0 && - \count(\array_diff_key($properties, $data)) > 0 + \count(\array_diff_key($requiredProperties, $data)) > 0 ) { - throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($properties), true)); + throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($requiredProperties), true)); } } @@ -8077,7 +8202,7 @@ protected function setInitialValuesAndProperties(array &$data, bool $checkProper *

(Mutable) Return this Arrayy object.

* * @phpstan-param array $elements - * @phpstan-return static + * @phpstan-return static */ protected function sorterKeys( array &$elements, @@ -8112,7 +8237,7 @@ protected function sorterKeys( *

(Mutable) Return this Arrayy object.

* * @phpstan-param array $elements - * @phpstan-return static + * @phpstan-return static */ protected function sorting( array &$elements, @@ -8154,6 +8279,9 @@ protected function sorting( * * @return array * + * @phpstan-param array $array + * @phpstan-return array + * * @psalm-mutation-free */ private function getArrayRecursiveHelperArrayy(array $array) @@ -8194,7 +8322,7 @@ private function checkType($key, $value) && $this->checkPropertiesMismatch === true ) { - throw new \TypeError('The key "' . $key . '" does not exists as "@property" phpdoc. (' . \get_class($this) . ').'); + throw new \TypeError('The key "' . $key . '" does not exist as a property definition. (' . \get_class($this) . ').'); } if (isset($this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES])) { diff --git a/src/ArrayyIterator.php b/src/ArrayyIterator.php index 7b21732..f2b1e22 100644 --- a/src/ArrayyIterator.php +++ b/src/ArrayyIterator.php @@ -14,7 +14,7 @@ class ArrayyIterator extends \ArrayIterator /** * @var string * - * @phpstan-var string|class-string<\Arrayy\Arrayy> + * @phpstan-var string|class-string<\Arrayy\Arrayy>> */ private $class; @@ -55,7 +55,7 @@ public function current() *

Will return a "Arrayy"-object instead of an array.

* * @phpstan-param TKey $offset - * @param-return Arrayy|mixed + * @param-return Arrayy>|mixed */ #[\ReturnTypeWillChange] public function offsetGet($offset) diff --git a/src/ArrayyMeta.php b/src/ArrayyMeta.php index 5b31258..f22093a 100644 --- a/src/ArrayyMeta.php +++ b/src/ArrayyMeta.php @@ -24,7 +24,7 @@ public function __get($name): string * * @return $this * - * @phpstan-param class-string<\Arrayy\Arrayy> $className + * @phpstan-param class-string<\Arrayy\Arrayy>> $className */ public function getMetaObject(string $className): self { @@ -36,7 +36,7 @@ public function getMetaObject(string $className): self } $reflector = new \ReflectionClass($className); - /** @var Arrayy $instance */ + /** @var Arrayy> $instance */ $instance = $reflector->newInstanceWithoutConstructor(); foreach ($instance->getPhpDocPropertiesFromClass() as $propertyName => $_) { $this->{$propertyName} = $propertyName; diff --git a/src/ArrayyRewindableGenerator.php b/src/ArrayyRewindableGenerator.php index cdaadb7..3f97f8a 100644 --- a/src/ArrayyRewindableGenerator.php +++ b/src/ArrayyRewindableGenerator.php @@ -16,7 +16,7 @@ class ArrayyRewindableGenerator extends \ArrayIterator /** * @var string * - * @phpstan-var string|class-string<\Arrayy\Arrayy> + * @phpstan-var string|class-string<\Arrayy\Arrayy>> */ protected $class; diff --git a/src/ArrayyStrict.php b/src/ArrayyStrict.php index 32f1e79..bec2f4a 100644 --- a/src/ArrayyStrict.php +++ b/src/ArrayyStrict.php @@ -12,7 +12,7 @@ * * @template TKey of array-key * @template T - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class ArrayyStrict extends Arrayy implements \Arrayy\Type\TypeInterface { diff --git a/src/Collection/AbstractCollection.php b/src/Collection/AbstractCollection.php index d99057d..58fbcd1 100644 --- a/src/Collection/AbstractCollection.php +++ b/src/Collection/AbstractCollection.php @@ -23,7 +23,7 @@ * * @template TKey of array-key * @template T - * @extends Arrayy + * @extends Arrayy> * @implements CollectionInterface */ abstract class AbstractCollection extends Arrayy implements CollectionInterface @@ -62,7 +62,7 @@ abstract class AbstractCollection extends Arrayy implements CollectionInterface * true, otherwise this option didn't not work anyway. *

* - * @phpstan-param array|\Arrayy\Arrayy|\Closure():array|mixed $data + * @phpstan-param array|\Arrayy\Arrayy>|\Closure():array|mixed $data * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass */ public function __construct( @@ -105,7 +105,7 @@ public function __construct( * * @phpstan-param T|static $value * @phpstan-param TKey|null $key - * @phpstan-return static + * @phpstan-return static */ public function append($value, $key = null): Arrayy { @@ -121,7 +121,7 @@ public function append($value, $key = null): Arrayy return $this; } - /* @phpstan-ignore-next-line | special? */ + /* @phpstan-ignore argument.type */ $return = parent::append($value, $key); $this->array = $return->array; $this->generator = null; @@ -168,7 +168,7 @@ public function offsetSet($offset, $value) * * @phpstan-param T|static $value * @phpstan-param TKey|null $key - * @phpstan-return static + * @phpstan-return static */ public function prepend($value, $key = null): Arrayy { @@ -184,7 +184,7 @@ public function prepend($value, $key = null): Arrayy return $this; } - /* @phpstan-ignore-next-line | special? */ + /* @phpstan-ignore argument.type */ $return = parent::prepend($value, $key); $this->array = $return->array; $this->generator = null; @@ -237,7 +237,7 @@ abstract public function getType(); * @return $this * * @phpstan-param CollectionInterface ...$collections - * @phpstan-return static + * @phpstan-return static */ public function merge(CollectionInterface ...$collections): self { @@ -264,7 +264,7 @@ public function merge(CollectionInterface ...$collections): self * @template TCreate as T * @phpstan-param array $data * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass - * @phpstan-return static + * @phpstan-return static * * @psalm-mutation-free */ @@ -273,11 +273,14 @@ public static function create( string $iteratorClass = ArrayyIterator::class, bool $checkPropertiesInConstructor = true ) { - return new static( // @phpstan-ignore new.static + /** @var static $instance */ + $instance = new static( // @phpstan-ignore new.static $data, $iteratorClass, $checkPropertiesInConstructor ); + + return $instance; } /** @@ -286,7 +289,7 @@ public static function create( * @return static *

(Immutable) Returns an new instance of the CollectionInterface object.

* - * @phpstan-return static + * @phpstan-return static * * @psalm-mutation-free */ @@ -326,7 +329,7 @@ public static function createFromJsonMapper(string $json) } } - /** @phpstan-var static */ + /** @phpstan-var static */ return $return; } diff --git a/src/Collection/Collection.php b/src/Collection/Collection.php index b1ffe87..96f164f 100644 --- a/src/Collection/Collection.php +++ b/src/Collection/Collection.php @@ -97,7 +97,7 @@ class Collection extends AbstractCollection *

* @param TypeInterface|null $type * - * @phpstan-param array|array|\Arrayy\Arrayy $data + * @phpstan-param array|array|\Arrayy\Arrayy> $data * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass */ public function __construct( @@ -115,7 +115,7 @@ public function __construct( } if ($type !== null) { - /* @phpstan-ignore-next-line - we use the "TypeInterface" only as base */ + /* @phpstan-ignore assign.propertyType */ $this->properties = $type; } @@ -136,7 +136,7 @@ public function __construct( * @template TConstruct * @phpstan-param string|class-string|class-string|TypeInterface|TypeCheckArray|array $type * @phpstan-param array $data - * @phpstan-return static + * @phpstan-return static */ public static function construct( $type, diff --git a/src/Collection/CollectionInterface.php b/src/Collection/CollectionInterface.php index 42f1b2b..2debd7d 100644 --- a/src/Collection/CollectionInterface.php +++ b/src/Collection/CollectionInterface.php @@ -164,7 +164,7 @@ public function containsValueRecursive($value): bool; * @template TCreate as T * @phpstan-param array $data * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass - * @phpstan-return static + * @phpstan-return static * * @psalm-mutation-free */ diff --git a/src/Create.php b/src/Create.php index 7e43f48..9241591 100644 --- a/src/Create.php +++ b/src/Create.php @@ -2,62 +2,6 @@ declare(strict_types=1); -namespace { - if (\PHP_VERSION_ID < 70300) { - if (!\function_exists('is_countable')) { - /** - * @param mixed $var - * - * @return bool - */ - function is_countable($var) - { - return \is_array($var) - || - $var instanceof SimpleXMLElement - || - $var instanceof Countable - || - $var instanceof ResourceBundle; - } - } - - if (!\function_exists('array_key_first')) { - /** - * @param array $array - * - * @return int|string|null - */ - function array_key_first(array $array) - { - foreach ($array as $key => $value) { - return $key; - } - - return null; - } - } - - if (!\function_exists('array_key_last')) { - /** - * @param array $array - * - * @return int|string|null - */ - function array_key_last(array $array) - { - if (\count($array) === 0) { - return null; - } - - return \array_keys( - \array_slice($array, -1, 1, true) - )[0]; - } - } - } -} - namespace Arrayy { use Arrayy\Collection\Collection; use Arrayy\TypeCheck\TypeCheckArray; @@ -69,7 +13,7 @@ function array_key_last(array $array) * * @param mixed $data * - * @return Arrayy + * @return Arrayy> */ function create($data): Arrayy { diff --git a/src/Mapper/Json.php b/src/Mapper/Json.php index 0e46f14..a5724e0 100644 --- a/src/Mapper/Json.php +++ b/src/Mapper/Json.php @@ -416,7 +416,7 @@ private function inspectProperty(\ReflectionClass $rc, $name): array $accessor = null; /** @var \Arrayy\Arrayy[] $ARRAYY_CACHE */ - /** @phpstan-var array> $ARRAYY_CACHE */ + /** @phpstan-var array>> $ARRAYY_CACHE */ static $ARRAYY_CACHE = []; if (\is_subclass_of($class->name, \Arrayy\Arrayy::class)) { diff --git a/src/StaticArrayy.php b/src/StaticArrayy.php index 5dac472..0b09613 100644 --- a/src/StaticArrayy.php +++ b/src/StaticArrayy.php @@ -70,7 +70,7 @@ public static function __callStatic(string $name, $arguments) * @param int|null $stop The stopping point * @param int $step How many to increment of * - * @return Arrayy + * @return Arrayy> * * @psalm-suppress InvalidReturnStatement - why? * @psalm-suppress InvalidReturnType - why? @@ -93,7 +93,7 @@ public static function range(int $base, ?int $stop = null, int $step = 1): Array * @param float|int|string|null $data * @param int $times * - * @return Arrayy + * @return Arrayy> * * @psalm-suppress InvalidReturnStatement - why? * @psalm-suppress InvalidReturnType - why? diff --git a/src/Type/DetectFirstValueTypeCollection.php b/src/Type/DetectFirstValueTypeCollection.php index 1010247..b0693a1 100644 --- a/src/Type/DetectFirstValueTypeCollection.php +++ b/src/Type/DetectFirstValueTypeCollection.php @@ -26,7 +26,7 @@ final class DetectFirstValueTypeCollection extends Collection implements TypeInt * @param string $iteratorClass * @param bool $checkPropertiesInConstructor * - * @phpstan-param array|Arrayy $data + * @phpstan-param array|Arrayy> $data * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass */ public function __construct( diff --git a/src/TypeCheck/TypeCheckPhpDoc.php b/src/TypeCheck/TypeCheckPhpDoc.php index 3aaa713..43fbbe7 100644 --- a/src/TypeCheck/TypeCheckPhpDoc.php +++ b/src/TypeCheck/TypeCheckPhpDoc.php @@ -7,8 +7,6 @@ namespace Arrayy\TypeCheck; -use phpDocumentor\Reflection\Type; - /** * inspired by https://github.com/spatie/value-object * @@ -52,16 +50,22 @@ public static function fromPhpDocumentorProperty(\phpDocumentor\Reflection\DocBl $property = $propertyTmp; } - $tmpObject = new \stdClass(); - $tmpObject->{$property} = null; - - $tmpReflection = new self((new \ReflectionProperty($tmpObject, $property))->getName()); - - $type = $phpDocumentorReflectionProperty->getType(); + return self::fromDocTypeObject($property, $phpDocumentorReflectionProperty->getType()); + } - /** @noinspection PhpSillyAssignmentInspection */ - /** @var Type|null $type */ - $type = $type; + /** + * Create a type checker from a phpDocumentor type object and an explicit property name. + * + * @param string $property + * @param \phpDocumentor\Reflection\Type|null $type + * + * @phpstan-param \phpDocumentor\Reflection\Type|null $type + * + * @return self + */ + public static function fromDocTypeObject(string $property, $type) + { + $tmpReflection = new self($property); if ($type) { $tmpReflection->hasTypeDeclaration = true; @@ -159,6 +163,25 @@ public static function parseDocTypeObject($type) return $types; } + if ($type instanceof \phpDocumentor\Reflection\Types\Nullable) { + $typeTmp = self::parseDocTypeObject($type->getActualType()); + if (\is_array($typeTmp) === true) { + $typeTmp[] = 'null'; + + return $typeTmp; + } + + return [$typeTmp, 'null']; + } + + if ( + \class_exists('\phpDocumentor\Reflection\PseudoTypes\ArrayShape') + && + $type instanceof \phpDocumentor\Reflection\PseudoTypes\ArrayShape + ) { + return 'array'; + } + if ($type instanceof \phpDocumentor\Reflection\Types\Array_) { $valueTypeTmp = $type->getValueType()->__toString(); if ($valueTypeTmp !== 'mixed') { diff --git a/tests/ArrayyTest.php b/tests/ArrayyTest.php index 3c78e16..6eea6f7 100644 --- a/tests/ArrayyTest.php +++ b/tests/ArrayyTest.php @@ -187,7 +187,7 @@ public function appendToEachValueProvider(): array * * @param mixed $actual */ - public static function assertArrayy($actual) + public static function assertArrayy($actual): void { /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ static::assertInstanceOf(\Arrayy\Arrayy::class, $actual); @@ -1888,7 +1888,7 @@ public function stringWithSeparatorProvider(): array ]; } - public function testAdd() + public function testAdd(): void { $array = [1, 2]; $arrayy = new A($array); @@ -1898,7 +1898,7 @@ public function testAdd() self::assertMutable($arrayy, $resultArrayy, $array); } - public function testAppendImmutableYield() + public function testAppendImmutableYield(): void { $array = [1, 2]; $arrayy = new A($array); @@ -1909,7 +1909,7 @@ public function testAppendImmutableYield() self::assertImmutable($arrayy, $resultArrayy, $array, $arrayResult); } - public function testPrependImmutableYield() + public function testPrependImmutableYield(): void { $array = [3 => 1, 2]; $arrayy = new A($array); @@ -1926,7 +1926,7 @@ public function testPrependImmutableYield() * @param array $result * @param mixed $value */ - public function testAppend($array, $result, $value) + public function testAppend($array, $result, $value): void { $arrayy = A::create($array)->append($value); @@ -1939,7 +1939,7 @@ public function testAppend($array, $result, $value) * @param array $array * @param array $result */ - public function testAppendToEachKey($array, $result) + public function testAppendToEachKey($array, $result): void { $resultTmp = A::create($array)->appendToEachKey('foo_'); @@ -1952,7 +1952,7 @@ public function testAppendToEachKey($array, $result) * @param array $array * @param array $result */ - public function testAppendToEachValue($array, $result) + public function testAppendToEachValue($array, $result): void { $resultTmp = A::create($array)->appendToEachValue('foo_'); @@ -1966,14 +1966,14 @@ public function testAppendToEachValue($array, $result) * @param mixed $value * @param float|int $expected */ - public function testAverage($array, $value, $expected) + public function testAverage($array, $value, $expected): void { $arrayy = new A($array); static::assertSame($expected, $arrayy->average($value), 'tested: ' . $value); } - public function testCanDoSomethingAtEachValue() + public function testCanDoSomethingAtEachValue(): void { $arrayy = A::create(['foo', 'bar' => 'bis']); @@ -1986,7 +1986,7 @@ public function testCanDoSomethingAtEachValue() $this->expectOutputString($result); } - public function testGetValue() + public function testGetValue(): void { $arrayy = (['bàř' => 'bàř']); @@ -1994,7 +1994,7 @@ public function testGetValue() static::assertSame('bàř', $arrayy['bàř']); } - public function testCanGetIntersectionOfTwoArrays() + public function testCanGetIntersectionOfTwoArrays(): void { $a = ['foo', 'bar']; $b = ['bar', 'baz']; @@ -2002,7 +2002,7 @@ public function testCanGetIntersectionOfTwoArrays() static::assertSame([0 => 'bar'], $array->getArray()); } - public function testCanGetIntersectionOfTwoArraysKeepKeys() + public function testCanGetIntersectionOfTwoArraysKeepKeys(): void { $a = ['foo', 'bar']; $b = ['bar', 'baz']; @@ -2010,7 +2010,7 @@ public function testCanGetIntersectionOfTwoArraysKeepKeys() static::assertSame([1 => 'bar'], $array->getArray()); } - public function testCanGroupValues() + public function testCanGroupValues(): void { $under = A::create(\range(1, 5))->group( static function ($value, $key) { @@ -2025,14 +2025,14 @@ static function ($value, $key) { static::assertSame($matcher, $under->getAll()); } - public function testCanGroupValuesWithNonExistingKey() + public function testCanGroupValuesWithNonExistingKey(): void { static::assertSame([], A::create(\range(1, 5))->group('unknown', true)->getArray()); static::assertSame([], A::create(\range(1, 5))->group('unknown', false)->getArray()); } - public function testCanGroupValuesWithSavingKeys() + public function testCanGroupValuesWithSavingKeys(): void { $grouper = static function ($value, $key) { return (int) ($value % 2 === 0); @@ -2045,7 +2045,7 @@ public function testCanGroupValuesWithSavingKeys() static::assertSame($matcher, $under->getArray()); } - public function testCanGroupValuesWithSavingKeysViaYield() + public function testCanGroupValuesWithSavingKeysViaYield(): void { $grouper = static function ($value, $key) { return (int) ($value % 2 === 0); @@ -2065,7 +2065,7 @@ public function testCanGroupValuesWithSavingKeysViaYield() static::assertSame($matcher, $result); } - public function testCanIndexBy() + public function testCanIndexBy(): void { $array = [ ['name' => 'moe', 'age' => 40], @@ -2080,7 +2080,7 @@ public function testCanIndexBy() static::assertSame($expected, A::create($array)->indexBy('age')->getArray()); } - public function testCanIndexByViaYield() + public function testCanIndexByViaYield(): void { $array = [ ['name' => 'moe', 'age' => 40], @@ -2100,7 +2100,7 @@ public function testCanIndexByViaYield() static::assertSame($expected, $result); } - public function testChangeKeyCase() + public function testChangeKeyCase(): void { // upper @@ -2158,7 +2158,7 @@ public function testChangeKeyCase() * * @param array $array */ - public function testChunk(array $array) + public function testChunk(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->chunk(2); @@ -2180,7 +2180,7 @@ public function testChunk(array $array) * @param array $array * @param array $result */ - public function testClean($array, $result) + public function testClean($array, $result): void { $arrayy = A::create($array); @@ -2192,7 +2192,7 @@ public function testClean($array, $result) * * @param array $array */ - public function testClear(array $array) + public function testClear(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->clear(); @@ -2200,7 +2200,7 @@ public function testClear(array $array) self::assertMutable($arrayy, $resultArrayy, []); } - public function testColumn() + public function testColumn(): void { $rows = [0 => ['id' => '3', 'title' => 'Foo', 'date' => '2013-03-25']]; @@ -2250,7 +2250,7 @@ public function testColumn() static::assertSame(A::create($expected2)->getArray(), A::create($rows)->getColumn(null)->getArray()); } - public function testCompareToPhpArray() + public function testCompareToPhpArray(): void { $initArray = [ 'fruit' => [ @@ -2279,7 +2279,7 @@ static function ($value) { static::assertSame([0 => 'orange*', 1 => 'avocado*', 3 => 'pear*'], $arrayy->getArray()); } - public function testConstruct() + public function testConstruct(): void { $testArray = ['foo bar', 'UTF-8']; $arrayy = new A($testArray); @@ -2287,7 +2287,7 @@ public function testConstruct() static::assertSame('foo bar,UTF-8', (string) $arrayy); } - public function testConstructWithArray() + public function testConstructWithArray(): void { $this->expectException(\InvalidArgumentException::class); @@ -2302,7 +2302,7 @@ public function testConstructWithArray() * @param mixed $value * @param bool $expected */ - public function testContainsOnly($array, $value, $expected) + public function testContainsOnly($array, $value, $expected): void { $arrayy = new A($array); @@ -2316,7 +2316,7 @@ public function testContainsOnly($array, $value, $expected) * @param mixed $value * @param bool $expected */ - public function testContains($array, $value, $expected) + public function testContains($array, $value, $expected): void { $arrayy = new A($array); @@ -2332,7 +2332,7 @@ public function testContains($array, $value, $expected) * @param mixed $value * @param bool $expected */ - public function testContainsCaseInsensitive($array, $value, $expected) + public function testContainsCaseInsensitive($array, $value, $expected): void { $arrayy = new A($array); @@ -2347,14 +2347,14 @@ public function testContainsCaseInsensitive($array, $value, $expected) * @param mixed $value * @param bool $expected */ - public function testContainsCaseInsensitiveRecursive($array, $value, $expected) + public function testContainsCaseInsensitiveRecursive($array, $value, $expected): void { $arrayy = new A($array); static::assertSame($expected, $arrayy->containsCaseInsensitive($value, true), 'tested: ' . \print_r($value, true)); } - public function testContainsKeys() + public function testContainsKeys(): void { static::assertTrue(A::create(['a' => 0, 'b' => 1, 'd' => ['c' => 2]])->containsKeys(['a', 'b', 'c'], true)); static::assertFalse(A::create(['a' => 0, 'b' => 1, 'd' => ['c' => 2]])->containsKeys(['a', 'b', 'c'], false)); @@ -2368,7 +2368,7 @@ public function testContainsKeys() static::assertFalse(A::create([])->containsKeys(['a', 'b', 'c'])); } - public function testPull() + public function testPull(): void { static::assertSame([0, 1, null], A::create(['a' => 0, 'b' => 1, 'd' => ['c' => 2]])->pull(['a', 'b', 'foo'])); static::assertSame([0, 1], A::create(['a' => 0, 'b' => 1, 'd' => ['c' => 2]])->pull(['a', 'b'])); @@ -2384,7 +2384,7 @@ public function testPull() static::assertSame(['d' => ['c' => 2]], $test->getArray()); } - public function testContainsKeysRecursive() + public function testContainsKeysRecursive(): void { static::assertTrue(A::create(['a' => 0, 'b' => 1, ['c' => 2]])->containsKeysRecursive(['a', 'b', 'c'])); static::assertTrue(A::create(['a' => 0, 'b' => 1, ['c' => 2]])->containsKeysRecursive(['a', 'b'])); @@ -2420,7 +2420,7 @@ public function testContainsKeysRecursive() * @param mixed $value * @param bool $expected */ - public function testContainsRecursive($array, $value, $expected) + public function testContainsRecursive($array, $value, $expected): void { $arrayy = new A($array); @@ -2428,7 +2428,7 @@ public function testContainsRecursive($array, $value, $expected) static::assertSame($expected, $arrayy->containsValueRecursive($value)); // alias } - public function testContainsValues() + public function testContainsValues(): void { static::assertTrue(A::create(['a', 'b', 'c'])->containsValues(['a', 'b'])); static::assertFalse(A::create(['a', 'b', 'd'])->containsValues(['a', 'b', 'c'])); @@ -2443,7 +2443,7 @@ public function testContainsValues() * @param array $array * @param int $expected */ - public function testCount($array, $expected) + public function testCount($array, $expected): void { $arrayy = new A($array); @@ -2460,7 +2460,7 @@ public function testCount($array, $expected) * @param array $array * @param int $expected */ - public function testCountRecursive($array, $expected) + public function testCountRecursive($array, $expected): void { $arrayy = new A($array); @@ -2470,7 +2470,7 @@ public function testCountRecursive($array, $expected) static::assertSame($expected, $arrayy->length(\COUNT_RECURSIVE)); } - public function testCountValues() + public function testCountValues(): void { $array = ['foo', 'lall', 'bar', 'bar', 'foo', 'bar']; $arrayy = new A($array); @@ -2479,7 +2479,7 @@ public function testCountValues() static::assertSame($expected, $arrayy->countValues()->getArray()); } - public function testCreateByReference() + public function testCreateByReference(): void { $testArray = ['foo bar', 'UTF-8']; $arrayy = new A(); @@ -2490,7 +2490,7 @@ public function testCreateByReference() static::assertSame($testArray, $arrayy->toArray()); } - public function testCreateFromJsonApiResponse() + public function testCreateFromJsonApiResponse(): void { $str = ' { @@ -2525,7 +2525,7 @@ public function testCreateFromJsonApiResponse() ); } - public function testCreateFromJson() + public function testCreateFromJson(): void { $str = ' {"employees":[ @@ -2569,7 +2569,7 @@ public function testCreateFromJson() * @param string $string * @param non-empty-string|null $separator */ - public function testCreateFromString($string, $separator) + public function testCreateFromString($string, $separator): void { if ($separator !== null) { $array = \explode($separator, $string); @@ -2585,7 +2585,7 @@ public function testCreateFromString($string, $separator) self::assertImmutable($arrayy, $resultArrayy, $array, $array); } - public function testCreateFromTraversableImmutable() + public function testCreateFromTraversableImmutable(): void { $array = ['recipe' => 'pancakes', 'egg', 'milk', 'flour']; $iterator = new \ArrayIterator($array); @@ -2596,7 +2596,7 @@ public function testCreateFromTraversableImmutable() self::assertImmutable($arrayy, $resultArrayy, $array, $array); } - public function testCreateFromStringRegEx() + public function testCreateFromStringRegEx(): void { $str = ' [2016-03-02 02:37:39] WARN main : router: error in file-name: jquery.min.map @@ -2618,7 +2618,7 @@ public function testCreateFromStringRegEx() static::assertSame($expected, $arrayy->getArray()); } - public function testCreateFromStringSimple() + public function testCreateFromStringSimple(): void { $str = 'John, Doe, Anna, Smith'; @@ -2630,7 +2630,7 @@ public function testCreateFromStringSimple() static::assertSame($expected, $arrayy->getArray()); } - public function testCreateWithRange() + public function testCreateWithRange(): void { $arrayy1 = A::createWithRange(2, 7); $array1 = \range(2, 7); @@ -2652,7 +2652,7 @@ public function testCreateWithRange() * * @param array $array */ - public function testCustomSort(array $array) + public function testCustomSort(array $array): void { $callable = static function ($a, $b) { if ($a === $b) { @@ -2675,7 +2675,7 @@ public function testCustomSort(array $array) * * @param array $array */ - public function testCustomSortImmutable(array $array) + public function testCustomSortImmutable(array $array): void { $callable = static function ($a, $b) { if ($a === $b) { @@ -2698,7 +2698,7 @@ public function testCustomSortImmutable(array $array) * * @param array $array */ - public function testCustomSortKeys(array $array) + public function testCustomSortKeys(array $array): void { $callable = static function ($a, $b) { if ($a === $b) { @@ -2723,7 +2723,7 @@ public function testCustomSortKeys(array $array) self::assertMutable($arrayy, $resultArrayy, $resultArrayV2->getArray()); } - public function testCustomSortKeysSimple() + public function testCustomSortKeysSimple(): void { $callable = static function ($a, $b) { if ($a === $b) { @@ -2783,7 +2783,7 @@ public function testCustomSortKeysSimple() self::assertImmutable($arrayy, $resultArrayy, $input, $resultArrayy->getArray()); } - public function testCustomSortValuesByDateTimeObject() + public function testCustomSortValuesByDateTimeObject(): void { $birthDates = [ ['Lucienne Adkisson', \date_create('2017-10-17')], @@ -2898,7 +2898,7 @@ public function testCustomSortValuesByDateTimeObject() * @param array $arrayNew * @param array $result */ - public function testDiff($array, $arrayNew, $result) + public function testDiff($array, $arrayNew, $result): void { $arrayy = A::create($array)->diff($arrayNew); @@ -2912,7 +2912,7 @@ public function testDiff($array, $arrayNew, $result) * @param array $arrayNew * @param array $result */ - public function testDiffKey($array, $arrayNew, $result) + public function testDiffKey($array, $arrayNew, $result): void { $arrayy = A::create($array)->diffKey($arrayNew); @@ -2926,14 +2926,14 @@ public function testDiffKey($array, $arrayNew, $result) * @param array $arrayNew * @param array $result */ - public function testDiffKeyAndValue($array, $arrayNew, $result) + public function testDiffKeyAndValue($array, $arrayNew, $result): void { $arrayy = A::create($array)->diffKeyAndValue($arrayNew); static::assertSame($result, $arrayy->getArray(), 'tested: ' . \print_r($array, true)); } - public function testDiffRecursive() + public function testDiffRecursive(): void { $testArray1 = [ 'test1' => ['lall'], @@ -3002,7 +3002,7 @@ public function testDiffRecursive() * * @param array $array */ - public function testDiffWith(array $array) + public function testDiffWith(array $array): void { $secondArray = [ 'one' => 1, @@ -3017,7 +3017,7 @@ public function testDiffWith(array $array) self::assertImmutable($arrayy, $resultArrayy, $array, $resultArray); } - public function testDivide() + public function testDivide(): void { $arrayy = new A(['id' => 999, 'name' => 'flux', 'group' => null, 'value' => 6868, 'when' => '2015-01-01']); $arrayyResult = new A(['id', 'name', 'group', 'value', 'when', 999, 'flux', '', 6868, '2015-01-01']); @@ -3025,7 +3025,7 @@ public function testDivide() static::assertSame($arrayyResult->toString(), $arrayy->divide()->toString()); } - public function testEach() + public function testEach(): void { $array = [1 => 'bar', 'foo' => 'foo']; $arrayy = A::create($array); @@ -3039,14 +3039,14 @@ public function testEach() static::assertSame($result, $under->getArray(), 'tested: ' . \print_r($array, true)); } - public function testEmptyConstruct() + public function testEmptyConstruct(): void { $arrayy = new A(); self::assertArrayy($arrayy); static::assertSame('', (string) $arrayy); } - public function testExchangeArray() + public function testExchangeArray(): void { $input = [ 'three' => 3, @@ -3068,7 +3068,7 @@ public function testExchangeArray() * @param mixed $default * @param array $expected */ - public function testFillWithDefaults($array, $num, $default, $expected) + public function testFillWithDefaults($array, $num, $default, $expected): void { $arrayy = new A($array); @@ -3081,7 +3081,7 @@ public function testFillWithDefaults($array, $num, $default, $expected) static::assertSame($expected, $result->getArray()); } - public function testFillWithDefaultsException() + public function testFillWithDefaultsException(): void { $this->expectException(\InvalidArgumentException::class); @@ -3090,7 +3090,7 @@ public function testFillWithDefaultsException() $arrayy->fillWithDefaults(-1); } - public function testIsEqual() + public function testIsEqual(): void { $arrayy = new A([1, 2, 3]); @@ -3099,7 +3099,7 @@ public function testIsEqual() static::assertFalse($arrayy->isEqual([3, 2, 1])); } - public function testFilter() + public function testFilter(): void { if (!\defined('ARRAY_FILTER_USE_BOTH')) { \define('ARRAY_FILTER_USE_BOTH', 1); @@ -3137,7 +3137,7 @@ static function ($value) { // --- $under = A::create([0 => 1, 1 => 2, 2 => 3, 3 => 4, 7 => 7])->filter( - /* @phpstan-ignore-next-line | FP from phpstan? */ + /* @phpstan-ignore argument.type */ static function ($key, $value): bool { return ($value % 2 !== 0) && ($key & 2 !== 0); }, @@ -3156,7 +3156,7 @@ static function ($value) { static::assertSame([0 => 1, 2 => 3, 7 => 7], $under->getArray()); } - public function testFilterBy() + public function testFilterBy(): void { $a = [ ['id' => 123, 'name' => 'foo', 'group' => 'primary', 'value' => 123456, 'when' => '2014-01-01'], @@ -3211,7 +3211,7 @@ public function testFilterBy() * @param mixed $search * @param false|mixed $result */ - public function testFind($array, $search, $result) + public function testFind($array, $search, $result): void { $closure = static function ($value) use ($search) { return $value === $search; @@ -3250,7 +3250,7 @@ public function findKeyProvider(): array * @param mixed $search * @param false|mixed $result */ - public function testFindKey($array, $search, $result) + public function testFindKey($array, $search, $result): void { $closure = static function ($value) use ($search) { return $value === $search; @@ -3262,7 +3262,7 @@ public function testFindKey($array, $search, $result) static::assertSame($result, $resultMatch, 'tested:' . \print_r($array, true)); } - public function testFindKeyWithKeyParameter() + public function testFindKeyWithKeyParameter(): void { // Verify that the key parameter is correctly passed to the closure $array = ['a' => 10, 'b' => 20, 'c' => 30]; @@ -3281,7 +3281,7 @@ public function testFindKeyWithKeyParameter() static::assertFalse($arrayy->findKey($closureNoMatch)); } - public function testFindKeyForMinAndMaxValues() + public function testFindKeyForMinAndMaxValues(): void { $arrayy = A::create([ 3 => 10, @@ -3308,7 +3308,7 @@ public function testFindKeyForMinAndMaxValues() * @param array $array * @param array $result */ - public function testFirst($array, $result) + public function testFirst($array, $result): void { $arrayy = A::create($array); @@ -3322,7 +3322,7 @@ public function testFirst($array, $result) * @param array $result * @param null $take */ - public function testFirsts($array, $result, $take = null) + public function testFirsts($array, $result, $take = null): void { $arrayy = A::create($array); $resultNew = $arrayy->firstsImmutable($take); @@ -3335,7 +3335,7 @@ public function testFirsts($array, $result, $take = null) static::assertSame($arrayy, $resultNew); } - public function testFlip() + public function testFlip(): void { $testArray = [0 => 'foo', 2 => 'bar', 4 => 'lall']; $arrayy = A::create($testArray)->flip(); @@ -3344,7 +3344,7 @@ public function testFlip() static::assertSame($expected, $arrayy->getArray()); } - public function testForEach() + public function testForEach(): void { $arrayy = new A([1 => 'foo bar', 'öäü']); @@ -3357,7 +3357,7 @@ public function testForEach() } } - public function testGet() + public function testGet(): void { $arrayy = new A(['foo bar', 'öäü']); self::assertArrayy($arrayy); @@ -3371,13 +3371,13 @@ public function testGet() * @param array $array * @param mixed $key */ - public function testGetV2($expected, $array, $key) + public function testGetV2($expected, $array, $key): void { $arrayy = new A($array); static::assertSame($expected, $arrayy->get($key), 'tested:' . \print_r($array, true)); } - public function testGetViaDotNotation() + public function testGetViaDotNotation(): void { $arrayy = new A(['Lars' => ['lastname' => 'Moelleken']]); $result = $arrayy->get('Lars.lastname'); @@ -3403,7 +3403,7 @@ public function testGetViaDotNotation() * @param array $array * @param mixed $key */ - public function testHas($expected, $array, $key) + public function testHas($expected, $array, $key): void { $arrayy = new A($array); static::assertSame($expected, $arrayy->has($key)); @@ -3416,7 +3416,7 @@ public function testHas($expected, $array, $key) * @param string $result * @param string $with */ - public function testImplode($array, $result, $with = ',') + public function testImplode($array, $result, $with = ','): void { $string = A::create($array)->implode($with); @@ -3430,14 +3430,14 @@ public function testImplode($array, $result, $with = ',') * @param string $result * @param string $with */ - public function testImplodeKeys($array, $result, $with = ',') + public function testImplodeKeys($array, $result, $with = ','): void { $string = A::create($array)->implodeKeys($with); static::assertSame($result, $string); } - public function testIndexByReturnEmpty() + public function testIndexByReturnEmpty(): void { $array = [ ['name' => 'moe', 'age' => 40], @@ -3447,7 +3447,7 @@ public function testIndexByReturnEmpty() static::assertSame([], A::create($array)->indexBy('vaaaa')->getArray()); } - public function testIndexByReturnSome() + public function testIndexByReturnSome(): void { $array = [ ['name' => 'moe', 'age' => 40], @@ -3468,14 +3468,14 @@ public function testIndexByReturnSome() * @param array $result * @param int $to */ - public function testInitial($array, $result, $to = 1) + public function testInitial($array, $result, $to = 1): void { $arrayy = A::create($array); static::assertSame($result, $arrayy->initial($to)->getArray()); } - public function testIntersectsBooleanFlag() + public function testIntersectsBooleanFlag(): void { $a = ['foo', 'bar']; $b = ['bar', 'baz']; @@ -3488,7 +3488,7 @@ public function testIntersectsBooleanFlag() static::assertFalse(A::create($a)->intersects($b)); } - public function testInvoke() + public function testInvoke(): void { $array = [' foo ', ' bar ']; $arrayy = A::create($array)->invoke('trim'); @@ -3511,7 +3511,7 @@ public function testInvoke() static::assertSame([1 => '_____foo', 2 => '__bar'], $arrayy->getArray()); } - public function testIsArrayAssoc() + public function testIsArrayAssoc(): void { $array0 = [1 => [1]]; $array1 = [ @@ -3579,7 +3579,7 @@ public function testIsArrayAssoc() ); } - public function testIsArrayMultidim() + public function testIsArrayMultidim(): void { $testArrays = [ [1 => [1]], @@ -3625,14 +3625,14 @@ public function testIsArrayMultidim() * @param array $array * @param bool $result */ - public function testIsAssoc($array, $result) + public function testIsAssoc($array, $result): void { $resultTmp = A::create($array)->isAssoc(); static::assertSame($result, $resultTmp); } - public function testIsEmpty() + public function testIsEmpty(): void { $testArrays = [ [1 => [1]], @@ -3672,7 +3672,7 @@ public function testIsEmpty() } } - public function testIsNumeric() + public function testIsNumeric(): void { $testArrays = [ [1 => [1]], @@ -3712,7 +3712,7 @@ public function testIsNumeric() } } - public function testIsSequentialRecursive() + public function testIsSequentialRecursive(): void { $testArrays = [ [1 => [1]], @@ -3755,7 +3755,7 @@ public function testIsSequentialRecursive() } } - public function testIsSequential() + public function testIsSequential(): void { $testArrays = [ [1 => [1]], @@ -3794,7 +3794,7 @@ public function testIsSequential() } } - public function testIsSet() + public function testIsSet(): void { $arrayy = new A(['foo bar', 'öäü']); self::assertArrayy($arrayy); @@ -3804,11 +3804,11 @@ public function testIsSet() $arrayy = new A([true => 'foo bar', 'lall' => 'öäü']); self::assertArrayy($arrayy); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore staticMethod.impossibleType, isset.offset */ static::assertTrue(isset($arrayy[true])); } - public function testJsonSerializable() + public function testJsonSerializable(): void { $arrayy = new A(); $arrayy['user'] = ['lastname' => 'Moelleken']; @@ -3828,7 +3828,7 @@ public function testJsonSerializable() ); } - public function testKeys() + public function testKeys(): void { $arrayyTmp = A::create([1 => 'foo', 2 => 'foo2', 3 => 'bar']); $keys = $arrayyTmp->keys(); @@ -3883,7 +3883,7 @@ public function testKeys() * @param array $result * @param null $take */ - public function testLast($array, $result, $take = null) + public function testLast($array, $result, $take = null): void { $arrayy = A::create($array); $resultNew = $arrayy->lastsImmutable($take); @@ -3894,7 +3894,7 @@ public function testLast($array, $result, $take = null) static::assertSame($result, $resultNew->getArray()); } - public function testMagicGet() + public function testMagicGet(): void { $array = [ 'one' => 1, @@ -3905,13 +3905,13 @@ public function testMagicGet() $arrayy = new Arrayy($array); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ static::assertSame(1, $arrayy->one); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ static::assertSame(2, $arrayy->test); } - public function testMagicInvoke() + public function testMagicInvoke(): void { $array = [ 'one' => 1, @@ -3925,7 +3925,7 @@ public function testMagicInvoke() static::assertSame('one', $arrayy(1)); } - public function testMagicSetViaDotNotation() + public function testMagicSetViaDotNotation(): void { $arrayy = new A(); $arrayy['user'] = ['lastname' => 'Moelleken']; @@ -3949,7 +3949,7 @@ public function testMagicSetViaDotNotation() * * @param array $array */ - public function testMap(array $array) + public function testMap(array $array): void { $callable = static function ($value) { return \str_repeat($value, 2); @@ -3967,13 +3967,13 @@ public function testMap(array $array) } $arrayy = new A($array); - /* @phpstan-ignore-next-line | old way of "callable" */ + /* @phpstan-ignore argument.type */ $resultArrayy = $arrayy->map('str_repeat', false, 2); $resultArray = \array_map($callable, $array); self::assertImmutable($arrayy, $resultArrayy, $array, $resultArray); } - public function testMapSimpleExample() + public function testMapSimpleExample(): void { $arrayy = new A(['foo', 'Foo']); $resultArrayy = $arrayy->map('strtoupper'); @@ -3987,7 +3987,7 @@ public function testMapSimpleExample() * @param mixed $search * @param bool $result */ - public function testMatches($array, $search, $result) + public function testMatches($array, $search, $result): void { $arrayy = A::create($array); @@ -4011,7 +4011,7 @@ public function testMatches($array, $search, $result) * @param array $search * @param bool $result */ - public function testMatchesAny($array, $search, $result) + public function testMatchesAny($array, $search, $result): void { $arrayy = A::create($array); @@ -4024,7 +4024,7 @@ public function testMatchesAny($array, $search, $result) static::assertSame($result, $resultMatch); } - public function testMatchesAnySimple() + public function testMatchesAnySimple(): void { /** * @param int $value @@ -4045,7 +4045,7 @@ public function testMatchesAnySimple() static::assertFalse($result); } - public function testMatchesSimple() + public function testMatchesSimple(): void { /** * @param int $value @@ -4072,14 +4072,14 @@ public function testMatchesSimple() * @param array $array * @param mixed $expected */ - public function testMax($array, $expected) + public function testMax($array, $expected): void { $arrayy = new A($array); static::assertSame($expected, $arrayy->max(), 'tested: ' . \print_r($array, true)); } - public function testMergeMethods() + public function testMergeMethods(): void { $array1 = [1 => 'one', 'foo' => 'bar1']; $array2 = ['foo' => 'bar2', 3 => 'three']; @@ -4131,7 +4131,7 @@ public function testMergeMethods() * @param array $arrayNew * @param array $result */ - public function testMergeAppendKeepIndex($array, $arrayNew, $result) + public function testMergeAppendKeepIndex($array, $arrayNew, $result): void { $arrayy = A::create($array)->mergeAppendKeepIndex($arrayNew); @@ -4145,7 +4145,7 @@ public function testMergeAppendKeepIndex($array, $arrayNew, $result) * @param array $arrayNew * @param array $result */ - public function testMergeAppendNewIndex($array, $arrayNew, $result) + public function testMergeAppendNewIndex($array, $arrayNew, $result): void { $arrayy = A::create($array)->mergeAppendNewIndex($arrayNew); @@ -4159,7 +4159,7 @@ public function testMergeAppendNewIndex($array, $arrayNew, $result) * @param array $arrayNew * @param array $result */ - public function testMergePrependKeepIndex($array, $arrayNew, $result) + public function testMergePrependKeepIndex($array, $arrayNew, $result): void { $arrayy = A::create($array)->mergePrependKeepIndex($arrayNew); @@ -4173,7 +4173,7 @@ public function testMergePrependKeepIndex($array, $arrayNew, $result) * @param array $arrayNew * @param array $result */ - public function testMergePrependNewIndex($array, $arrayNew, $result) + public function testMergePrependNewIndex($array, $arrayNew, $result): void { $arrayy = A::create($array)->mergePrependNewIndex($arrayNew); @@ -4185,7 +4185,7 @@ public function testMergePrependNewIndex($array, $arrayNew, $result) * * @param array $array */ - public function testMergePrependNewIndexV2(array $array) + public function testMergePrependNewIndexV2(array $array): void { $secondArray = [ 'one' => 1, @@ -4205,7 +4205,7 @@ public function testMergePrependNewIndexV2(array $array) * * @param array $array */ - public function testMergeToRecursively(array $array) + public function testMergeToRecursively(array $array): void { $secondArray = [ 'one' => 1, @@ -4225,7 +4225,7 @@ public function testMergeToRecursively(array $array) * * @param array $array */ - public function testMergeWith(array $array) + public function testMergeWith(array $array): void { $secondArray = [ 'one' => 1, @@ -4245,7 +4245,7 @@ public function testMergeWith(array $array) * * @param array $array */ - public function testMergeWithRecursively(array $array) + public function testMergeWithRecursively(array $array): void { $secondArray = [ 'one' => 1, @@ -4266,14 +4266,14 @@ public function testMergeWithRecursively(array $array) * @param array $array * @param mixed $expected */ - public function testMin($array, $expected) + public function testMin($array, $expected): void { $arrayy = new A($array); static::assertSame($expected, $arrayy->min(), 'tested:' . \print_r($array, true)); } - public function testMissingToString() + public function testMissingToString(): void { $this->expectException(\InvalidArgumentException::class); @@ -4285,7 +4285,7 @@ public function testMissingToString() ); } - public function testMoveElementToFirstPlace() + public function testMoveElementToFirstPlace(): void { $arr1 = new A(['a', 'b', 'c', 'd', 'e']); $expected = [3 => 'd', 0 => 'a', 1 => 'b', 2 => 'c', 4 => 'e']; @@ -4302,7 +4302,7 @@ public function testMoveElementToFirstPlace() static::assertSame($expected, $newArr2->toArray()); } - public function testMoveElementToLastPlace() + public function testMoveElementToLastPlace(): void { $arr1 = new A(['a', 'b', 'c', 'd', 'e']); $expected = [0 => 'a', 1 => 'b', 2 => 'c', 4 => 'e', 3 => 'd']; @@ -4319,7 +4319,7 @@ public function testMoveElementToLastPlace() static::assertSame($expected, $newArr2->toArray()); } - public function testMoveElement() + public function testMoveElement(): void { $arr1 = new A(['a', 'b', 'c', 'd', 'e']); $expected = ['a', 'd', 'b', 'c', 'e']; @@ -4336,7 +4336,7 @@ public function testMoveElement() static::assertSame($expected, $newArr2->toArray()); } - public function testNested() + public function testNested(): void { $array = [ 'one' => 'yes_one', @@ -4380,7 +4380,7 @@ public function testNested() * * @param array $array */ - public function testOffsetNullSet(array $array) + public function testOffsetNullSet(array $array): void { $offset = null; $value = 'new'; @@ -4397,7 +4397,7 @@ public function testOffsetNullSet(array $array) * * @param array $array */ - public function testOffsetSet(array $array) + public function testOffsetSet(array $array): void { $offset = 1; $value = 'new'; @@ -4414,7 +4414,7 @@ public function testOffsetSet(array $array) * * @param array $array */ - public function testOffsetUnset(array $array) + public function testOffsetUnset(array $array): void { $arrayy = new A($array); $offset = 1; @@ -4423,7 +4423,7 @@ public function testOffsetUnset(array $array) unset($array[$offset]); static::assertSame($array, $arrayy->toArray()); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore staticMethod.alreadyNarrowedType, isset.offset */ static::assertFalse(isset($array[$offset])); static::assertFalse($arrayy->offsetExists($offset)); } @@ -4433,7 +4433,7 @@ public function testOffsetUnset(array $array) * * @param array $array */ - public function testDeleteKey(array $array) + public function testDeleteKey(array $array): void { $arrayy = new A($array); $offset = 1; @@ -4442,12 +4442,12 @@ public function testDeleteKey(array $array) unset($array[$offset]); static::assertSame($array, $arrayy->toArray()); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore staticMethod.alreadyNarrowedType, isset.offset */ static::assertFalse(isset($array[$offset])); static::assertFalse($arrayy->offsetExists($offset)); } - public function testOffsetUnsetViaDotNotation() + public function testOffsetUnsetViaDotNotation(): void { $array = ['a', 'b' => [0 => 'c', 1 => null]]; $arrayy = new A($array); @@ -4462,7 +4462,7 @@ public function testOffsetUnsetViaDotNotation() unset($array['b'][0]); static::assertSame($array, $arrayy->toArray()); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore staticMethod.alreadyNarrowedType, isset.offset */ static::assertFalse(isset($array[$offset])); static::assertFalse($arrayy->offsetExists($offset)); @@ -4481,7 +4481,7 @@ public function testOffsetUnsetViaDotNotation() static::assertFalse($arrayy->offsetExists($offset)); } - public function testOrderByKey() + public function testOrderByKey(): void { $array = [ 99 => 'aaa', @@ -4528,7 +4528,7 @@ public function testOrderByKey() static::assertSame($expected, $result); } - public function testOrderByValueKeepIndex() + public function testOrderByValueKeepIndex(): void { $array = [ 100 => 'abc', @@ -4552,7 +4552,7 @@ public function testOrderByValueKeepIndex() static::assertSame($expected, $result); } - public function testOrderByValueNewIndex() + public function testOrderByValueNewIndex(): void { $array = [ 1 => 'hcd', @@ -4581,7 +4581,7 @@ public function testOrderByValueNewIndex() * * @param array $array */ - public function testPad(array $array) + public function testPad(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->pad(10, 5); @@ -4595,7 +4595,7 @@ public function testPad(array $array) * * @param array $array */ - public function testPop(array $array) + public function testPop(array $array): void { $arrayy = new A($array); $poppedValue = $arrayy->pop(); @@ -4613,14 +4613,14 @@ public function testPop(array $array) * @param array $result * @param mixed $value */ - public function testPrepend($array, $result, $value) + public function testPrepend($array, $result, $value): void { $arrayy = A::create($array)->prepend($value); static::assertSame($result, $arrayy->getArray()); } - public function testPrependKey() + public function testPrependKey(): void { $arrayy = new A(['id' => 999, 'name' => 'flux', 'group' => null, 'value' => 6868, 'when' => '2015-01-01']); $arrayyResult = new A( @@ -4659,7 +4659,7 @@ public function testPrependKey() * @param array $array * @param array $result */ - public function testPrependToEachKey($array, $result) + public function testPrependToEachKey($array, $result): void { $resultTmp = A::create($array)->prependToEachKey('_foo'); @@ -4679,7 +4679,7 @@ public function testPrependToEachKey($array, $result) * @param array $array * @param array $result */ - public function testPrependToEachValue($array, $result) + public function testPrependToEachValue($array, $result): void { $resultTmp = A::create($array)->prependToEachValue('_foo'); @@ -4691,7 +4691,7 @@ public function testPrependToEachValue($array, $result) * * @param array $array */ - public function testPush(array $array) + public function testPush(array $array): void { $newElement1 = 5; $newElement2 = 10; @@ -4710,7 +4710,7 @@ public function testPush(array $array) * @param array $array * @param int|null $take */ - public function testRandom($array, $take = null) + public function testRandom($array, $take = null): void { $arrayy = A::create($array); $result = $arrayy->randomMutable($take)->getArray(); @@ -4718,7 +4718,7 @@ public function testRandom($array, $take = null) static::assertContains($result[0], $array); } - public function testRandomKey() + public function testRandomKey(): void { $array = [1 => 'one', 2 => 'two']; $arrayy = A::create($array); @@ -4728,7 +4728,7 @@ public function testRandomKey() static::assertArrayHasKey($result, $array); } - public function testRandomKeys() + public function testRandomKeys(): void { $array = [1 => 'one', 2 => 'two']; $arrayy = A::create($array); @@ -4738,7 +4738,7 @@ public function testRandomKeys() static::assertArrayHasKey($result[1], $array); } - public function testRandomValue() + public function testRandomValue(): void { $array = [1 => 'one', 2 => 'two']; $arrayy = A::create($array); @@ -4747,7 +4747,7 @@ public function testRandomValue() static::assertContains($result, $array); } - public function testRandomValues() + public function testRandomValues(): void { $array = [1 => 'one', 2 => 'two']; $arrayy = A::create($array); @@ -4763,7 +4763,7 @@ public function testRandomValues() * @param array $array * @param int|null $take */ - public function testRandomWeighted($array, $take = null) + public function testRandomWeighted($array, $take = null): void { $arrayy = A::create($array); $result = $arrayy->randomWeighted([0], $take)->getArray(); @@ -4771,7 +4771,7 @@ public function testRandomWeighted($array, $take = null) static::assertContains($result[0], $array); } - public function testReduce() + public function testReduce(): void { $testArray = ['foo', 2 => 'bar', 4 => 'lall']; @@ -4789,7 +4789,7 @@ public function testReduce() static::assertSame($expected, $arrayy->getArray()); } - public function testReduceViaFunction() + public function testReduceViaFunction(): void { $testArray = ['foo', 2 => 'bar', 4 => 'lall']; @@ -4820,7 +4820,7 @@ public function testReduceViaFunction() * @param array $expected * @param bool $unique */ - public function testReduceDimension(array $array, array $expected, bool $unique = false) + public function testReduceDimension(array $array, array $expected, bool $unique = false): void { $arrayy = new A($array); $result = $arrayy->reduce_dimension($unique)->getArray(); @@ -4833,7 +4833,7 @@ public function testReduceDimension(array $array, array $expected, bool $unique * * @param array $array */ - public function testTestgetValues(array $array) + public function testTestgetValues(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->getValues()->getArray(); @@ -4847,7 +4847,7 @@ public function testTestgetValues(array $array) * * @param array $array */ - public function testGetValuesYield(array $array) + public function testGetValuesYield(array $array): void { $arrayy = new A($array); $resultGenerator = $arrayy->getValuesYield(); @@ -4866,7 +4866,7 @@ public function testGetValuesYield(array $array) * * @param array $array */ - public function testGetGetBackwardsGenerator(array $array) + public function testGetGetBackwardsGenerator(array $array): void { $arrayy = new A($array); $resultGenerator = $arrayy->getBackwardsGenerator(); @@ -4885,7 +4885,7 @@ public function testGetGetBackwardsGenerator(array $array) * * @param array $array */ - public function testReindex(array $array) + public function testReindex(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->reindex()->getArray(); @@ -4894,7 +4894,7 @@ public function testReindex(array $array) static::assertSame([], \array_diff($resultArrayy, $resultArray)); } - public function testReindexSimple() + public function testReindexSimple(): void { $testArray = [2 => 1, 3 => 2]; $arrayy = new A($testArray); @@ -4905,7 +4905,7 @@ public function testReindexSimple() static::assertSame($result, $arrayy->getArray()); } - public function testPartition() + public function testPartition(): void { $array = [1, 2, 3, 4]; $arrayy = A::create($array)->partition( @@ -4928,7 +4928,7 @@ static function ($value, $key) { static::assertEquals([2 => 'bar', 4 => '123'], $arrayy[1]->toArray()); } - public function testReject() + public function testReject(): void { $array = [1, 2, 3, 4]; $arrayy = A::create($array)->reject( @@ -4949,7 +4949,7 @@ static function ($value, $key) { static::assertSame([2 => 'bar', 4 => '123'], $arrayy->getArray()); } - public function testValidate() + public function testValidate(): void { $array = [2, 4]; $result = A::create($array)->validate( @@ -4987,7 +4987,7 @@ static function ($value, $key) { * @param mixed $key * @param array $result */ - public function testRemove($array, $key, $result) + public function testRemove($array, $key, $result): void { $arrayy = new A($array); $resultTmp = $arrayy->remove($key)->getArray(); @@ -5000,7 +5000,7 @@ public function testRemove($array, $key, $result) * @param array $array * @param array $result */ - public function testRemoveFirst($array, $result) + public function testRemoveFirst($array, $result): void { $arrayy = A::create($array)->removeFirst(); @@ -5013,7 +5013,7 @@ public function testRemoveFirst($array, $result) * @param array $array * @param array $result */ - public function testRemoveLast($array, $result) + public function testRemoveLast($array, $result): void { $arrayy = A::create($array)->removeLast(); @@ -5027,7 +5027,7 @@ public function testRemoveLast($array, $result) * @param array $result * @param mixed $key */ - public function testRemoveV2($array, $result, $key) + public function testRemoveV2($array, $result, $key): void { $arrayy = A::create($array)->remove($key); @@ -5041,7 +5041,7 @@ public function testRemoveV2($array, $result, $key) * @param array $result * @param mixed $value */ - public function testRemoveValue($array, $result, $value) + public function testRemoveValue($array, $result, $value): void { $arrayy = A::create($array)->removeValue($value); @@ -5054,7 +5054,7 @@ public function testRemoveValue($array, $result, $value) static::assertSame($result, $arrayy->getArray()); } - public function testRepeat() + public function testRepeat(): void { $arrayTmp = ['lall']; $arrayExpected = [['lall'], ['lall'], ['lall']]; @@ -5082,7 +5082,7 @@ public function testRepeat() static::assertSame($arrayExpected, $arrayyResult->getArray()); } - public function testReplace() + public function testReplace(): void { $arraySource = [1 => 'foo', 2 => 'foo2', 3 => 'bar']; $arrayyTmp = A::create($arraySource); @@ -5097,7 +5097,7 @@ public function testReplace() static::assertSame($arraySource, $arrayyTmp->getArray()); } - public function testReplaceAllKeys() + public function testReplaceAllKeys(): void { $firstArray = [ 1 => 'one', @@ -5117,7 +5117,7 @@ public function testReplaceAllKeys() static::assertSame($resultArray, $resultArrayy); } - public function testReplaceAllKeysV2() + public function testReplaceAllKeysV2(): void { $firstArray = [ 1 => 'one', @@ -5141,7 +5141,7 @@ public function testReplaceAllKeysV2() static::assertSame($result, $resultArrayy); } - public function testReplaceAllValues() + public function testReplaceAllValues(): void { $firstArray = [ 1 => 'one', @@ -5161,7 +5161,7 @@ public function testReplaceAllValues() self::assertImmutable($arrayy, $resultArrayy, $firstArray, $resultArray); } - public function testReplaceAllValuesV2() + public function testReplaceAllValuesV2(): void { $firstArray = [ 1 => 'one', @@ -5191,7 +5191,7 @@ public function testReplaceAllValuesV2() * * @param array $array */ - public function testReplaceIn(array $array) + public function testReplaceIn(array $array): void { $secondArray = [ 'one' => 1, @@ -5211,7 +5211,7 @@ public function testReplaceIn(array $array) * * @param array $array */ - public function testReplaceInRecursively(array $array) + public function testReplaceInRecursively(array $array): void { $secondArray = [ 'one' => 1, @@ -5226,7 +5226,7 @@ public function testReplaceInRecursively(array $array) static::assertSame([], \array_diff($resultArrayy, $resultArray)); } - public function testReplaceKeys() + public function testReplaceKeys(): void { $arrayy = A::create([1 => 'bar', 'foo' => 'foo'])->replaceKeys([1 => 2, 'foo' => 'replaced']); @@ -5239,7 +5239,7 @@ public function testReplaceKeys() static::assertSame('foo', $arrayy['replaced']); } - public function testReplaceOneValue() + public function testReplaceOneValue(): void { $testArray = ['bar', 'foo' => 'foo', 'foobar' => 'foobar']; $arrayy = A::create($testArray)->replaceOneValue('foo', 'replaced'); @@ -5248,7 +5248,7 @@ public function testReplaceOneValue() static::assertSame('foobar', $arrayy['foobar']); } - public function testReplaceV2() + public function testReplaceV2(): void { $arrayyTmp = A::create([1 => 'foo', 2 => 'foo2', 3 => 'bar']); @@ -5263,7 +5263,7 @@ public function testReplaceV2() static::assertNotSame($arrayyTmp, $arrayy); } - public function testReplaceValues() + public function testReplaceValues(): void { $testArray = ['bar', 'foo' => 'foo', 'foobar' => 'foobar']; $arrayy = A::create($testArray)->replaceValues('foo', 'replaced'); @@ -5277,7 +5277,7 @@ public function testReplaceValues() * * @param array $array */ - public function testReplaceWith(array $array) + public function testReplaceWith(array $array): void { $secondArray = [ 'one' => 1, @@ -5297,7 +5297,7 @@ public function testReplaceWith(array $array) * * @param array $array */ - public function testReplaceWithRecursively(array $array) + public function testReplaceWithRecursively(array $array): void { $secondArray = [ 'one' => 1, @@ -5319,7 +5319,7 @@ public function testReplaceWithRecursively(array $array) * @param array $result * @param int $from */ - public function testRest($array, $result, $from = 1) + public function testRest($array, $result, $from = 1): void { $arrayy = A::create($array); @@ -5332,7 +5332,7 @@ public function testRest($array, $result, $from = 1) * @param array $array * @param array $result */ - public function testReverse($array, $result) + public function testReverse($array, $result): void { $arrayy = A::create($array)->reverse(); @@ -5346,7 +5346,7 @@ public function testReverse($array, $result) * @param array $array * @param mixed $value */ - public function testSearchIndex($expected, $array, $value) + public function testSearchIndex($expected, $array, $value): void { $arrayy = new A($array); @@ -5360,26 +5360,21 @@ public function testSearchIndex($expected, $array, $value) * @param array $array * @param mixed $value */ - public function testSearchValue($expected, $array, $value) + public function testSearchValue($expected, $array, $value): void { $arrayy = new A($array); static::assertSame($expected, $arrayy->searchValue($value)->getArray()); } - public function testSerialize() + public function testSerialize(): void { $testArray = [1, 4, 7]; $arrayy = A::create($testArray); $result = $arrayy->serialize(); - if (\method_exists(__CLASS__, 'assertStringContainsString')) { - static::assertStringContainsString('a:3:{i:0;i:1;i:1;i:4;i:2;i:7;}', $result); - static::assertStringContainsString($result, \serialize($arrayy)); - } else { - static::assertContains('a:3:{i:0;i:1;i:1;i:4;i:2;i:7;}', $result); - static::assertContains($result, \serialize($arrayy)); - } + static::assertStringContainsString('a:3:{i:0;i:1;i:1;i:4;i:2;i:7;}', $result); + static::assertStringContainsString($result, \serialize($arrayy)); static::assertSame($arrayy->getArray(), \unserialize(\serialize($arrayy))->getArray()); // create a object with an "arrayy"-property @@ -5391,18 +5386,10 @@ public function testSerialize() // serialize + tests if (\PHP_VERSION_ID < 70400) { - if (\method_exists(__CLASS__, 'assertStringContainsString')) { - static::assertStringContainsString('O:8:"stdClass":1:{s:6:"arrayy";C:13:"Arrayy\Arrayy":', \serialize($object)); - } else { - static::assertContains('O:8:"stdClass":1:{s:6:"arrayy";C:13:"Arrayy\Arrayy":', \serialize($object)); - } + static::assertStringContainsString('O:8:"stdClass":1:{s:6:"arrayy";C:13:"Arrayy\Arrayy":', \serialize($object)); static::assertNotSame($object, \unserialize(\serialize($object))); } else { - if (\method_exists(__CLASS__, 'assertStringContainsString')) { - static::assertStringContainsString('O:8:"stdClass":1:{s:6:"arrayy";O:13:"Arrayy\\Arrayy":', \serialize($object)); - } else { - static::assertContains('O:8:"stdClass":1:{s:6:"arrayy";O:13:"Arrayy\\Arrayy":', \serialize($object)); - } + static::assertStringContainsString('O:8:"stdClass":1:{s:6:"arrayy";O:13:"Arrayy\\Arrayy":', \serialize($object)); static::assertNotSame($object, \unserialize(\serialize($object))); } @@ -5427,26 +5414,18 @@ public function testSerialize() // serialize + tests if (\PHP_VERSION_ID < 70400) { static::assertInstanceOf(CityData::class, $model); - if (\method_exists(__CLASS__, 'assertStringContainsString')) { - static::assertStringContainsString('C:21:"Arrayy\tests\CityData":', \serialize($model)); - } else { - static::assertContains('C:21:"Arrayy\tests\CityData":', \serialize($model)); - } + static::assertStringContainsString('C:21:"Arrayy\tests\CityData":', \serialize($model)); static::assertNotSame($model, \unserialize(\serialize($model))); static::assertInstanceOf(CityData::class, $model); } else { static::assertInstanceOf(CityData::class, $model); - if (\method_exists(__CLASS__, 'assertStringContainsString')) { - static::assertStringContainsString('O:21:"Arrayy\tests\CityData":', \serialize($model)); - } else { - static::assertContains('O:21:"Arrayy\tests\CityData":', \serialize($model)); - } + static::assertStringContainsString('O:21:"Arrayy\tests\CityData":', \serialize($model)); static::assertNotSame($model, \unserialize(\serialize($model))); static::assertInstanceOf(CityData::class, $model); } } - public function testSerializeSimple() + public function testSerializeSimple(): void { $arrayy = A::create([1, 'a', 4.4]); @@ -5460,7 +5439,7 @@ public function testSerializeSimple() * @param mixed $key * @param mixed $value */ - public function testSet($array, $key, $value) + public function testSet($array, $key, $value): void { $arrayy = new A($array); $arrayy = $arrayy->set($key, $value)->getArray(); @@ -5474,14 +5453,14 @@ public function testSet($array, $key, $value) * @param mixed $key * @param mixed $value */ - public function testSetAndGet($array, $key, $value) + public function testSetAndGet($array, $key, $value): void { $arrayy = new A($array); $result = $arrayy->setAndGet($key, $value); static::assertSame($value, $result); } - public function testSetAndGetSimple() + public function testSetAndGetSimple(): void { $arrayy = new A([1, 2, 3]); $result = $arrayy->setAndGet(0, 4); @@ -5498,7 +5477,7 @@ public function testSetAndGetSimple() static::assertSame($expected, $result); } - public function testSetV2() + public function testSetV2(): void { $arrayy = new A(['foo bar', 'UTF-8']); $arrayy[1] = 'öäü'; @@ -5506,15 +5485,15 @@ public function testSetV2() static::assertSame('foo bar,öäü', (string) $arrayy); } - public function testSetValueViaMagicSet() + public function testSetValueViaMagicSet(): void { $arrayy = new A(['Lars' => ['lastname' => 'Mueller2']]); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ $arrayy->Lars = ['lastname' => 'Moelleken']; - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ $arrayy->Sven = ['lastname' => 'Moelleken']; - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ $arrayy->foo = ['lastname' => null]; $resultTmp = $arrayy->get('Lars'); @@ -5536,7 +5515,7 @@ public function testSetValueViaMagicSet() static::assertNull($resultTmp); } - public function testSetViaDotNotation() + public function testSetViaDotNotation(): void { $arrayy = new A(['Lars' => ['lastname' => 'Moelleken']]); @@ -5547,10 +5526,10 @@ public function testSetViaDotNotation() static::assertSame(['lastname' => 'Moelleken'], $arrayy['Lars']->getArray()); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ static::assertSame(['lastname' => 'Moelleken'], $arrayy->Lars->getArray()); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ static::assertSame('Moelleken', $arrayy->Lars->lastname); static::assertSame('Moelleken', $arrayy['Lars']['lastname']); @@ -5585,7 +5564,7 @@ public function testSetViaDotNotation() static::assertSame('Mueller', $resultTmp); // set a new value, again - via object-syntax - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore property.notFound */ $arrayy->Lars = ['lastname' => 'Mueller2']; $resultTmp = $arrayy->get('Lars'); @@ -5607,7 +5586,7 @@ public function testSetViaDotNotation() * * @param array $array */ - public function testShift(array $array) + public function testShift(array $array): void { $arrayy = new A($array); $shiftedValue = $arrayy->shift(); @@ -5618,7 +5597,7 @@ public function testShift(array $array) static::assertSame($resultArray, $arrayy->toArray()); } - public function testShuffle() + public function testShuffle(): void { $arrayy = A::create([1 => 'bar', 'foo' => 'foo'])->shuffle(); @@ -5633,7 +5612,7 @@ public function testShuffle() static::assertContains('foo', $arrayy->getArray()); } - public function testSimpleAt() + public function testSimpleAt(): void { $result = A::create(); $closure = static function ($value, $key) use ($result) { @@ -5644,7 +5623,7 @@ public function testSimpleAt() static::assertSame(A::create([':foo:', 'bar' => ':bis:'])->getArray(), $result->getArray()); } - public function testSizeIs() + public function testSizeIs(): void { $a = A::create([1, 2]); @@ -5653,7 +5632,7 @@ public function testSizeIs() static::assertFalse($a->sizeIs(0)); } - public function testSizeIsLessThen() + public function testSizeIsLessThen(): void { $a = A::create([1, 2]); @@ -5662,7 +5641,7 @@ public function testSizeIsLessThen() static::assertTrue($a->sizeIsLessThan(3)); } - public function testSizeIsGreaterThan() + public function testSizeIsGreaterThan(): void { $a = A::create([1, 2]); @@ -5671,7 +5650,7 @@ public function testSizeIsGreaterThan() static::assertTrue($a->sizeIsGreaterThan(0)); } - public function testSizeIsBetween() + public function testSizeIsBetween(): void { $a = A::create([1, 2]); @@ -5681,7 +5660,7 @@ public function testSizeIsBetween() static::assertTrue($a->sizeIsBetween(3, 1)); } - public function testSimpleEach() + public function testSimpleEach(): void { $closure = static function ($value) { return ':' . $value . ':'; @@ -5691,7 +5670,7 @@ public function testSimpleEach() static::assertSame([':foo:', 'bar' => ':bis:'], $result->getArray()); } - public function testSimpleRandom() + public function testSimpleRandom(): void { $testArray = [-8 => -9, 1, 2 => false]; $arrayy = A::create($testArray); @@ -5722,7 +5701,7 @@ public function testSimpleRandom() static::assertCount(3, $result); } - public function testSimpleRandomWeighted() + public function testSimpleRandomWeighted(): void { $testArray = ['foo', 'bar']; $result = A::create($testArray)->randomWeighted(['bar' => 2]); @@ -5738,7 +5717,7 @@ public function testSimpleRandomWeighted() * * @param array $array */ - public function testSlice(array $array) + public function testSlice(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->slice(1, 1); @@ -5747,7 +5726,7 @@ public function testSlice(array $array) self::assertImmutable($arrayy, $resultArrayy, $array, $resultArray); } - public function testSort() + public function testSort(): void { $testArray = [5, 3, 1, 2, 4]; $under = A::create($testArray)->sorter(null, 'desc'); @@ -5797,7 +5776,7 @@ static function ($value) { * * @param array $array */ - public function testSortAscWithPreserveKeys(array $array) + public function testSortAscWithPreserveKeys(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->sort(\SORT_ASC, \SORT_REGULAR, true); @@ -5830,7 +5809,7 @@ public function testSortAscWithPreserveKeys(array $array) * * @param array $array */ - public function testSortAscWithoutPreserveKeys(array $array) + public function testSortAscWithoutPreserveKeys(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->sort(\SORT_ASC, \SORT_REGULAR, false); @@ -5854,7 +5833,7 @@ public function testSortAscWithoutPreserveKeys(array $array) * * @param array $array */ - public function testSortDescWithPreserveKeys(array $array) + public function testSortDescWithPreserveKeys(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->sort(\SORT_DESC, \SORT_REGULAR, true); @@ -5878,7 +5857,7 @@ public function testSortDescWithPreserveKeys(array $array) * * @param array $array */ - public function testSortImmutableDescWithPreserveKeys(array $array) + public function testSortImmutableDescWithPreserveKeys(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->sortImmutable(\SORT_DESC, \SORT_REGULAR, true); @@ -5902,7 +5881,7 @@ public function testSortImmutableDescWithPreserveKeys(array $array) * * @param array $array */ - public function testSortDescWithoutPreserveKeys(array $array) + public function testSortDescWithoutPreserveKeys(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->sort(\SORT_DESC, \SORT_REGULAR, false); @@ -5937,7 +5916,7 @@ public function testSortDescWithoutPreserveKeys(array $array) * @param array $result * @param string $direction */ - public function testSortKeys($array, $result, $direction = 'ASC') + public function testSortKeys($array, $result, $direction = 'ASC'): void { $arrayy = A::create($array)->sortKeys($direction); @@ -5949,7 +5928,7 @@ public function testSortKeys($array, $result, $direction = 'ASC') * * @param array $array */ - public function testSortKeysAsc(array $array) + public function testSortKeysAsc(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->sortKeys(\SORT_ASC, \SORT_REGULAR); @@ -5982,7 +5961,7 @@ public function testSortKeysAsc(array $array) * * @param array $array */ - public function testNatcasesort(array $array) + public function testNatcasesort(array $array): void { \natcasesort($array); $arrayy = new A($array); @@ -5998,7 +5977,7 @@ public function testNatcasesort(array $array) * * @param array $array */ - public function testNatsortImmutable(array $array) + public function testNatsortImmutable(array $array): void { \natsort($array); $arrayy = new A($array); @@ -6014,7 +5993,7 @@ public function testNatsortImmutable(array $array) * * @param array $array */ - public function testNatsort(array $array) + public function testNatsort(array $array): void { \natsort($array); $arrayy = new A($array); @@ -6030,7 +6009,7 @@ public function testNatsort(array $array) * * @param array $array */ - public function testNatcasesortImmutable(array $array) + public function testNatcasesortImmutable(array $array): void { \natcasesort($array); $arrayy = new A($array); @@ -6046,7 +6025,7 @@ public function testNatcasesortImmutable(array $array) * * @param array $array */ - public function testUasort(array $array) + public function testUasort(array $array): void { $function = static function ($a, $b) { if ($a == $b) { @@ -6069,7 +6048,7 @@ public function testUasort(array $array) * * @param array $array */ - public function testUasortImmutable(array $array) + public function testUasortImmutable(array $array): void { $function = static function ($a, $b) { if ($a == $b) { @@ -6092,7 +6071,7 @@ public function testUasortImmutable(array $array) * * @param array $array */ - public function testSortKeysDesc(array $array) + public function testSortKeysDesc(array $array): void { $arrayy = new A($array); $resultArrayy = $arrayy->sortKeys(\SORT_DESC, \SORT_REGULAR); @@ -6120,7 +6099,7 @@ public function testSortKeysDesc(array $array) self::assertImmutable($arrayy, $resultArrayy, $array, $resultArrayV2->getArray()); } - public function testSortV2() + public function testSortV2(): void { $array = [ 1 => 'hcd', @@ -6144,7 +6123,7 @@ public function testSortV2() static::assertSame($expected, $result); } - public function testSplit() + public function testSplit(): void { self::assertArrayy(A::create()->split()); @@ -6195,7 +6174,7 @@ public function testSplit() * * @param array $array */ - public function testStaticCreate(array $array) + public function testStaticCreate(array $array): void { $arrayy = new A($array); $resultArrayy = A::create($array); @@ -6208,7 +6187,7 @@ public function testStaticCreate(array $array) * * @param array $array */ - public function testStaticCreateFromGeneratorImmutableFromArray(array $array) + public function testStaticCreateFromGeneratorImmutableFromArray(array $array): void { $arrayy = A::create($array); $generator = $arrayy->getGenerator(); @@ -6223,7 +6202,7 @@ public function testStaticCreateFromGeneratorImmutableFromArray(array $array) * @param array $array * @param int $count */ - public function testStaticCreateFromGeneratorFunctionFromArray(array $array, int $count) + public function testStaticCreateFromGeneratorFunctionFromArray(array $array, int $count): void { $arrayy = A::create($array); $resultArrayy = A::createFromGeneratorFunction( @@ -6242,7 +6221,7 @@ static function () use ($arrayy) { * * @param array $array */ - public function testStaticCreateFromJson(array $array) + public function testStaticCreateFromJson(array $array): void { $json = (string) \json_encode($array); @@ -6257,7 +6236,7 @@ public function testStaticCreateFromJson(array $array) * * @param array $array */ - public function testStaticCreateFromObject(array $array) + public function testStaticCreateFromObject(array $array): void { $arrayy = A::create($array); $resultArrayy = A::createFromObject($arrayy); @@ -6265,7 +6244,7 @@ public function testStaticCreateFromObject(array $array) self::assertImmutable($arrayy, $resultArrayy, $array, $array); } - public function testCustomMerge() + public function testCustomMerge(): void { $arr = [ 0 => ['title' => 'A', 'quantity' => 2], @@ -6292,7 +6271,7 @@ public function testCustomMerge() ); } - public function testCreateFromObjectAndDot() + public function testCreateFromObjectAndDot(): void { $s = new \stdClass(); $s->foo = 'bar'; @@ -6323,7 +6302,7 @@ public function testCreateFromObjectAndDot() static::assertSame($expected, $services->getArray()); } - public function testStaticCreateFromObjectVars() + public function testStaticCreateFromObjectVars(): void { $a = new \stdClass(); $a->x = 42; @@ -6348,7 +6327,7 @@ public function testStaticCreateFromObjectVars() * @param string $string * @param non-empty-string|null $separator */ - public function testStaticCreateFromString($string, $separator) + public function testStaticCreateFromString($string, $separator): void { if ($separator !== null) { $array = \explode($separator, $string); @@ -6363,7 +6342,7 @@ public function testStaticCreateFromString($string, $separator) self::assertImmutable($arrayy, $resultArrayy, $array, $array); } - public function testStripEmpty() + public function testStripEmpty(): void { $arrayy = new A(['id' => 999, 'name' => 'flux', 'group' => null, 'value' => 6868, 'when' => '2015-01-01']); $arrayyResult = new A(['id' => 999, 'name' => 'flux', 'value' => 6868, 'when' => '2015-01-01']); @@ -6371,7 +6350,7 @@ public function testStripEmpty() static::assertSame($arrayyResult->toString(), $arrayy->stripEmpty()->toString()); } - public function testSwap() + public function testSwap(): void { $arrayy = new A(['id' => 999, 'name' => 'flux', 'group' => null, 'value' => 6868, 'when' => '2015-01-01']); $arrayyResult = new A( @@ -6394,7 +6373,7 @@ public function testSwap() * @param array $arrayNew * @param array $result */ - public function testTestdiffReverse($array, $arrayNew, $result) + public function testTestdiffReverse($array, $arrayNew, $result): void { $arrayy = A::create($array)->diffReverse($arrayNew); @@ -6407,7 +6386,7 @@ public function testTestdiffReverse($array, $arrayNew, $result) * @param array $array * @param bool $result */ - public function testTestisMultiArray($array, $result) + public function testTestisMultiArray($array, $result): void { $resultTmp = A::create($array)->isMultiArray(); @@ -6420,7 +6399,7 @@ public function testTestisMultiArray($array, $result) * @param string $expected * @param array $array */ - public function testToString($expected, $array) + public function testToString($expected, $array): void { static::assertSame($expected, (string) new A($array)); } @@ -6431,7 +6410,7 @@ public function testToString($expected, $array) * @param array $array * @param array $result */ - public function testUnique($array, $result) + public function testUnique($array, $result): void { $arrayy = A::create($array)->unique(); static::assertSame($result, $arrayy->getArray()); @@ -6446,13 +6425,13 @@ public function testUnique($array, $result) * @param array $array * @param array $result */ - public function testUniqueKeepIndex($array, $result) + public function testUniqueKeepIndex($array, $result): void { $arrayy = A::create($array)->uniqueKeepIndex(); static::assertSame($result, $arrayy->getArray()); } - public function testUnset() + public function testUnset(): void { $arrayy = new A(['foo bar', 'öäü']); unset($arrayy[1]); @@ -6461,7 +6440,7 @@ public function testUnset() static::assertNull($arrayy[1]); } - public function testUnsetSimple() + public function testUnsetSimple(): void { $arrayy = new A([1 => 1, 2 => 2, 3 => 3]); unset($arrayy[2]); @@ -6479,7 +6458,7 @@ public function testUnsetSimple() * * @param array $array */ - public function testUnshift(array $array) + public function testUnshift(array $array): void { $newElement1 = 5; $newElement2 = 10; @@ -6492,7 +6471,7 @@ public function testUnshift(array $array) self::assertMutable($arrayy, $resultArrayy, $resultArray); } - public function testValues() + public function testValues(): void { $arrayyTmp = A::create([1 => 'foo', 2 => 'foo2', 3 => 'bar']); $values = $arrayyTmp->values(); @@ -6506,7 +6485,7 @@ public function testValues() * * @param array $array */ - public function testWalk(array $array) + public function testWalk(array $array): void { $callable = static function (&$value, $key) { $value = $key; @@ -6525,7 +6504,7 @@ public function testWalk(array $array) * * @param array $array */ - public function testWalkRecursively(array $array) + public function testWalkRecursively(array $array): void { $callable = static function (&$value, $key) { $value = $key; @@ -6539,7 +6518,7 @@ public function testWalkRecursively(array $array) self::assertMutable($arrayy, $resultArrayy, $resultArray); } - public function testWalkSimple() + public function testWalkSimple(): void { $callable = static function (&$value, $key) { $value = $key; @@ -6553,7 +6532,7 @@ public function testWalkSimple() static::assertSame($expected, $resultArrayy->getArray()); } - public function testWalkSimpleRecursively() + public function testWalkSimpleRecursively(): void { $callable = static function (&$value, $key) { $value = $key; @@ -6697,12 +6676,12 @@ public function uniqueProviderKeepIndex(): array } /** - * @param A $arrayzy - * @param A|A|A $resultArrayzy + * @param A> $arrayzy + * @param A>|A>|A> $resultArrayzy * @param array $array * @param array $resultArray */ - protected static function assertImmutable(A $arrayzy, A $resultArrayzy, array $array, array $resultArray) + protected static function assertImmutable(A $arrayzy, A $resultArrayzy, array $array, array $resultArray): void { static::assertNotSame($arrayzy, $resultArrayzy); static::assertSame($array, $arrayzy->toArray()); @@ -6710,11 +6689,11 @@ protected static function assertImmutable(A $arrayzy, A $resultArrayzy, array $a } /** - * @param A $arrayzy - * @param A $resultArrayzy + * @param A> $arrayzy + * @param A> $resultArrayzy * @param array $resultArray */ - protected static function assertMutable(A $arrayzy, A $resultArrayzy, array $resultArray) + protected static function assertMutable(A $arrayzy, A $resultArrayzy, array $resultArray): void { static::assertSame($arrayzy, $resultArrayzy); static::assertSame($resultArray, $arrayzy->toArray()); diff --git a/tests/BasicArrayTest.php b/tests/BasicArrayTest.php index ae7e722..e671c94 100644 --- a/tests/BasicArrayTest.php +++ b/tests/BasicArrayTest.php @@ -24,7 +24,7 @@ final class BasicArrayTest extends \PHPUnit\Framework\TestCase const TYPE_NUMERIC = 'numeric'; /** - * @var class-string<\Arrayy\Arrayy> + * @var class-string<\Arrayy\Arrayy>> */ protected $arrayyClassName = A::class; @@ -92,7 +92,7 @@ public function stringWithSeparatorProvider(): array * * @param array $array */ - public function testContains(array $array) + public function testContains(array $array): void { $element = 2; @@ -107,7 +107,7 @@ public function testContains(array $array) * * @param array $array */ - public function testContainsKey(array $array) + public function testContainsKey(array $array): void { $key = 2; @@ -122,7 +122,7 @@ public function testContainsKey(array $array) * * @param array $array */ - public function testCount(array $array) + public function testCount(array $array): void { $arrayy = $this->createArrayy($array); $count = \count($array); @@ -135,7 +135,7 @@ public function testCount(array $array) * * @param array $array */ - public function testCurrent(array $array) + public function testCurrent(array $array): void { $arrayy = $this->createArrayy($array); $current = \current($array); @@ -149,7 +149,7 @@ public function testCurrent(array $array) * * @param array $array */ - public function testDebugReturn(array $array) + public function testDebugReturn(array $array): void { $arrayy = $this->createArrayy($array); $printed = \print_r($array, true); @@ -162,7 +162,7 @@ public function testDebugReturn(array $array) * * @param array $array */ - public function testExists(array $array) + public function testExists(array $array): void { $callable = static function ($value, $key) { return $key === 2 && $value === 'two'; @@ -174,7 +174,7 @@ public function testExists(array $array) static::assertSame($isExists, $arrayy->exists($callable)); } - public function testFind() + public function testFind(): void { $callable = static function ($value, $key) { return $value === 'a' && $key > 2; @@ -191,7 +191,7 @@ public function testFind() * * @param array $array */ - public function testFirstMutable(array $array) + public function testFirstMutable(array $array): void { $arrayy = $this->createArrayy($array); $first = \reset($array); @@ -211,7 +211,7 @@ public function testFirstMutable(array $array) * * @param array $array */ - public function testFirstInLoop(array $array) + public function testFirstInLoop(array $array): void { $arrayy = $this->createArrayy($array); $first = \reset($array); @@ -244,7 +244,7 @@ public function testFirstInLoop(array $array) * * @param array $array */ - public function testFirstImmutable(array $array) + public function testFirstImmutable(array $array): void { $arrayy = $this->createArrayy($array); $first = \reset($array); @@ -264,7 +264,7 @@ public function testFirstImmutable(array $array) * * @param array $array */ - public function testFirstImmutableInLoop(array $array) + public function testFirstImmutableInLoop(array $array): void { $arrayy = $this->createArrayy($array); $first = \reset($array); @@ -292,7 +292,7 @@ public function testFirstImmutableInLoop(array $array) static::assertSame($count, $tmpCount); } - public function testForEachWithInnerArrayy() + public function testForEachWithInnerArrayy(): void { $arrayy = $this->createArrayy(['foo' => [3 => [33, 34, 35], 2 => [22, 23, 24], 1 => [11, 12, 13]]]); @@ -311,7 +311,7 @@ public function testForEachWithInnerArrayy() } } - public function testGetIterator() + public function testGetIterator(): void { $arrayy = $this->createArrayy(['foo', 'bar', 1, null]); @@ -322,7 +322,7 @@ public function testGetIterator() static::assertSame('bar', $result->current()); } - public function testRecursiveIterator() + public function testRecursiveIterator(): void { $arrayy = Arrayy::create(['1', '1', Arrayy::create(['2', '2', '2', Arrayy::create(['3', 3])]), 1]); @@ -345,7 +345,7 @@ public function testRecursiveIterator() static::assertSame($expected, $result); } - public function testGetIteratorWithSubArray() + public function testGetIteratorWithSubArray(): void { $arrayy = $this->createArrayy(['foo' => [3, 2, 1], 'bar' => [1, 2, 3], 1, null]); @@ -363,7 +363,7 @@ public function testGetIteratorWithSubArray() * * @param array $array */ - public function testGetKeys(array $array) + public function testGetKeys(array $array): void { $arrayy = $this->createArrayy($array); $keys = \array_keys($array); @@ -376,7 +376,7 @@ public function testGetKeys(array $array) * * @param array $array */ - public function testGetObject(array $array) + public function testGetObject(array $array): void { $arrayy = $this->createArrayy($array); $result = \Arrayy\Arrayy::createFromObjectVars($arrayy->getObject())->toArray(); @@ -389,7 +389,7 @@ public function testGetObject(array $array) * * @param array $array */ - public function testGetRandom(array $array) + public function testGetRandom(array $array): void { $arrayy = $this->createArrayy($array); $value = $arrayy->getRandom()->getArray(); @@ -398,12 +398,7 @@ public function testGetRandom(array $array) static::assertNotNull($value[0]); static::assertContains($value[0], $arrayy->toArray()); } else { - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($value); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $value); - } + static::assertIsArray($value); } } @@ -412,7 +407,7 @@ public function testGetRandom(array $array) * * @param array $array */ - public function testGetRandomKey(array $array) + public function testGetRandomKey(array $array): void { $arrayy = $this->createArrayy($array); @@ -423,12 +418,7 @@ public function testGetRandomKey(array $array) static::assertNotNull($key); static::assertArrayHasKey($key, $arrayy->toArray()); } else { - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($arrayy->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $arrayy->getArray()); - } + static::assertIsArray($arrayy->getArray()); } } @@ -437,17 +427,12 @@ public function testGetRandomKey(array $array) * * @param array $array */ - public function testGetRandomKeys(array $array) + public function testGetRandomKeys(array $array): void { $arrayy = $this->createArrayy($array); if (\count($array) < 2) { - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($arrayy->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $arrayy->getArray()); - } + static::assertIsArray($arrayy->getArray()); } else { $keys = $arrayy->getRandomKeys(2); @@ -458,7 +443,7 @@ public function testGetRandomKeys(array $array) } } - public function testGetRandomKeysLogicExceptionGivenZero() + public function testGetRandomKeysLogicExceptionGivenZero(): void { $this->expectException(\RangeException::class); @@ -466,7 +451,7 @@ public function testGetRandomKeysLogicExceptionGivenZero() $arrayy->getRandomKeys(0); } - public function testGetRandomKeysRangeException() + public function testGetRandomKeysRangeException(): void { $this->expectException(\RangeException::class); @@ -479,26 +464,16 @@ public function testGetRandomKeysRangeException() * * @param array $array */ - public function testGetRandomKeysShouldReturnArray(array $array) + public function testGetRandomKeysShouldReturnArray(array $array): void { $arrayy = $this->createArrayy($array); if (\count($array) === 0) { - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($arrayy->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $arrayy->getArray()); - } + static::assertIsArray($arrayy->getArray()); } else { $keys = $arrayy->getRandomKeys(\count($array))->getArray(); - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($keys); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $keys); - } + static::assertIsArray($keys); } } @@ -507,17 +482,12 @@ public function testGetRandomKeysShouldReturnArray(array $array) * * @param array $array */ - public function testGetRandomValueSingle(array $array) + public function testGetRandomValueSingle(array $array): void { $arrayy = $this->createArrayy($array); if (\count($array) === 0) { - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($arrayy->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $arrayy->getArray()); - } + static::assertIsArray($arrayy->getArray()); } else { $value = $arrayy->getRandomValue(); @@ -535,17 +505,12 @@ public function testGetRandomValueSingle(array $array) * * @param array $array */ - public function testGetRandomValues(array $array) + public function testGetRandomValues(array $array): void { $arrayy = $this->createArrayy($array); if (\count($array) < 2) { - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($arrayy->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $arrayy->getArray()); - } + static::assertIsArray($arrayy->getArray()); return; } @@ -565,17 +530,12 @@ public function testGetRandomValues(array $array) * * @param array $array */ - public function testGetRandomValuesSingle(array $array) + public function testGetRandomValuesSingle(array $array): void { $arrayy = $this->createArrayy($array); if (\count($array) === 0) { - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($arrayy->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $arrayy->getArray()); - } + static::assertIsArray($arrayy->getArray()); return; } @@ -583,12 +543,7 @@ public function testGetRandomValuesSingle(array $array) $values = $arrayy->getRandomValues(1)->getArray(); static::assertCount(1, $values); - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($arrayy->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $arrayy->getArray()); - } + static::assertIsArray($arrayy->getArray()); foreach ($values as $value) { if (!$value instanceof \Arrayy\Arrayy) { static::assertContains($value, $array); @@ -601,7 +556,7 @@ public function testGetRandomValuesSingle(array $array) * * @param array $array */ - public function testIndexOf(array $array) + public function testIndexOf(array $array): void { $element = 2; @@ -617,7 +572,7 @@ public function testIndexOf(array $array) * @param array $array * @param string $type */ - public function testIsAssoc(array $array, $type = null) + public function testIsAssoc(array $array, $type = null): void { $arrayy = $this->createArrayy($array); $isAssoc = static::TYPE_ASSOC === $type; @@ -630,7 +585,7 @@ public function testIsAssoc(array $array, $type = null) * * @param array $array */ - public function testIsEmpty(array $array) + public function testIsEmpty(array $array): void { $isEmpty = !$array; $arrayy = $this->createArrayy($array); @@ -644,7 +599,7 @@ public function testIsEmpty(array $array) * @param array $array * @param string $type */ - public function testIsNumeric(array $array, $type = null) + public function testIsNumeric(array $array, $type = null): void { $arrayy = $this->createArrayy($array); $isNumeric = static::TYPE_NUMERIC === $type; @@ -657,7 +612,7 @@ public function testIsNumeric(array $array, $type = null) * * @param array $array */ - public function testKey(array $array) + public function testKey(array $array): void { $arrayy = $this->createArrayy($array); $key = \key($array); @@ -671,7 +626,7 @@ public function testKey(array $array) * * @param array $array */ - public function testLast(array $array) + public function testLast(array $array): void { $arrayy = $this->createArrayy($array); $last = \end($array); @@ -693,7 +648,7 @@ public function testLast(array $array) * * @param array $array */ - public function testLastKey(array $array) + public function testLastKey(array $array): void { $arrayy = $this->createArrayy($array); $last = \array_key_last($array); @@ -703,7 +658,7 @@ public function testLastKey(array $array) $last = null; } - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore instanceof.alwaysFalse */ if ($result instanceof Arrayy) { $result = $result->getArray(); } @@ -716,7 +671,7 @@ public function testLastKey(array $array) * * @param array $array */ - public function testArrayyFirst(array $array) + public function testArrayyFirst(array $array): void { $arrayy = $this->createArrayy($array); $first = array_first($array); @@ -738,7 +693,7 @@ public function testArrayyFirst(array $array) * * @param array $array */ - public function testArrayyLast(array $array) + public function testArrayyLast(array $array): void { $arrayy = $this->createArrayy($array); $first = array_last($array); @@ -760,7 +715,7 @@ public function testArrayyLast(array $array) * * @param array $array */ - public function testFirstKey(array $array) + public function testFirstKey(array $array): void { $arrayy = $this->createArrayy($array); $first = \array_key_first($array); @@ -778,7 +733,7 @@ public function testFirstKey(array $array) * * @param array $array */ - public function testMostUsedValue(array $array) + public function testMostUsedValue(array $array): void { $arrayy = $this->createArrayy($array); if ($arrayy->isMultiArray()) { @@ -805,7 +760,7 @@ public function testMostUsedValue(array $array) static::assertSame($first, $result); } - public function testArrayyIterator() + public function testArrayyIterator(): void { $iterator = new ArrayyIterator(['foo' => 'bar']); @@ -824,7 +779,7 @@ public function testArrayyIterator() * * @param array $array */ - public function testMostUsedValues(array $array) + public function testMostUsedValues(array $array): void { $arrayy = $this->createArrayy($array); if ($arrayy->isMultiArray()) { @@ -856,7 +811,7 @@ public function testMostUsedValues(array $array) * * @param array $array */ - public function testNext(array $array) + public function testNext(array $array): void { $arrayy = $this->createArrayy($array)->getArray(); $next = \next($array); @@ -869,7 +824,7 @@ public function testNext(array $array) * * @param array $array */ - public function testOffsetExists(array $array) + public function testOffsetExists(array $array): void { $offset = 1; $isOffsetExists = isset($array[$offset]); @@ -884,7 +839,7 @@ public function testOffsetExists(array $array) * * @param array $array */ - public function testOffsetGet(array $array) + public function testOffsetGet(array $array): void { $offset = 1; $value = $array[$offset] ?? null; @@ -899,7 +854,7 @@ public function testOffsetGet(array $array) * * @param array $array */ - public function testPrevious(array $array) + public function testPrevious(array $array): void { $arrayy = $this->createArrayy($array)->getArray(); $prev = \prev($array); @@ -912,7 +867,7 @@ public function testPrevious(array $array) * * @param array $array */ - public function testReIndex(array $array) + public function testReIndex(array $array): void { $arrayy = $this->createArrayy($array); $values = \array_values($array); @@ -920,7 +875,7 @@ public function testReIndex(array $array) static::assertSame($values, $arrayy->reindex()->getArray()); } - public function testReduce() + public function testReduce(): void { $func = static function ($resultArray, $value) { if ($value % 2 === 0) { @@ -991,7 +946,7 @@ public function testReduce() static::assertSame([2, 3, 4], $arrayy->getArray()); } - public function testGetArrayViaGenerator() + public function testGetArrayViaGenerator(): void { $generator = static function () { yield 1 => 2; @@ -1004,7 +959,7 @@ public function testGetArrayViaGenerator() static::assertSame([2, 3], $arrayy->getArray(false, false)); } - public function testGetListViaGenerator() + public function testGetListViaGenerator(): void { $generator = static function () { yield 1 => 2; @@ -1022,7 +977,7 @@ public function testGetListViaGenerator() * * @param array $array */ - public function testToJson(array $array) + public function testToJson(array $array): void { $json = \json_encode($array); @@ -1037,7 +992,7 @@ public function testToJson(array $array) * @param string $string * @param non-empty-string $separator */ - public function testToString($string, $separator) + public function testToString($string, $separator): void { $array = \explode($separator, $string); \assert(\is_array($array)); @@ -1055,7 +1010,7 @@ public function testToString($string, $separator) * @param array $array * @param array $resultArray */ - protected function assertImmutable(A $arrayy, A $resultArrayy, array $array, array $resultArray) + protected function assertImmutable(A $arrayy, A $resultArrayy, array $array, array $resultArray): void { static::assertNotSame($arrayy, $resultArrayy); static::assertSame($array, $arrayy->toArray()); @@ -1067,7 +1022,7 @@ protected function assertImmutable(A $arrayy, A $resultArrayy, array $array, arr * @param A $resultArrayy * @param array $resultArray */ - protected function assertMutable(A $arrayy, A $resultArrayy, array $resultArray) + protected function assertMutable(A $arrayy, A $resultArrayy, array $resultArray): void { static::assertSame($arrayy, $resultArrayy); static::assertSame($resultArray, $arrayy->toArray()); diff --git a/tests/CityData.php b/tests/CityData.php index 636b6d3..62170a2 100644 --- a/tests/CityData.php +++ b/tests/CityData.php @@ -7,7 +7,7 @@ * @property string $name * @property string[] $infos * - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class CityData extends \Arrayy\Arrayy { diff --git a/tests/CityDataTest.php b/tests/CityDataTest.php index de3e013..ec10c59 100644 --- a/tests/CityDataTest.php +++ b/tests/CityDataTest.php @@ -11,14 +11,14 @@ */ final class CityDataTest extends \PHPUnit\Framework\TestCase { - public function testParameterMatchEmpty() + public function testParameterMatchEmpty(): void { $model = new CityData([]); static::assertInstanceOf(Arrayy::class, $model); } - public function testParameterMatchFail() + public function testParameterMatchFail(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected "infos" to be of type {string[]}, instead got value "foo" (foo) with type {string}.'); @@ -36,7 +36,7 @@ public function testParameterMatchFail() static::assertInstanceOf(Arrayy::class, $model); } - public function testParameterMatchFailV2() + public function testParameterMatchFailV2(): void { $this->expectException(\TypeError::class); @@ -53,7 +53,7 @@ public function testParameterMatchFailV2() static::assertInstanceOf(Arrayy::class, $model); } - public function testParameterMatchFailWithArray() + public function testParameterMatchFailWithArray(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Property mismatch'); @@ -69,7 +69,7 @@ public function testParameterMatchFailWithArray() static::assertInstanceOf(Arrayy::class, $model); } - public function testSetAndGet() + public function testSetAndGet(): void { $modelMeta = CityData::meta(); @@ -88,7 +88,7 @@ public function testSetAndGet() static::assertNull($model[3]); } - public function testDataFromJsonMapper() + public function testDataFromJsonMapper(): void { $jsonData = '{"name":"D\u00fcsseldorf","plz":null,"infos":["foo","bar","lall"]}'; @@ -102,7 +102,7 @@ public function testDataFromJsonMapper() static::assertNull($model[3]); } - public function testDataFromJsonMapperRejectsInvalidArrayElementTypes() + public function testDataFromJsonMapperRejectsInvalidArrayElementTypes(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected "infos" to be of type {string[]}'); @@ -113,7 +113,7 @@ public function testDataFromJsonMapperRejectsInvalidArrayElementTypes() /** * @depends testSetAndGet */ - public function testSetAndGetAgain() + public function testSetAndGetAgain(): void { $modelMeta = CityData::meta(); @@ -131,7 +131,7 @@ public function testSetAndGetAgain() static::assertNull($model[3]); } - public function testExtendedClass() + public function testExtendedClass(): void { $modelMeta = BigCityData::meta(); @@ -150,19 +150,10 @@ public function testExtendedClass() static::assertSame('lall', $model[$modelMeta->extra_info]); } - public function testExtendedClassV2() + public function testExtendedClassV2(): void { $this->expectException(\TypeError::class); - if ( - \class_exists(\Composer\InstalledVersions::class) - && - \version_compare((string) \Composer\InstalledVersions::getPrettyVersion('phpunit/phpunit'), '8.4.0', '>=') - ) { - $this->expectExceptionMessageMatches('#Invalid type: expected "plz" to be of type {string}, instead got value "NULL"#'); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - $this->expectExceptionMessageRegExp('#Invalid type: expected "plz" to be of type {string}, instead got value "NULL"#'); - } + $this->expectExceptionMessageMatches('#Invalid type: expected "plz" to be of type {string}, instead got value "NULL"#'); $modelMeta = BigCityData::meta(); new BigCityData( diff --git a/tests/Collection/ArrayTypeTest.php b/tests/Collection/ArrayTypeTest.php index 0d183c2..efc64a7 100644 --- a/tests/Collection/ArrayTypeTest.php +++ b/tests/Collection/ArrayTypeTest.php @@ -12,7 +12,7 @@ */ final class ArrayTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new ArrayCollection([['a', 1, 1.4], [], [true, new \stdClass()], []]); @@ -22,11 +22,11 @@ public function testArray() ); } - public function testStringArrayFalse() + public function testStringArrayFalse(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ $set = new \Arrayy\Type\StringArrayCollection([['a', 1, 1.4], [], [true, new \stdClass()], []]); static::assertEquals( @@ -35,7 +35,7 @@ public function testStringArrayFalse() ); } - public function testStringArray() + public function testStringArray(): void { $set = new \Arrayy\Type\StringArrayCollection([['a', 'foo']]); @@ -45,11 +45,11 @@ public function testStringArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new ArrayCollection([['a', 1, 1.4], [], [true, new \stdClass()], '[]']); } } diff --git a/tests/Collection/BoolTypeTest.php b/tests/Collection/BoolTypeTest.php index 990b809..444c6d8 100644 --- a/tests/Collection/BoolTypeTest.php +++ b/tests/Collection/BoolTypeTest.php @@ -12,7 +12,7 @@ */ final class BoolTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new BoolCollection([true, true, false, false]); @@ -22,7 +22,7 @@ public function testArray() ); } - public function testBoolArray() + public function testBoolArray(): void { $set = new \Arrayy\Type\BoolArrayCollection([[true, true], [false, false]]); @@ -33,7 +33,7 @@ public function testBoolArray() $test = null; foreach ($set->getIterator() as $foo) { - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore identical.alwaysFalse */ if ($foo === '1') { $test = false; } @@ -47,19 +47,19 @@ public function testBoolArray() static::assertTrue($test); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new BoolCollection([true, true, false, 1]); } - public function testBoolArrayWrongValue() + public function testBoolArrayWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new BoolCollection([[true, true], false, [true]]); } } diff --git a/tests/Collection/CallableTypeTest.php b/tests/Collection/CallableTypeTest.php index 77bc719..b1a2c8f 100644 --- a/tests/Collection/CallableTypeTest.php +++ b/tests/Collection/CallableTypeTest.php @@ -12,7 +12,7 @@ */ final class CallableTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new \Arrayy\Type\CallableCollection([ static function () { @@ -36,11 +36,11 @@ static function () { ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new FloatCollection(['strtolower', 1]); } } diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index d29a654..914aa56 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -16,7 +16,7 @@ */ final class CollectionTest extends \PHPUnit\Framework\TestCase { - public function testSimpleGenericCollection() + public function testSimpleGenericCollection(): void { $pets = new \stdClass(); $pets->foo = 1; @@ -29,7 +29,7 @@ public function testSimpleGenericCollection() static::assertSame([$pets, $colors], $collection->getCollection()); } - public function testSimpleBaseGenericCollection() + public function testSimpleBaseGenericCollection(): void { $pets = new \stdClass(); $pets->foo = 1; @@ -50,18 +50,18 @@ public function testSimpleBaseGenericCollection() static::assertInstanceOf(Collection::class, $baseCollection); } - public function testSimpleGenericFailCollection() + public function testSimpleGenericFailCollection(): void { $this->expectException(\TypeError::class); $pets = new \stdClass(); $pets->foo = 1; - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ collection(ModelInterface::class, $pets); } - public function testUserDataCollectionFromJsonWithNotMatchedFields() + public function testUserDataCollectionFromJsonWithNotMatchedFields(): void { $this->expectException(\TypeError::class); @@ -69,7 +69,7 @@ public function testUserDataCollectionFromJsonWithNotMatchedFields() UserDataCollection::createFromJsonMapper($json); } - public function testUserDataCollectionFromJson() + public function testUserDataCollectionFromJson(): void { $json = '{"id":1,"firstName":"Lars","lastName":"Moelleken","city":{"name":"Düsseldorf","plz":null,"infos":["lall"]}}'; $userDataCollection = UserDataCollection::createFromJsonMapper($json); @@ -80,15 +80,14 @@ public function testUserDataCollectionFromJson() static::assertInstanceOf(\Arrayy\tests\UserData::class, $userData); static::assertSame('Lars', $userData->firstName); static::assertInstanceOf(\Arrayy\tests\CityData::class, $userData->city); - /* @phpstan-ignore-next-line */ static::assertSame('Düsseldorf', $userData->city->name); } - public function testUserDataCollectionFromJsonMulti() + public function testUserDataCollectionFromJsonMulti(): void { $json = '[{"id":1,"firstName":"Lars","lastName":"Moelleken","city":{"name":"Düsseldorf","plz":null,"infos":["lall"]}}, {"id":1,"firstName":"Sven","lastName":"Moelleken","city":{"name":"Köln","plz":null,"infos":["foo"]}}]'; /** @var \Arrayy\Arrayy|\Arrayy\tests\UserData[] $userDataCollection */ - /** @phpstan-var \Arrayy\Arrayy $userDataCollection */ + /** @phpstan-var \Arrayy\Arrayy> $userDataCollection */ $userDataCollection = UserDataCollection::createFromJsonMapper($json); $userDataCollection->getAll(); @@ -104,7 +103,7 @@ public function testUserDataCollectionFromJsonMulti() static::assertSame('Köln', $userData1->city->name); } - public function testSimpleCollection() + public function testSimpleCollection(): void { $pets = new \stdClass(); $pets->foo = 'fooooo'; @@ -121,15 +120,13 @@ public function testSimpleCollection() static::assertSame('fooooo', $stdClassCollection->get('123.foo')); } - public function testJsonSerializableCollection() + public function testJsonSerializableCollection(): void { $pets = new \Arrayy\Arrayy(); - /* @phpstan-ignore-next-line */ - $pets->foo = 'fooooo'; + $pets['foo'] = 'fooooo'; $colors = new \Arrayy\Arrayy(); - /* @phpstan-ignore-next-line */ - $colors->color = 'red'; + $colors['color'] = 'red'; $jsonSerializableCollection = new \Arrayy\Type\JsonSerializableCollection([$pets, $colors]); @@ -144,7 +141,7 @@ public function testJsonSerializableCollection() } } - public function testBasic() + public function testBasic(): void { $pets = new \stdClass(); $pets->foo = 'fooooo'; @@ -171,14 +168,14 @@ public function testBasic() ); } - public function testBasicFail() + public function testBasicFail(): void { $this->expectException(\TypeError::class); new StdClassCollection([123, 'test']); } - public function testModelCollection() + public function testModelCollection(): void { $pets = new ModelA(['cat', 'dog', 'bird']); $colors = new ModelB(['red', 'yellow', 'green', 'white']); @@ -192,7 +189,7 @@ public function testModelCollection() static::assertSame([$pets, $colors], $modelCollection->getCollection()); } - public function testConstructorException() + public function testConstructorException(): void { $this->expectException(\TypeError::class); @@ -209,7 +206,7 @@ public function testConstructorException() static::assertSame(ModelInterface::class, $modelCollection->getType()); } - public function testAddExceptionV1() + public function testAddExceptionV1(): void { $this->expectException(\TypeError::class); @@ -226,13 +223,13 @@ public function testAddExceptionV1() $modelCollection = new ModelsCollection([$pets, $colors]); - /* @phpstan-ignore-next-line | offset on object */ + /* @phpstan-ignore offsetAssign.valueType */ $modelCollection[] = $cityData; static::assertSame(ModelInterface::class, $modelCollection->getType()); } - public function testAddExceptionV2() + public function testAddExceptionV2(): void { $this->expectException(\TypeError::class); @@ -249,13 +246,13 @@ public function testAddExceptionV2() $modelCollection = new ModelsCollection([$pets, $colors]); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ $modelCollection->add($cityData); static::assertSame(ModelInterface::class, $modelCollection->getType()); } - public function testWhere() + public function testWhere(): void { $pet1 = new ModelA(['pet' => ['cat']]); $pet2 = new ModelB(['pet' => ['dog', 'bird']]); @@ -270,7 +267,7 @@ public function testWhere() static::assertEquals($modelCollectionExpected, $newCollection); } - public function testClear() + public function testClear(): void { $pet1 = new ModelA(['pet' => ['cat']]); $pet2 = new ModelB(['pet' => ['dog', 'bird']]); @@ -285,14 +282,14 @@ public function testClear() static::assertSame(0, $modelCollection->count()); } - public function testTypesForAllProperties() + public function testTypesForAllProperties(): void { $model = new ModelC(['test', 'foo']); static::assertSame(['test', 'foo'], $model->getArray()); } - public function testTypesForAllPropertiesFail() + public function testTypesForAllPropertiesFail(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected to be of type {string}, instead got value `1` with type {integer}.'); @@ -300,14 +297,14 @@ public function testTypesForAllPropertiesFail() new ModelC(['test', 1]); } - public function testTypesForOneProperties() + public function testTypesForOneProperties(): void { $model = new ModelC(['test', 'foo']); static::assertSame(['test', 'foo'], $model->getArray()); } - public function testTypesForOnePropertiesFail() + public function testTypesForOnePropertiesFail(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected to be of type {int}, instead got value `a` with type {string}.'); @@ -315,14 +312,14 @@ public function testTypesForOnePropertiesFail() new ModelD(['foo' => 'a']); } - public function testTypesForOnePropertiesCorrect() + public function testTypesForOnePropertiesCorrect(): void { $d = new ModelD(['foo' => 1]); static::assertSame(['foo' => 1], $d->getArray()); } - public function testPrependExceptionV1() + public function testPrependExceptionV1(): void { $this->expectException(\TypeError::class); @@ -339,13 +336,13 @@ public function testPrependExceptionV1() $modelCollection = new ModelsCollection([$pets, $colors]); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ $modelCollection->prepend($cityData); static::assertSame(ModelInterface::class, $modelCollection->getType()); } - public function testPrependExceptionV2() + public function testPrependExceptionV2(): void { $this->expectException(\TypeError::class); @@ -365,13 +362,13 @@ public function testPrependExceptionV2() $rand = $modelCollection->randomImmutable(1); static::assertInstanceOf(ModelInterface::class, $rand->first()); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ $modelCollection->prepend($cityData, 0); static::assertSame(ModelInterface::class, $modelCollection->getType()); } - public function testColumnByArrayKey() + public function testColumnByArrayKey(): void { $bar1 = new ModelA(); $bar1['name'] = 'a'; @@ -397,7 +394,7 @@ public function testColumnByArrayKey() } } - public function testWithGeneratorsV1() + public function testWithGeneratorsV1(): void { $arrayyFunction = static function () { $bar1 = new ModelA(); @@ -427,7 +424,7 @@ public function testWithGeneratorsV1() } } - public function testMerge() + public function testMerge(): void { $bar1 = new ModelA(); $bar1['name'] = 'a'; diff --git a/tests/Collection/DetectTypeTypeTest.php b/tests/Collection/DetectTypeTypeTest.php index 60a6c28..4c1da46 100644 --- a/tests/Collection/DetectTypeTypeTest.php +++ b/tests/Collection/DetectTypeTypeTest.php @@ -13,7 +13,7 @@ */ final class DetectTypeTypeTest extends TestCase { - public function testArrayDetectString() + public function testArrayDetectString(): void { $set = new DetectFirstValueTypeCollection(['A', 'B', 'C', 'D']); @@ -23,7 +23,7 @@ public function testArrayDetectString() ); } - public function testArrayDetectInteger() + public function testArrayDetectInteger(): void { $set = new DetectFirstValueTypeCollection([1, 2, 3, 4]); @@ -33,7 +33,7 @@ public function testArrayDetectInteger() ); } - public function testArrayDetectClass() + public function testArrayDetectClass(): void { $set = new DetectFirstValueTypeCollection([new \stdClass(), new \stdClass()]); @@ -43,7 +43,7 @@ public function testArrayDetectClass() ); } - public function testArrayDetectTraversable() + public function testArrayDetectTraversable(): void { $set = new DetectFirstValueTypeCollection(new MixedCollection(['A', 'B', 'C', 'D'])); @@ -53,28 +53,28 @@ public function testArrayDetectTraversable() ); } - public function testWrongValueDetectString() + public function testWrongValueDetectString(): void { $this->expectException(\TypeError::class); new DetectFirstValueTypeCollection(['A', 'B', 'C', 1]); } - public function testWrongValueDetectInteger() + public function testWrongValueDetectInteger(): void { $this->expectException(\TypeError::class); new DetectFirstValueTypeCollection([1, 2, 3, 4.0]); } - public function testWrongValueDetectClass() + public function testWrongValueDetectClass(): void { $this->expectException(\TypeError::class); new DetectFirstValueTypeCollection([new \stdClass(), new DetectFirstValueTypeCollection()]); } - public function testWrongValueDetectTraversable() + public function testWrongValueDetectTraversable(): void { $this->expectException(\TypeError::class); diff --git a/tests/Collection/FloatIntTypeTest.php b/tests/Collection/FloatIntTypeTest.php index 8ed5eb1..4ae251d 100644 --- a/tests/Collection/FloatIntTypeTest.php +++ b/tests/Collection/FloatIntTypeTest.php @@ -12,7 +12,7 @@ */ final class FloatIntTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new FloatIntCollection([1.0, 1.1, 1.2, 1.3, 2]); @@ -22,7 +22,7 @@ public function testArray() ); } - public function testFloatArray() + public function testFloatArray(): void { $set = new \Arrayy\Type\FloatIntArrayCollection([[1.0, 1.1, 1.2], [2.3, 2]]); @@ -32,11 +32,11 @@ public function testFloatArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new FloatIntCollection([1.0, 1.1, 1.2, '2']); } } diff --git a/tests/Collection/FloatTypeTest.php b/tests/Collection/FloatTypeTest.php index cee4115..3ff82b0 100644 --- a/tests/Collection/FloatTypeTest.php +++ b/tests/Collection/FloatTypeTest.php @@ -12,7 +12,7 @@ */ final class FloatTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new FloatCollection([1.0, 1.1, 1.2, 1.3, 2.0]); @@ -22,7 +22,7 @@ public function testArray() ); } - public function testFloatArray() + public function testFloatArray(): void { $set = new \Arrayy\Type\FloatArrayCollection([[1.0, 1.1, 1.2], [2.3, 2.0]]); @@ -32,11 +32,11 @@ public function testFloatArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new FloatCollection([1.0, 1.1, 1.2, '2']); } } diff --git a/tests/Collection/InstanceTypeTest.php b/tests/Collection/InstanceTypeTest.php index d67aa99..3a61c41 100644 --- a/tests/Collection/InstanceTypeTest.php +++ b/tests/Collection/InstanceTypeTest.php @@ -14,7 +14,7 @@ */ final class InstanceTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new InstanceCollection( [new BoolCollection(), new BoolCollection()], @@ -41,7 +41,7 @@ public function testArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); diff --git a/tests/Collection/IntegerTypeTest.php b/tests/Collection/IntegerTypeTest.php index c13f35c..476ea80 100644 --- a/tests/Collection/IntegerTypeTest.php +++ b/tests/Collection/IntegerTypeTest.php @@ -12,7 +12,7 @@ */ final class IntegerTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new IntCollection([1, 2, 3, 4]); @@ -22,7 +22,7 @@ public function testArray() ); } - public function testIntArray() + public function testIntArray(): void { $set = new \Arrayy\Type\IntArrayCollection([[1, 2], [3, 4]]); @@ -32,19 +32,19 @@ public function testIntArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new IntCollection([1, 2, 3, 4.0]); } - public function testIntArrayWrongValue() + public function testIntArrayWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new IntCollection([[1, 2], 4.0]); } } diff --git a/tests/Collection/MixedTypeTest.php b/tests/Collection/MixedTypeTest.php index bebe5c0..2274c6d 100644 --- a/tests/Collection/MixedTypeTest.php +++ b/tests/Collection/MixedTypeTest.php @@ -12,7 +12,7 @@ */ final class MixedTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new MixedCollection([[], true, 1, 1.2, 'A']); diff --git a/tests/Collection/NonEmptyStringTypeTest.php b/tests/Collection/NonEmptyStringTypeTest.php index dce54a0..bfb9814 100644 --- a/tests/Collection/NonEmptyStringTypeTest.php +++ b/tests/Collection/NonEmptyStringTypeTest.php @@ -11,7 +11,7 @@ */ final class NonEmptyStringTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new \Arrayy\Type\NonEmptyStringCollection( [ @@ -31,11 +31,11 @@ public function testArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new \Arrayy\Type\NonEmptyStringCollection([ 'foo', '', diff --git a/tests/Collection/NumericStringTypeTest.php b/tests/Collection/NumericStringTypeTest.php index 72cfdb3..02cd186 100644 --- a/tests/Collection/NumericStringTypeTest.php +++ b/tests/Collection/NumericStringTypeTest.php @@ -11,7 +11,7 @@ */ final class NumericStringTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new \Arrayy\Type\NumericStringCollection( [ @@ -31,11 +31,11 @@ public function testArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new \Arrayy\Type\NumericStringCollection([ 3.2, 2, diff --git a/tests/Collection/NumericTypeTest.php b/tests/Collection/NumericTypeTest.php index 40878c6..0a3b3d2 100644 --- a/tests/Collection/NumericTypeTest.php +++ b/tests/Collection/NumericTypeTest.php @@ -11,7 +11,7 @@ */ final class NumericTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new \Arrayy\Type\NumericCollection( [ @@ -31,11 +31,11 @@ public function testArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new \Arrayy\Type\NumericCollection([ new \stdClass(), \tmpfile(), diff --git a/tests/Collection/ObjectTypeTest.php b/tests/Collection/ObjectTypeTest.php index a0b886b..baffa7b 100644 --- a/tests/Collection/ObjectTypeTest.php +++ b/tests/Collection/ObjectTypeTest.php @@ -11,7 +11,7 @@ */ final class ObjectTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new \Arrayy\Type\ObjectCollection([ new \stdClass(), @@ -29,11 +29,11 @@ public function testArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new \Arrayy\Type\ObjectCollection(['strtolower', 1]); } } diff --git a/tests/Collection/ResourceTypeTest.php b/tests/Collection/ResourceTypeTest.php index 0f10b29..89ed481 100644 --- a/tests/Collection/ResourceTypeTest.php +++ b/tests/Collection/ResourceTypeTest.php @@ -11,7 +11,7 @@ */ final class ResourceTypeTest extends TestCase { - public function testArray() + public function testArray(): void { /** @var resource $f1 */ $f1 = \tmpfile(); @@ -38,11 +38,11 @@ public function testArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new \Arrayy\Type\ResourceCollection([ new \stdClass(), \tmpfile(), diff --git a/tests/Collection/ScalarTypeTest.php b/tests/Collection/ScalarTypeTest.php index 823d461..7891afc 100644 --- a/tests/Collection/ScalarTypeTest.php +++ b/tests/Collection/ScalarTypeTest.php @@ -11,7 +11,7 @@ */ final class ScalarTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = new \Arrayy\Type\ScalarCollection([ '4', @@ -37,7 +37,7 @@ public function testArray() ); } - public function testArrayFromJsonMapper() + public function testArrayFromJsonMapper(): void { $set = \Arrayy\Type\ScalarCollection::createFromJsonMapper('["4",5,7,true,false,"6","7"]'); @@ -55,15 +55,15 @@ public function testArrayFromJsonMapper() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new \Arrayy\Type\ScalarCollection([new \stdClass(), 1]); } - public function testWrongValueFromJsonMapper() + public function testWrongValueFromJsonMapper(): void { $this->expectException(\TypeError::class); diff --git a/tests/Collection/StringTypeTest.php b/tests/Collection/StringTypeTest.php index 8e08275..ec4f5e2 100644 --- a/tests/Collection/StringTypeTest.php +++ b/tests/Collection/StringTypeTest.php @@ -13,23 +13,19 @@ */ final class StringTypeTest extends TestCase { - public function testArraySimple() + public function testArraySimple(): void { $this->expectException(\TypeError::class); $strings = PhpString::create(); - /* @phpstan-ignore-next-line | offset on object */ $strings[] = 'A'; - /* @phpstan-ignore-next-line | offset on object */ $strings[] = 'B'; - /* @phpstan-ignore-next-line | offset on object */ $strings[] = 'C'; - /* @phpstan-ignore-next-line | offset on object */ $strings[] = 1.0; } - public function testArray() + public function testArray(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -39,7 +35,7 @@ public function testArray() ); } - public function testArrayFromJsonMapper() + public function testArrayFromJsonMapper(): void { $json = '["A","B","C","D"]'; @@ -51,15 +47,15 @@ public function testArrayFromJsonMapper() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore offsetAssign.valueType */ new StringCollection(['A', 'B', 'C', 1]); } - public function testWrongValueFromJsonMapper() + public function testWrongValueFromJsonMapper(): void { $this->expectException(\TypeError::class); diff --git a/tests/Collection/TypeTypeTest.php b/tests/Collection/TypeTypeTest.php index eb4b2c3..3af2fc2 100644 --- a/tests/Collection/TypeTypeTest.php +++ b/tests/Collection/TypeTypeTest.php @@ -12,7 +12,7 @@ */ final class TypeTypeTest extends TestCase { - public function testArray() + public function testArray(): void { $set = Collection::construct('string', ['A', 'B', 'C', 'D']); @@ -22,13 +22,13 @@ public function testArray() ); } - public function testWrongValue() + public function testWrongValue(): void { $this->expectException(\TypeError::class); /** @noinspection PhpParamsInspection */ /** @noinspection PhpStrictTypeCheckingInspection */ - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ new Collection(\stdClass::class, [new \stdClass(), 'A']); } } diff --git a/tests/Collection/TypesTest.php b/tests/Collection/TypesTest.php index 8ac5c52..6389a68 100644 --- a/tests/Collection/TypesTest.php +++ b/tests/Collection/TypesTest.php @@ -14,7 +14,7 @@ */ final class TypesTest extends TestCase { - public function testShuffleSimple() + public function testShuffleSimple(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -25,7 +25,7 @@ public function testShuffleSimple() static::assertNotContains('E', $set->toArray()); } - public function testTypeCheck() + public function testTypeCheck(): void { $set = new StringCollection(['A', 'B', 'C']); @@ -35,16 +35,16 @@ public function testTypeCheck() static::assertSame([1 => '1', 'A', 'B', 'C', 'D', 'E'], $set->toArray()); } - public function testPushTypeCheckError() + public function testPushTypeCheckError(): void { $set = new StringCollection(['A', 'B', 'C']); $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ static::assertSame(['A', 'B', 'C', 'D', 'E'], $set->push(5)->getArray()); } - public function testChainMethods() + public function testChainMethods(): void { $m = UserData::meta(); $mCity = \Arrayy\tests\CityData::meta(); @@ -72,16 +72,16 @@ public function testChainMethods() static::assertSame('Lars;Lea;Sven', $names); } - public function testUnshiftTypeCheckError() + public function testUnshiftTypeCheckError(): void { $set = new StringCollection(['A', 'B', 'C']); $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ static::assertSame(['A', 'B', 'C', 'D', 'E'], $set->unshift(5)->getArray()); } - public function testChunk() + public function testChunk(): void { $set = new StringCollection(['A', 'B', 'C', 'D', 'E']); @@ -97,7 +97,7 @@ public function testChunk() ); } - public function testCount() + public function testCount(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -107,7 +107,7 @@ public function testCount() ); } - public function testDiff() + public function testDiff(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); $set1 = new StringCollection(['A', 'C']); @@ -134,7 +134,7 @@ public function testDiff() ); } - public function testEach() + public function testEach(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -155,7 +155,7 @@ static function ($item) { ); } - public function testFilter() + public function testFilter(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -176,7 +176,7 @@ static function ($item) { ); } - public function testFirst() + public function testFirst(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -191,7 +191,7 @@ public function testFirst() ); } - public function testGet() + public function testGet(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -201,7 +201,7 @@ public function testGet() ); } - public function testHas() + public function testHas(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -209,7 +209,7 @@ public function testHas() static::assertFalse($set->hasValue('E')); } - public function testImplode() + public function testImplode(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -229,7 +229,7 @@ public function testImplode() ); } - public function testIntersect() + public function testIntersect(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); $set1 = new StringCollection(['A', 'C']); @@ -246,7 +246,7 @@ public function testIntersect() ); } - public function testLast() + public function testLast(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -261,7 +261,7 @@ public function testLast() ); } - public function testNth() + public function testNth(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -281,7 +281,7 @@ public function testNth() ); } - public function testOnly() + public function testOnly(): void { $set = new StringCollection(['A', 'c' => 'B']); @@ -296,7 +296,7 @@ public function testOnly() ); } - public function testPad() + public function testPad(): void { $set = new StringCollection(['A', 'B']); @@ -311,7 +311,7 @@ public function testPad() ); } - public function testPop() + public function testPop(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -326,7 +326,7 @@ public function testPop() ); } - public function testPush() + public function testPush(): void { $set = new StringCollection(['A', 'B', 'C']); $set->push('D'); @@ -337,11 +337,11 @@ public function testPush() ); $this->expectException(\TypeError::class); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore argument.type */ $set->push(1); } - public function testReduce() + public function testReduce(): void { $set = new IntCollection([1, 2, 3, 4]); @@ -358,7 +358,7 @@ static function ($carry, $item) { ); } - public function testReverse() + public function testReverse(): void { $set = new StringCollection([1 => 'A', 'B', 'C', 'D']); @@ -368,7 +368,7 @@ public function testReverse() ); } - public function testReverseKeepIndex() + public function testReverseKeepIndex(): void { $set = new StringCollection([1 => 'A', 'B', 'C', 'D']); @@ -378,7 +378,7 @@ public function testReverseKeepIndex() ); } - public function testSearch() + public function testSearch(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -388,7 +388,7 @@ public function testSearch() ); } - public function testShift() + public function testShift(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -398,7 +398,7 @@ public function testShift() ); } - public function testShuffle() + public function testShuffle(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -425,7 +425,7 @@ public function testShuffle() ); } - public function testSlice() + public function testSlice(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -440,7 +440,7 @@ public function testSlice() ); } - public function testSort() + public function testSort(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -454,7 +454,7 @@ static function ($a, $b) { ); } - public function testSplice() + public function testSplice(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); $array = $set->splice(1, 2, ['E', 'F']); @@ -465,7 +465,7 @@ public function testSplice() ); } - public function testToJson() + public function testToJson(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); @@ -475,7 +475,7 @@ public function testToJson() ); } - public function testToPermutation() + public function testToPermutation(): void { $set = new StringCollection(['A', 'B', 'C']); @@ -516,7 +516,7 @@ public function testToPermutation() ); } - public function testUnique() + public function testUnique(): void { $set = new StringCollection(['A', 'B', 'C', 'D', 'A']); @@ -526,7 +526,7 @@ public function testUnique() ); } - public function testInstanceError() + public function testInstanceError(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected to be of type {stdClass}, instead got value `Arrayy\\Arrayy Object'); @@ -541,7 +541,7 @@ public function testInstanceError() ); } - public function testInstance() + public function testInstance(): void { $testArray = [new \stdClass(), new \stdClass()]; @@ -558,7 +558,7 @@ public function testInstance() ); } - public function testInstancesError() + public function testInstancesError(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected to be of type {stdClass}, instead got value `Arrayy\\Arrayy Object'); @@ -573,7 +573,7 @@ public function testInstancesError() ); } - public function testInstances() + public function testInstances(): void { $testArray = [new \stdClass(), new \stdClass(), new \Arrayy\Arrayy()]; @@ -593,7 +593,7 @@ public function testInstances() /** * @noinspection PhpUnusedParameterInspection */ - public function testWalk() + public function testWalk(): void { $set = new StringCollection(['A', 'B', 'C', 'D']); diff --git a/tests/CreateTest.php b/tests/CreateTest.php index 9de2fdd..fb9affa 100644 --- a/tests/CreateTest.php +++ b/tests/CreateTest.php @@ -9,7 +9,7 @@ */ final class CreateTest extends \PHPUnit\Framework\TestCase { - public function testCreate() + public function testCreate(): void { $arrayy = \Arrayy\create(['foo bar', 'UTF-8']); diff --git a/tests/DocBlockScalarData.php b/tests/DocBlockScalarData.php index 21c4cbc..b687c1b 100644 --- a/tests/DocBlockScalarData.php +++ b/tests/DocBlockScalarData.php @@ -5,7 +5,7 @@ /** * @property scalar $value * - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class DocBlockScalarData extends \Arrayy\Arrayy { diff --git a/tests/DotNotationCollectionTest.php b/tests/DotNotationCollectionTest.php index 7f2eba2..cd950d4 100644 --- a/tests/DotNotationCollectionTest.php +++ b/tests/DotNotationCollectionTest.php @@ -23,13 +23,13 @@ final class DotNotationCollectionTest extends \PHPUnit\Framework\TestCase ], ]; - public function testCreateObject() + public function testCreateObject(): void { $dn = new Arrayy(['foo' => 'bar']); static::assertFalse($dn->isEmpty()); } - public function testGetPath() + public function testGetPath(): void { $dn = new Arrayy($this->_array_test_1); @@ -39,7 +39,7 @@ public function testGetPath() static::assertNull($dn->get('foo.test')); } - public function testSetPath() + public function testSetPath(): void { $dn = new Arrayy($this->_array_test_1); @@ -49,19 +49,14 @@ public function testSetPath() static::assertEquals($dn->get('foo.bar'), 123); $jade = $dn->get('foo.jade.profile.new'); - if (\method_exists(__CLASS__, 'assertIsArray')) { - static::assertIsArray($jade->getArray()); - } else { - /** @noinspection PhpUndefinedMethodInspection */ - static::assertInternalType('array', $jade->getArray()); - } + static::assertIsArray($jade->getArray()); static::assertSame('path', $jade['test']['of']); $dn->add('test'); static::assertSame('test', $dn[0]); } - public function testSetException() + public function testSetException(): void { $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Can not set value at this path "test" because (integer)"123" is not an array.'); @@ -69,7 +64,7 @@ public function testSetException() $dn->set('foo.bar.test', ['bob']); } - public function testHavePath() + public function testHavePath(): void { $dn = new Arrayy($this->_array_test_1); @@ -79,7 +74,7 @@ public function testHavePath() static::assertFalse($dn->has('bar.foo')); } - public function testAdd() + public function testAdd(): void { $dn = new Arrayy($this->_array_test_1); diff --git a/tests/DotTest.php b/tests/DotTest.php index 40d11a4..86eced3 100644 --- a/tests/DotTest.php +++ b/tests/DotTest.php @@ -16,28 +16,28 @@ final class DotTest extends \PHPUnit\Framework\TestCase * Construct * -------------------------------------------------------------- */ - public function testConstructWithoutValues() + public function testConstructWithoutValues(): void { $dot = new Arrayy(); static::assertSame([], $dot->getAll()); } - public function testConstructWithArray() + public function testConstructWithArray(): void { $dot = new Arrayy(['foo' => 'bar']); static::assertSame('bar', $dot->get('foo')); } - public function testConstructWithString() + public function testConstructWithString(): void { $dot = new Arrayy('foobar'); static::assertSame('foobar', $dot->get(0)); } - public function testConstructWithDot() + public function testConstructWithDot(): void { $dot1 = new Arrayy(['foo' => 'bar']); $dot2 = new Arrayy($dot1); @@ -45,7 +45,7 @@ public function testConstructWithDot() static::assertSame('bar', $dot2->get('foo')); } - public function testConstructHelper() + public function testConstructHelper(): void { $dot = \Arrayy\create(['foo' => 'bar']); @@ -59,7 +59,7 @@ public function testConstructHelper() * -------------------------------------------------------------- */ - public function testAddKeyValuePair() + public function testAddKeyValuePair(): void { $dot = new Arrayy(); $dot->append('baz', 'foo.bar'); @@ -67,7 +67,7 @@ public function testAddKeyValuePair() static::assertSame('baz', $dot->get('foo.bar')); } - public function testAddValueToExistingKey() + public function testAddValueToExistingKey(): void { $dot = new Arrayy(['foo' => 'bar']); $dot->append('baz', 'foo'); @@ -75,7 +75,7 @@ public function testAddValueToExistingKey() static::assertSame('baz', $dot->get('foo')); } - public function testAddArrayOfKeyValuePairs() + public function testAddArrayOfKeyValuePairs(): void { $dot = new Arrayy(['foobar' => 'baz']); $dot->add([ @@ -98,7 +98,7 @@ public function testAddArrayOfKeyValuePairs() * -------------------------------------------------------------- */ - public function testAllReturnsAllItems() + public function testAllReturnsAllItems(): void { $dot = new Arrayy(['foo' => 'bar']); @@ -111,7 +111,7 @@ public function testAllReturnsAllItems() * -------------------------------------------------------------- */ - public function testClearKey() + public function testClearKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot->clear('foo.bar'); @@ -119,7 +119,7 @@ public function testClearKey() static::assertNull($dot->get('foo.bar')); } - public function testClearNonExistingKey() + public function testClearNonExistingKey(): void { $dot = new Arrayy(); $dot->clear('foo'); @@ -127,7 +127,7 @@ public function testClearNonExistingKey() static::assertNull($dot->get('foo')); } - public function testClearArrayOfKeys() + public function testClearArrayOfKeys(): void { $dot = new Arrayy(['foo' => 'bar', 'baz' => 'qux', 'lall' => 'foo']); $dot->clear(['foo.bar', 'baz']); @@ -135,7 +135,7 @@ public function testClearArrayOfKeys() static::assertSame(['foo' => null, 'lall' => 'foo'], $dot->getAll()); } - public function testClearAll() + public function testClearAll(): void { $dot = new Arrayy(['foo' => 'bar']); $dot->clear(); @@ -149,7 +149,7 @@ public function testClearAll() * -------------------------------------------------------------- */ - public function testDeleteKey() + public function testDeleteKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot->delete('foo.bar'); @@ -157,7 +157,7 @@ public function testDeleteKey() static::assertFalse($dot->has('foo.bar')); } - public function testDeleteNonExistingKey() + public function testDeleteNonExistingKey(): void { $dot = new Arrayy(['foo' => 'bar']); $dot->delete('baz.qux'); @@ -165,7 +165,7 @@ public function testDeleteNonExistingKey() static::assertSame(['foo' => 'bar'], $dot->getAll()); } - public function testDeleteArrayOfKeys() + public function testDeleteArrayOfKeys(): void { $dot = new Arrayy(['foo' => 'bar', 'baz' => 'qux']); $dot->delete(['foo', 'baz']); @@ -178,7 +178,7 @@ public function testDeleteArrayOfKeys() * Flatten * -------------------------------------------------------------- */ - public function testFlatten() + public function testFlatten(): void { $dot = new Arrayy(['foo' => ['abc' => 'xyz', 'bar' => ['baz']]]); $flatten = $dot->flatten(); @@ -192,7 +192,7 @@ public function testFlatten() static::assertSame('lall', $flatten['1.foo']); } - public function testFlattenWithCustomDelimiter() + public function testFlattenWithCustomDelimiter(): void { $dot = new Arrayy(['foo' => ['abc' => 'xyz', 'bar' => ['baz']]]); $flatten = $dot->flatten('_'); @@ -206,21 +206,21 @@ public function testFlattenWithCustomDelimiter() * -------------------------------------------------------------- */ - public function testGetValueFromKey() + public function testGetValueFromKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); static::assertSame('baz', $dot->get('foo.bar')); } - public function testGetValueFromNonExistingKey() + public function testGetValueFromNonExistingKey(): void { $dot = new Arrayy(); static::assertNull($dot->get('foo')); } - public function testGetGivenDefaultValueFromNonExistingKey() + public function testGetGivenDefaultValueFromNonExistingKey(): void { $dot = new Arrayy(); @@ -233,7 +233,7 @@ public function testGetGivenDefaultValueFromNonExistingKey() * -------------------------------------------------------------- */ - public function testHasKey() + public function testHasKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); @@ -244,7 +244,7 @@ public function testHasKey() static::assertFalse($dot->has('foo.bar')); } - public function testHasArrayOfKeys() + public function testHasArrayOfKeys(): void { $dot = new Arrayy(['foo' => 'bar', 'baz' => 'qux']); @@ -255,7 +255,7 @@ public function testHasArrayOfKeys() static::assertFalse($dot->has(['foo', 'baz'])); } - public function testHasWithEmptyDot() + public function testHasWithEmptyDot(): void { $dot = new Arrayy(); @@ -268,7 +268,7 @@ public function testHasWithEmptyDot() * -------------------------------------------------------------- */ - public function testIsEmptyDot() + public function testIsEmptyDot(): void { $dot = new Arrayy(); @@ -279,7 +279,7 @@ public function testIsEmptyDot() static::assertFalse($dot->isEmpty()); } - public function testIsEmptyKey() + public function testIsEmptyKey(): void { $dot = new Arrayy(); @@ -290,7 +290,7 @@ public function testIsEmptyKey() static::assertFalse($dot->isEmpty('foo.bar')); } - public function testIsEmptyArrayOfKeys() + public function testIsEmptyArrayOfKeys(): void { $dot = new Arrayy(); @@ -307,7 +307,7 @@ public function testIsEmptyArrayOfKeys() * -------------------------------------------------------------- */ - public function testMergeArrayWithDot() + public function testMergeArrayWithDot(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot = $dot->mergeAppendKeepIndex(['foo' => ['bar' => 'qux']]); @@ -315,7 +315,7 @@ public function testMergeArrayWithDot() static::assertSame('qux', $dot->get('foo.bar')); } - public function testMergeArrayWithKey() + public function testMergeArrayWithKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot = $dot->mergeAppendKeepIndex(['foo' => ['bar' => 'qux']]); @@ -323,7 +323,7 @@ public function testMergeArrayWithKey() static::assertSame('qux', $dot->get('foo.bar')); } - public function testMergeDotWithDot() + public function testMergeDotWithDot(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz']]); $dot2 = new Arrayy(['foo' => ['bar' => 'qux']]); @@ -332,7 +332,7 @@ public function testMergeDotWithDot() static::assertSame('qux', $dot1->get('foo.bar')); } - public function testMergeDotObjectWithKey() + public function testMergeDotObjectWithKey(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz']]); $dot2 = new Arrayy(['bar' => 'qux']); @@ -347,7 +347,7 @@ public function testMergeDotObjectWithKey() * -------------------------------------------------------------- */ - public function testRecursiveMergeArrayWithDot() + public function testRecursiveMergeArrayWithDot(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot = $dot->mergeAppendNewIndex(['foo' => ['bar' => 'qux', 'quux' => 'quuz']], true); @@ -364,7 +364,7 @@ public function testRecursiveMergeArrayWithDot() static::assertSame('quuz', $dot->get('foo.quux')); } - public function testRecursiveMergeArrayWithKey() + public function testRecursiveMergeArrayWithKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot = $dot->mergePrependNewIndex(['foo' => ['bar' => 'qux', 'quux' => 'quuz']], true); @@ -373,7 +373,7 @@ public function testRecursiveMergeArrayWithKey() static::assertSame('quuz', $dot->get('foo.quux')); } - public function testRecursiveMergeDotWithDot() + public function testRecursiveMergeDotWithDot(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz']]); $dot2 = new Arrayy(['foo' => ['bar' => 'qux', 'quux' => 'quuz']]); @@ -383,7 +383,7 @@ public function testRecursiveMergeDotWithDot() static::assertSame('quuz', $dot1->get('foo.quux')); } - public function testRecursiveMergeDotObjectWithKey() + public function testRecursiveMergeDotObjectWithKey(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz']]); $dot2 = new Arrayy(['foo' => ['bar' => 'qux', 'quux' => 'quuz']]); @@ -399,7 +399,7 @@ public function testRecursiveMergeDotObjectWithKey() * -------------------------------------------------------------- */ - public function testRecursiveDistinctMergeArrayWithDot() + public function testRecursiveDistinctMergeArrayWithDot(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot = $dot->mergeAppendKeepIndex(['foo' => ['bar' => 'qux', 'quux' => 'quuz']], true); @@ -408,7 +408,7 @@ public function testRecursiveDistinctMergeArrayWithDot() static::assertSame('quuz', $dot->get('foo.quux')); } - public function testRecursiveDistinctMergeArrayWithKey() + public function testRecursiveDistinctMergeArrayWithKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot = $dot->mergeAppendKeepIndex(['foo' => ['bar' => 'qux', 'quux' => 'quuz']], true); @@ -417,7 +417,7 @@ public function testRecursiveDistinctMergeArrayWithKey() static::assertSame('quuz', $dot->get('foo.quux')); } - public function testRecursiveDistinctMergeDotWithDot() + public function testRecursiveDistinctMergeDotWithDot(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz']]); $dot2 = new Arrayy(['foo' => ['bar' => 'qux', 'quux' => 'quuz']]); @@ -427,7 +427,7 @@ public function testRecursiveDistinctMergeDotWithDot() static::assertSame('quuz', $dot1->get('foo.quux')); } - public function testRecursiveDistinctMergeDotObjectWithKey() + public function testRecursiveDistinctMergeDotObjectWithKey(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz']]); $dot2 = new Arrayy(['foo' => ['bar' => 'qux', 'quux' => 'quuz']]); @@ -443,7 +443,7 @@ public function testRecursiveDistinctMergeDotObjectWithKey() * -------------------------------------------------------------- */ - public function testPullKey() + public function testPullKey(): void { $dot = new Arrayy(['foo' => 'bar']); @@ -451,21 +451,21 @@ public function testPullKey() static::assertFalse($dot->has('foo')); } - public function testPullNonExistingKey() + public function testPullNonExistingKey(): void { $dot = new Arrayy(); static::assertNull($dot->pull('foo')); } - public function testPullNonExistingKeyWithDefaultValue() + public function testPullNonExistingKeyWithDefaultValue(): void { $dot = new Arrayy(); static::assertSame('bar', $dot->pull('foo', 'bar')); } - public function testPullAll() + public function testPullAll(): void { $dot = new Arrayy(['foo' => 'bar']); @@ -479,7 +479,7 @@ public function testPullAll() * -------------------------------------------------------------- */ - public function testPushValue() + public function testPushValue(): void { $dot = new Arrayy(); $dot->push('foo'); @@ -487,7 +487,7 @@ public function testPushValue() static::assertSame('foo', $dot->get(0)); } - public function testPushValueToKey() + public function testPushValueToKey(): void { $dot = new Arrayy(['foo']); $dot->push('baz'); @@ -501,7 +501,7 @@ public function testPushValueToKey() * -------------------------------------------------------------- */ - public function testReplaceWithArray() + public function testReplaceWithArray(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz']]); $dot = $dot->replace('foo', 'foo', ['qux' => 'quux']); @@ -509,7 +509,7 @@ public function testReplaceWithArray() static::assertSame(['qux' => 'quux'], $dot->get('foo')->getArray()); } - public function testReplaceKeyWithArray() + public function testReplaceKeyWithArray(): void { $dot = new Arrayy(['foo' => ['bar' => 'baz', 'qux' => 'quux']]); $dot = $dot->replace('foo', 'bar', ['qux' => 'corge']); @@ -517,7 +517,7 @@ public function testReplaceKeyWithArray() static::assertSame(['qux' => 'corge'], $dot->get('bar')->getArray()); } - public function testReplaceWithDot() + public function testReplaceWithDot(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz']]); $dot2 = new Arrayy(['bar' => 'qux']); @@ -526,7 +526,7 @@ public function testReplaceWithDot() static::assertSame(['bar' => 'qux'], $dot1->get('foo')->getArray()); } - public function testReplaceKeyWithDot() + public function testReplaceKeyWithDot(): void { $dot1 = new Arrayy(['foo' => ['bar' => 'baz', 'qux' => 'quux']]); $dot2 = new Arrayy(['qux' => 'corge']); @@ -549,7 +549,7 @@ public function testReplaceKeyWithDot() * -------------------------------------------------------------- */ - public function testSetKeyValuePair() + public function testSetKeyValuePair(): void { $dot = new Arrayy(); $dot->set('foo.bar', 'baz'); @@ -557,7 +557,7 @@ public function testSetKeyValuePair() static::assertSame('baz', $dot->get('foo.bar')); } - public function testSetArrayOfKeyValuePairs() + public function testSetArrayOfKeyValuePairs(): void { $dot = new Arrayy(['foo' => 'bar', 'baz' => 'qux']); @@ -570,7 +570,7 @@ public function testSetArrayOfKeyValuePairs() * -------------------------------------------------------------- */ - public function testSetArray() + public function testSetArray(): void { $dot = (new Arrayy())::createFromArray(['foo' => 'bar']); @@ -583,7 +583,7 @@ public function testSetArray() * -------------------------------------------------------------- */ - public function testSetReference() + public function testSetReference(): void { $dot = new Arrayy(); $items = ['foo' => 'bar']; @@ -599,7 +599,7 @@ public function testSetReference() * -------------------------------------------------------------- */ - public function testOffsetExists() + public function testOffsetExists(): void { $dot = new Arrayy(['foo' => 'bar']); @@ -610,14 +610,14 @@ public function testOffsetExists() static::assertFalse(isset($dot['foo'])); } - public function testOffsetGet() + public function testOffsetGet(): void { $dot = new Arrayy(['foo' => 'bar']); static::assertSame('bar', $dot['foo']); } - public function testOffsetSet() + public function testOffsetSet(): void { $dot = new Arrayy(); $dot['foo.bar'] = 'baz'; @@ -625,7 +625,7 @@ public function testOffsetSet() static::assertSame('baz', $dot['foo.bar']); } - public function testOffsetSetWithoutKey() + public function testOffsetSetWithoutKey(): void { $dot = new Arrayy(); $dot[] = 'foobar'; @@ -633,7 +633,7 @@ public function testOffsetSetWithoutKey() static::assertSame('foobar', $dot->get(0)); } - public function testOffsetUnset() + public function testOffsetUnset(): void { $dot = new Arrayy(['foo' => 'bar']); unset($dot['foo']); @@ -647,7 +647,7 @@ public function testOffsetUnset() * -------------------------------------------------------------- */ - public function testToJsonAll() + public function testToJsonAll(): void { $dot = new Arrayy(['foo' => 'bar']); @@ -657,7 +657,7 @@ public function testToJsonAll() ); } - public function testToJsonAllWithOption() + public function testToJsonAllWithOption(): void { $dot = new Arrayy(['foo' => "'bar'"]); @@ -667,7 +667,7 @@ public function testToJsonAllWithOption() ); } - public function testToJsonKey() + public function testToJsonKey(): void { $dot = new Arrayy(['foo' => ['bar' => 'value']]); @@ -677,7 +677,7 @@ public function testToJsonKey() ); } - public function testToJsonKeyWithOptions() + public function testToJsonKeyWithOptions(): void { $dot = new Arrayy(['foo' => ['bar' => "'value'"]]); @@ -693,14 +693,14 @@ public function testToJsonKeyWithOptions() * -------------------------------------------------------------- */ - public function testCount() + public function testCount(): void { $dot = new Arrayy([1, 2, 3]); static::assertSame(3, $dot->count()); } - public function testCountable() + public function testCountable(): void { $dot = new Arrayy([1, 2, 3]); @@ -713,14 +713,14 @@ public function testCountable() * -------------------------------------------------------------- */ - public function testGetIteratorReturnsArrayIterator() + public function testGetIteratorReturnsArrayIterator(): void { $dot = new Arrayy(); static::assertInstanceOf(\Arrayy\ArrayyIterator::class, $dot->getIterator()); } - public function testIterationReturnsOriginalValues() + public function testIterationReturnsOriginalValues(): void { $dot = new Arrayy([1, 2, 3]); @@ -738,7 +738,7 @@ public function testIterationReturnsOriginalValues() * -------------------------------------------------------------- */ - public function testJsonEncodingReturnsJson() + public function testJsonEncodingReturnsJson(): void { $dot = new Arrayy(['foo' => 'bar']); diff --git a/tests/GetAccountsResponse.php b/tests/GetAccountsResponse.php index 708102a..677a524 100644 --- a/tests/GetAccountsResponse.php +++ b/tests/GetAccountsResponse.php @@ -7,7 +7,7 @@ /** * @property \Arrayy\tests\AccountCollection $accounts * - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class GetAccountsResponse extends Arrayy { diff --git a/tests/InfrastructureCoverageTest.php b/tests/InfrastructureCoverageTest.php new file mode 100644 index 0000000..858f48a --- /dev/null +++ b/tests/InfrastructureCoverageTest.php @@ -0,0 +1,102 @@ + 'bar']], 0, Arrayy::class); + + $current = $iterator->offsetGet(0); + + static::assertInstanceOf(Arrayy::class, $current); + static::assertSame('bar', $current->get('foo')); + } + + public function testArrayyMetaReturnsEmptyStringForUnknownProperties(): void + { + static::assertSame('', (new ArrayyMeta())->__get('missing')); + } + + public function testArrayyRewindableGeneratorInvokesRewindCallback(): void + { + $rewinds = 0; + $iterator = new ArrayyRewindableGenerator( + static function (): \Generator { + yield 'foo' => 'bar'; + }, + static function () use (&$rewinds): void { + ++$rewinds; + } + ); + + $iterator->rewind(); + + static::assertSame(1, $rewinds); + static::assertTrue($iterator->valid()); + static::assertSame('foo', $iterator->key()); + static::assertSame('bar', $iterator->current()); + } + + public function testArrayyRewindableGeneratorRejectsNonGeneratorFactories(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('The callable needs to return a Generator'); + + new ArrayyRewindableGenerator(static fn (): array => []); + } + + public function testDetectFirstValueTypeCollectionWrapsScalarInput(): void + { + $collection = new DetectFirstValueTypeCollection($this->mixedValue('A')); + + static::assertSame(['A'], $collection->toArray()); + static::assertSame('string', $collection->getType()); + } + + public function testTypeStdClassCollectionReturnsStdClassType(): void + { + $collection = new \Arrayy\Type\StdClassCollection([new \stdClass()]); + + static::assertSame(\stdClass::class, $collection->getType()); + } + + public function testAbstractCollectionExpandsNestedCollectionsForOffsetSetPrependAndSet(): void + { + $first = (object) ['name' => 'first']; + $second = (object) ['name' => 'second']; + + $collection = new StdClassCollection(); + $collection[] = $this->mixedValue(new StdClassCollection([$first])); + $collection->prepend($this->mixedValue(new StdClassCollection([$second])), 'lead'); + $collection->set('tail', $this->mixedValue(new StdClassCollection([$first, $second]))); + + static::assertSame($second, $collection['lead']); + static::assertSame($first, $collection[0]); + static::assertSame($second, $collection['tail']); + } + + /** + * @param mixed $value + * + * @return mixed + */ + private function mixedValue($value) + { + return $value; + } +} diff --git a/tests/JsonMapperCoverageTest.php b/tests/JsonMapperCoverageTest.php new file mode 100644 index 0000000..a8d599f --- /dev/null +++ b/tests/JsonMapperCoverageTest.php @@ -0,0 +1,201 @@ +expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('JsonMapper::map() requires second argument to be an object, integer given.'); + + (new Json())->map([], 123); + } + + public function testMapInvokesUndefinedPropertyHandlerWithSafeName(): void + { + $mapper = new Json(); + $captured = []; + $target = new \stdClass(); + + $mapper->undefinedPropertyHandler = static function ($object, string $key, $value) use (&$captured): void { + $captured = [$object, $key, $value]; + }; + + $result = $mapper->map(['unknown-key' => 'value'], $target); + + static::assertSame($target, $result); + static::assertSame([$target, 'UnknownKey', 'value'], $captured); + } + + public function testMapSkipsPrivatePropertiesWithoutSetters(): void + { + $mapper = new Json(); + $target = new JsonMapperPrivatePropertyFixture(); + + $result = $mapper->map(['secret' => 'changed'], $target); + + static::assertSame($target, $result); + static::assertSame('keep', $target->getSecret()); + } + + public function testMapTreatsDocOnlyPropertiesAsMixed(): void + { + $mapper = new Json(); + $payload = (object) ['id' => 1]; + $target = new JsonMapperDocOnlyFixture(); + + $result = $mapper->map(['payload' => $payload], $target); + + static::assertSame($target, $result); + static::assertSame($payload, $target->payload); + } + + public function testMapAcceptsExplicitNullForNullableProperties(): void + { + $target = (new Json())->map(['name' => null], new JsonMapperNullableFixture()); + + static::assertNull($target->name); + } + + public function testMapRejectsExplicitNullForNonNullableProperties(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('JSON property "name" in class "Arrayy\\tests\\JsonMapperStringFixture" must not be NULL'); + + (new Json())->map(['name' => null], new JsonMapperStringFixture()); + } + + public function testMapRejectsObjectsForStringProperties(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('JSON property "name" in class "Arrayy\\tests\\JsonMapperStringFixture" is an object and cannot be converted to a string'); + + (new Json())->map(['name' => (object) ['value' => 'foo']], new JsonMapperStringFixture()); + } + + public function testMapDirectlyAssignsObjectsThatAlreadyMatchTheDeclaredType(): void + { + $account = new Account('Foo'); + $target = (new Json())->map(['account' => $account], new JsonMapperAccountHolderFixture()); + + static::assertSame($account, $target->account); + } + + public function testMapCreatesTypedObjectsFromScalarAndObjectInput(): void + { + $mapper = new Json(); + + $fromScalar = $mapper->map(['account' => 'Foo'], new JsonMapperAccountHolderFixture()); + static::assertInstanceOf(Account::class, $fromScalar->account); + static::assertSame('Foo', $fromScalar->account->accountName); + + $fromObject = $mapper->map(['account' => (object) ['accountName' => 'Bar']], new JsonMapperAccountHolderFixture()); + static::assertInstanceOf(Account::class, $fromObject->account); + static::assertSame('Bar', $fromObject->account->accountName); + } + + public function testMapArrayHandlesNestedArraysScalarCastingAndClassInstantiation(): void + { + $mapper = new Json(); + + static::assertSame([[1, 2]], $mapper->mapArray([['1', '2']], [], 'int[]')); + static::assertSame([null, 2], $mapper->mapArray([null, '2'], [], 'int')); + + $objects = $mapper->mapArray([(object) ['accountName' => 'Baz']], [], Account::class); + static::assertInstanceOf(Account::class, $objects[0]); + static::assertSame('Baz', $objects[0]->accountName); + } + + public function testMapArrayRejectsNestedArraysForScalarTypes(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('JSON property "items" is an array of type "int" but contained a value of type "array"'); + + (new Json())->mapArray([['x']], [], 'int', 'items'); + } + + public function testMapArraySupportsArrayObjectTargets(): void + { + $mapped = (new Json())->mapArray([['foo' => 'bar']], [], \ArrayObject::class); + + static::assertInstanceOf(\ArrayObject::class, $mapped[0]); + static::assertSame(['foo' => 'bar'], $mapped[0]->getArrayCopy()); + } + + public function testMapArrayCreatesNestedArrayyObjectsFromPhpDocTypes(): void + { + $mapped = (new Json())->mapArray( + [ + 'city' => (object) [ + 'name' => 'Düsseldorf', + 'plz' => null, + 'infos' => ['foo'], + ], + ], + new JsonMapperArrayyCityHolderFixture() + ); + + static::assertInstanceOf(CityData::class, $mapped['city']); + static::assertSame('Düsseldorf', $mapped['city']['name']); + } +} + +final class JsonMapperPrivatePropertyFixture +{ + private string $secret = 'keep'; + + public function getSecret(): string + { + return $this->secret; + } +} + +final class JsonMapperDocOnlyFixture +{ + /** + * Plain documentation without type metadata. + */ + public mixed $payload; +} + +final class JsonMapperNullableFixture +{ + /** + * @var string|null + */ + public $name; +} + +final class JsonMapperStringFixture +{ + /** + * @var string + */ + public $name; +} + +final class JsonMapperAccountHolderFixture +{ + /** + * @var \Arrayy\tests\Account + */ + public $account; +} + +/** + * @property \Arrayy\tests\CityData $city + * @extends \Arrayy\Arrayy> + */ +final class JsonMapperArrayyCityHolderFixture extends Arrayy +{ +} diff --git a/tests/JsonMapperTest.php b/tests/JsonMapperTest.php index 0128d9d..9abda9a 100644 --- a/tests/JsonMapperTest.php +++ b/tests/JsonMapperTest.php @@ -7,7 +7,7 @@ */ final class JsonMapperTest extends \PHPUnit\Framework\TestCase { - public function testJsonMappingV1() + public function testJsonMappingV1(): void { $data = ['accounts' => [new Account('Foo'), new Account('Bar')]]; $json = json_encode($data); diff --git a/tests/ModelA.php b/tests/ModelA.php index 0112e57..fdddd25 100644 --- a/tests/ModelA.php +++ b/tests/ModelA.php @@ -5,7 +5,7 @@ use Arrayy\ArrayyIterator; /** - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class ModelA extends \Arrayy\Arrayy implements ModelInterface { diff --git a/tests/ModelB.php b/tests/ModelB.php index ad0f2ad..388a66f 100644 --- a/tests/ModelB.php +++ b/tests/ModelB.php @@ -3,7 +3,7 @@ namespace Arrayy\tests; /** - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class ModelB extends \Arrayy\Arrayy implements ModelInterface { diff --git a/tests/ModelTest.php b/tests/ModelTest.php index 7e0ff42..b3f7f67 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -9,7 +9,7 @@ */ final class ModelTest extends \PHPUnit\Framework\TestCase { - public function testDotNotation() + public function testDotNotation(): void { $model = new ModelA(['foo', 'bar' => ['config' => ['lall' => true]]]); $tmpModel = new ModelA(['foo']); @@ -24,7 +24,7 @@ public function testDotNotation() static::assertTrue($tmpModel == $model->firstsImmutable(1)); } - public function testForEach() + public function testForEach(): void { $colors = new ModelB(['red', 'yellow', 'green', 'white']); @@ -39,7 +39,7 @@ public function testForEach() $colors->natsort(); } - public function testJsonMapper() + public function testJsonMapper(): void { $colors = ModelB::createFromJsonMapper('["red","yellow","green","white"]'); diff --git a/tests/NativeCityData.php b/tests/NativeCityData.php index 8aa5f78..e4b0c8e 100644 --- a/tests/NativeCityData.php +++ b/tests/NativeCityData.php @@ -3,7 +3,7 @@ namespace Arrayy\tests; /** - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class NativeCityData extends \Arrayy\Arrayy { diff --git a/tests/NativeIntersectionData.php b/tests/NativeIntersectionData.php index f6225ce..214880c 100644 --- a/tests/NativeIntersectionData.php +++ b/tests/NativeIntersectionData.php @@ -3,7 +3,7 @@ namespace Arrayy\tests; /** - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class NativeIntersectionData extends \Arrayy\Arrayy { diff --git a/tests/NativePropertyTypeTest.php b/tests/NativePropertyTypeTest.php index 2e8812d..06bb24e 100644 --- a/tests/NativePropertyTypeTest.php +++ b/tests/NativePropertyTypeTest.php @@ -9,7 +9,7 @@ */ final class NativePropertyTypeTest extends \PHPUnit\Framework\TestCase { - public function testNativeTypedPropertiesSetAndGet() + public function testNativeTypedPropertiesSetAndGet(): void { $cityMeta = NativeCityData::meta(); $city = new NativeCityData( @@ -36,7 +36,7 @@ public function testNativeTypedPropertiesSetAndGet() static::assertSame('city', $modelMeta->city); } - public function testNativeTypedPropertiesRejectInvalidValues() + public function testNativeTypedPropertiesRejectInvalidValues(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type'); @@ -50,7 +50,7 @@ public function testNativeTypedPropertiesRejectInvalidValues() ); } - public function testNativeTypedArrayPropertiesRejectInvalidElementTypes() + public function testNativeTypedArrayPropertiesRejectInvalidElementTypes(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected "infos" to be of type {string[]}'); @@ -66,7 +66,7 @@ public function testNativeTypedArrayPropertiesRejectInvalidElementTypes() ); } - public function testNativeMetaIncludesPropertiesDeclaredNatively() + public function testNativeMetaIncludesPropertiesDeclaredNatively(): void { $cityMeta = NativeCityData::meta(); @@ -75,10 +75,10 @@ public function testNativeMetaIncludesPropertiesDeclaredNatively() static::assertSame('infos', $cityMeta->infos); } - public function testNativeTypedPropertiesRejectUnknownKeysWhenMismatchCheckIsEnabled() + public function testNativeTypedPropertiesRejectUnknownKeysWhenMismatchCheckIsEnabled(): void { $this->expectException(\TypeError::class); - $this->expectExceptionMessage('The key "unknown" does not exists'); + $this->expectExceptionMessage('The key "unknown" does not exist'); new NativeCityData( [ @@ -90,7 +90,7 @@ public function testNativeTypedPropertiesRejectUnknownKeysWhenMismatchCheckIsEna ); } - public function testNativeTypedPropertiesWorkWithJsonMapper() + public function testNativeTypedPropertiesWorkWithJsonMapper(): void { $json = '{"id":1,"firstName":"Lars","lastName":"Moelleken","city":{"name":"Düsseldorf","plz":null,"infos":["lall"]}}'; $userData = NativeUserData::createFromJsonMapper($json); @@ -101,7 +101,7 @@ public function testNativeTypedPropertiesWorkWithJsonMapper() static::assertSame('Düsseldorf', $userData[NativeUserData::meta()->city][NativeCityData::meta()->name]); } - public function testNativeTypedArrayPropertiesRejectInvalidJsonMapperElementTypes() + public function testNativeTypedArrayPropertiesRejectInvalidJsonMapperElementTypes(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected "infos" to be of type {string[]}'); @@ -109,7 +109,7 @@ public function testNativeTypedArrayPropertiesRejectInvalidJsonMapperElementType NativeCityData::createFromJsonMapper('{"name":"Düsseldorf","plz":null,"infos":[1,2,3]}'); } - public function testNativeTypedNestedJsonMapperRejectsInvalidArrayElementTypes() + public function testNativeTypedNestedJsonMapperRejectsInvalidArrayElementTypes(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type: expected "infos" to be of type {string[]}'); @@ -117,7 +117,7 @@ public function testNativeTypedNestedJsonMapperRejectsInvalidArrayElementTypes() NativeUserData::createFromJsonMapper('{"id":1,"firstName":"Lars","lastName":"Moelleken","city":{"name":"Düsseldorf","plz":null,"infos":[1,2,3]}}'); } - public function testNativeTypedPropertiesAreMergedFromParentClasses() + public function testNativeTypedPropertiesAreMergedFromParentClasses(): void { $modelMeta = NativeBigCityData::meta(); $model = new NativeBigCityData( @@ -139,7 +139,7 @@ public function testNativeTypedPropertiesAreMergedFromParentClasses() * Risk: if parseReflectionTypeObject's union-type branch silently accepts every value, * only tests that try all three cases (accept A, accept B, reject other) catch the breakage. */ - public function testNativeUnionTypeAcceptsBothValidSubtypes() + public function testNativeUnionTypeAcceptsBothValidSubtypes(): void { $meta = NativeUserData::meta(); @@ -153,7 +153,7 @@ public function testNativeUnionTypeAcceptsBothValidSubtypes() /** * Risk: if parseReflectionTypeObject returns wrong types for a union, a float would slip through. */ - public function testNativeUnionTypeRejectsInvalidType() + public function testNativeUnionTypeRejectsInvalidType(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessageMatches('#Invalid type: expected "firstName" to be of type \{(int\|string|string\|int)\}#'); @@ -166,7 +166,7 @@ public function testNativeUnionTypeRejectsInvalidType() * Risk: if typeAllowsNull mis-classifies ?string as non-nullable, null would be rejected; * if it mis-classifies as always-nullable, ints would be accepted. */ - public function testNativeNullablePropertyRejectsWrongType() + public function testNativeNullablePropertyRejectsWrongType(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessageMatches('#Invalid type: expected "plz" to be of type \{string\|null\}#'); @@ -183,7 +183,7 @@ public function testNativeNullablePropertyRejectsWrongType() * Risk: if type checking were removed from offsetSet / internalSet, post-construction * assignments with wrong types would silently succeed. */ - public function testNativePropertyTypeIsEnforcedAfterConstruction() + public function testNativePropertyTypeIsEnforcedAfterConstruction(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessageMatches('#Invalid type: expected "id" to be of type \{int\}#'); @@ -197,10 +197,10 @@ public function testNativePropertyTypeIsEnforcedAfterConstruction() * Risk: if checkPropertiesMismatch were removed from checkType, assigning an unknown key * after construction on a mismatch-guarded class would silently succeed. */ - public function testNativePropertyMismatchIsEnforcedAfterConstruction() + public function testNativePropertyMismatchIsEnforcedAfterConstruction(): void { $this->expectException(\TypeError::class); - $this->expectExceptionMessage('The key "unknown" does not exists'); + $this->expectExceptionMessage('The key "unknown" does not exist'); $cityMeta = NativeCityData::meta(); $model = new NativeCityData([ @@ -215,7 +215,7 @@ public function testNativePropertyMismatchIsEnforcedAfterConstruction() * Risk: if the property-mismatch check in the constructor were bypassed for native classes, * omitting required properties would silently succeed. */ - public function testNativeMissingRequiredPropertiesInConstructorThrows() + public function testNativeMissingRequiredPropertiesInConstructorThrows(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Property mismatch'); @@ -228,7 +228,7 @@ public function testNativeMissingRequiredPropertiesInConstructorThrows() * Risk: if the inheritance walk in getPropertiesFromNativeDefinitions stopped at the * concrete class, parent-declared properties would never be type-checked in a child. */ - public function testNativeInheritedParentPropertyTypeConstraintIsEnforcedInChild() + public function testNativeInheritedParentPropertyTypeConstraintIsEnforcedInChild(): void { $this->expectException(\TypeError::class); // NativeBigCityData inherits `string $name` from NativeCityData @@ -248,7 +248,7 @@ public function testNativeInheritedParentPropertyTypeConstraintIsEnforcedInChild * * @requires PHP 8.1 */ - public function testNativeIntersectionTypedPropertiesWork() + public function testNativeIntersectionTypedPropertiesWork(): void { $modelMeta = NativeIntersectionData::meta(); $items = new \ArrayObject(['foo']); diff --git a/tests/NativeUserData.php b/tests/NativeUserData.php index 044047a..af30579 100644 --- a/tests/NativeUserData.php +++ b/tests/NativeUserData.php @@ -3,7 +3,7 @@ namespace Arrayy\tests; /** - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class NativeUserData extends \Arrayy\Arrayy { diff --git a/tests/PHPStan/AnalyseTest.php b/tests/PHPStan/AnalyseTest.php index c411a63..11c5e0f 100644 --- a/tests/PHPStan/AnalyseTest.php +++ b/tests/PHPStan/AnalyseTest.php @@ -9,7 +9,7 @@ */ final class AnalyseTest extends \PHPUnit\Framework\TestCase { - public function testGenerics() + public function testGenerics(): void { $json = '[{"id":1,"firstName":"Lars","lastName":"Moelleken","city":{"name":"Düsseldorf","plz":null,"infos":["lall"]}}, {"id":2,"firstName":"Sven","lastName":"Moelleken","city":{"name":"Köln","plz":null,"infos":["foo"]}}]'; $userDataCollection = UserDataCollection::createFromJsonMapper($json); @@ -19,7 +19,7 @@ public function testGenerics() static::assertInstanceOf(\Arrayy\tests\UserData::class, $user); \PHPStan\Testing\assertType('Arrayy\tests\CityData|null', $user->city); - static::assertTrue($user->city === null || $user->city instanceof \Arrayy\tests\CityData); /* @phpstan-ignore-line | always true */ + static::assertTrue($user->city === null || $user->city instanceof \Arrayy\tests\CityData); /* @phpstan-ignore staticMethod.alreadyNarrowedType, instanceof.alwaysTrue, booleanOr.alwaysTrue */ \PHPStan\Testing\assertType('string|null', $user->city->name ?? null); static::assertTrue(($user->city->name ?? null) === null || is_string($user->city->name ?? null)); @@ -41,19 +41,19 @@ public function testGenerics() $set[] = 'F'; $set[] = 'G'; try { - /* @phpstan-ignore-next-line | not accept */ + /* @phpstan-ignore offsetAssign.valueType */ $set[] = 2; } catch (\TypeError $e) { // nothing } try { - /* @phpstan-ignore-next-line | not accept */ + /* @phpstan-ignore offsetAssign.valueType */ $set[] = 3; } catch (\TypeError $e) { // nothing } try { - /* @phpstan-ignore-next-line | not accept */ + /* @phpstan-ignore offsetAssign.valueType */ $set[] = false; } catch (\TypeError $e) { // nothing @@ -85,7 +85,7 @@ public function testGenerics() foreach ($set as $item) { \PHPStan\Testing\assertType('non-empty-string', $item); - static::assertTrue(strlen($item) > 0);/* @phpstan-ignore-line | always true */ + static::assertTrue(strlen($item) > 0); /* @phpstan-ignore staticMethod.alreadyNarrowedType, greater.alwaysTrue */ } // ------------------------------------------------------------------------- diff --git a/tests/PHPStan/ArrayShapeAccessTest.php b/tests/PHPStan/ArrayShapeAccessTest.php new file mode 100644 index 0000000..66e781a --- /dev/null +++ b/tests/PHPStan/ArrayShapeAccessTest.php @@ -0,0 +1,40 @@ + 1, + 'firstName' => 'Lars', + 'lastName' => 'Moelleken', + 'city' => new ArrayShapeCity([ + 'name' => 'Düsseldorf', + 'plz' => null, + ]), + ]); + + \PHPStan\Testing\assertType('int|null', $user['id']); + \PHPStan\Testing\assertType('string|null', $user['firstName']); + \PHPStan\Testing\assertType('string|null', $user['lastName']); + \PHPStan\Testing\assertType('Arrayy\tests\PHPStan\ArrayShapeCity|null', $user['city']); + + if ($user['city'] !== null) { + \PHPStan\Testing\assertType('Arrayy\tests\PHPStan\ArrayShapeCity', $user['city']); + \PHPStan\Testing\assertType('string|null', $user['city']['name']); + \PHPStan\Testing\assertType('string|null', $user['city']['plz']); + } + + self::assertSame('Moelleken', $user['lastName']); + self::assertInstanceOf(ArrayShapeCity::class, $user['city']); + } +} diff --git a/tests/PHPStan/ArrayShapeCity.php b/tests/PHPStan/ArrayShapeCity.php new file mode 100644 index 0000000..ca2097e --- /dev/null +++ b/tests/PHPStan/ArrayShapeCity.php @@ -0,0 +1,16 @@ +, value-of, T> + */ +final class ArrayShapeCity extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; + + protected $checkPropertiesMismatchInConstructor = true; +} diff --git a/tests/PHPStan/ArrayShapeUser.php b/tests/PHPStan/ArrayShapeUser.php new file mode 100644 index 0000000..762e393 --- /dev/null +++ b/tests/PHPStan/ArrayShapeUser.php @@ -0,0 +1,16 @@ +, value-of, T> + */ +final class ArrayShapeUser extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; + + protected $checkPropertiesMismatchInConstructor = true; +} diff --git a/tests/StaticArrayyTest.php b/tests/StaticArrayyTest.php index a8cd2bf..bbb5b54 100644 --- a/tests/StaticArrayyTest.php +++ b/tests/StaticArrayyTest.php @@ -10,7 +10,7 @@ */ final class StaticArrayyTest extends \PHPUnit\Framework\TestCase { - public function testBadMethodCall() + public function testBadMethodCall(): void { $this->expectException(\BadMethodCallException::class); @@ -19,86 +19,78 @@ public function testBadMethodCall() $result = A::invalidMethod('foo'); // @phpstan-ignore staticMethod.notFound } - public function testEmptyArgsInvocation() + public function testEmptyArgsInvocation(): void { /** @noinspection PhpUndefinedMethodInspection */ $result = A::first(); // @phpstan-ignore staticMethod.notFound static::assertNull($result); } - public function testInvocation() + public function testInvocation(): void { /** @noinspection PhpUndefinedMethodInspection */ $result = A::first(['lall', 'FOOBAR'], 1); // @phpstan-ignore staticMethod.notFound static::assertSame('lall', $result); } - public function testPartialArgsInvocation() + public function testPartialArgsInvocation(): void { /** @noinspection PhpUndefinedMethodInspection */ $result = A::replaceOneValue(['foo', 'bar'], 'foo'); // @phpstan-ignore staticMethod.notFound static::assertSame(['', 'bar'], $result->getArray()); } - public function testFullArgsInvocation() + public function testFullArgsInvocation(): void { /** @noinspection PhpUndefinedMethodInspection */ $result = A::replaceOneValue(['foo', 'bar'], 'foo', 'test'); // @phpstan-ignore staticMethod.notFound static::assertSame(['test', 'bar'], $result->getArray()); } - public function testArrayyRange() + public function testArrayyRange(): void { $result = A::range(1, null); static::assertSame([1], $result->getArray()); } - public function testArrayyRange1() + public function testArrayyRange1(): void { $result = A::range(1, null, 10); static::assertSame([1], $result->getArray()); } - public function testArrayyRange10() + public function testArrayyRange10(): void { $result = A::range(1, 10); static::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $result->getArray()); } - public function testArrayyRange100() + public function testArrayyRange100(): void { $result = A::range(0, 100, 10); static::assertSame([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100], $result->getArray()); } - public function testArrayyRepeat() + public function testArrayyRepeat(): void { $result = A::repeat('foobar', 3); - if (\method_exists(__CLASS__, 'assertStringContainsString')) { - static::assertStringContainsString('foobar,foobar,foobar', (string) $result); - } else { - static::assertContains('foobar,foobar,foobar', (string) $result); - } + static::assertStringContainsString('foobar,foobar,foobar', (string) $result); $result = A::repeat('', 3); static::assertSame('', (string) $result); } - public function testArrayyRepeatWithArray() + public function testArrayyRepeatWithArray(): void { $result = A::repeat(3, 2); - if (\method_exists(__CLASS__, 'assertStringContainsString')) { - static::assertStringContainsString('3,3', (string) $result); - } else { - static::assertContains('3,3', (string) $result); - } + static::assertStringContainsString('3,3', (string) $result); } /** @@ -106,7 +98,7 @@ public function testArrayyRepeatWithArray() * static method should accept 2 more arguments than their Stringy * equivalent. */ - public function testArgumentNumbers() + public function testArgumentNumbers(): void { $staticArrayyClass = new \ReflectionClass(A::class); $arrayyClass = new \ReflectionClass(Arrayy::class); diff --git a/tests/TypeCheckCoreCoverageTest.php b/tests/TypeCheckCoreCoverageTest.php index cd11f2b..4f0671d 100644 --- a/tests/TypeCheckCoreCoverageTest.php +++ b/tests/TypeCheckCoreCoverageTest.php @@ -219,6 +219,102 @@ public function testFromPhpDocumentorPropertyParsesSupportedPseudoTypes(): void static::assertSame(['string[]'], $arrayTypeCheck->getTypes()); } + /** + * Risk: `parseDocTypeObject()` has a Nullable branch that wraps the inner type in + * ['innerType', 'null']. If this branch is removed or mis-ordered relative to + * Compound handling, nullable @property types (e.g. `?City`) stop being accepted. + */ + public function testFromDocTypeObjectNullableProducesNullableChecker(): void + { + $docBlock = DocBlockFactory::createInstance()->create(<<<'DOC' +/** + * @property ?\ArrayObject $city + */ +DOC); + $tag = $docBlock->getTagsByName('property')[0]; + + $checker = TypeCheckPhpDoc::fromDocTypeObject('city', $tag->getType()); + + static::assertSame(['\\ArrayObject', 'null'], $checker->getTypes()); + + $nullValue = null; + $objectValue = new \ArrayObject(); + static::assertTrue($checker->checkType($nullValue)); + static::assertTrue($checker->checkType($objectValue)); + } + + /** + * Risk: `parseDocTypeObject()` has an ArrayShape branch that returns 'array' when a + * shape value type is itself a nested array-shape. If this branch is removed, nesting + * a shape inside a shape raises a "no branch matched" case and the type is silently + * returned as the raw toString representation instead of 'array'. + */ + public function testFromDocTypeObjectNestedArrayShapeYieldsArrayType(): void + { + $docBlock = DocBlockFactory::createInstance()->create(<<<'DOC' +/** + * @template T of array{data: array{x: int}} + */ +DOC); + $bound = $docBlock->getTagsByName('template')[0]->getBound(); + $nestedShapeType = $bound->getItems()[0]->getValue(); // array{x: int} + + $checker = TypeCheckPhpDoc::fromDocTypeObject('data', $nestedShapeType); + + // A nested array shape is collapsed to 'array'; only structural shape keys of + // the *model* are registered as properties. + static::assertSame(['array'], $checker->getTypes()); + $anyArray = ['x' => 42, 'extra' => true]; + static::assertTrue($checker->checkType($anyArray)); + } + + /** + * Risk: happy path for a valid nested model value in an optional shape key. This + * exercises the `Object_` branch of parseDocTypeObject for nullable class types and + * ensures that a correctly-typed value for the `city` key is accepted at construction. + */ + public function testArrayShapeOptionalKeyAcceptsValidObjectValue(): void + { + $meta = TypeCheckArrayShapeUserData::meta(); + $city = new \Arrayy\tests\CityData([ + 'plz' => null, + 'name' => 'Düsseldorf', + 'infos' => ['lall'], + ]); + + $model = new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'Moelleken', + $meta->infos => ['a'], + $meta->city => $city, + ]); + + static::assertInstanceOf(\Arrayy\tests\CityData::class, $model[$meta->city]); + static::assertSame('Düsseldorf', $model[$meta->city]['name']); + } + + /** + * Risk: `city?: CityData|null` encodes two independent branches — the key may be omitted, + * and when present the value may be either a CityData instance or null. Coverage must prove + * explicit null is accepted, not only omission and object input. + */ + public function testArrayShapeOptionalNullableKeyAcceptsExplicitNull(): void + { + $meta = TypeCheckArrayShapeUserData::meta(); + + $model = new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'Moelleken', + $meta->infos => ['a'], + $meta->city => null, + ]); + + static::assertArrayHasKey($meta->city, $model->getArray()); + static::assertNull($model[$meta->city]); + } + /** * Risk: these scalar/null/mixed docblock tokens are mapped manually; if any branch drifts, * `Arrayy` starts rejecting valid values or formatting the wrong expected type. @@ -346,6 +442,278 @@ public function testTypeCheckCallbackValidatesAndSupportsNullableValues(): void $failingCheck->checkType($invalidValue); } + public function testArrayShapeTemplateProvidesPropertyDefinitions(): void + { + $meta = TypeCheckArrayShapeUserData::meta(); + $model = new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'Moelleken', + $meta->infos => ['foo'], + ]); + + static::assertSame('id', $meta->id); + static::assertSame('city', $meta->city); + static::assertSame('Lars', $model[$meta->firstName]); + } + + public function testArrayShapeTemplateRejectsInvalidPropertyTypes(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('Invalid type: expected "infos" to be of type {string[]}'); + + $meta = TypeCheckArrayShapeUserData::meta(); + new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'Moelleken', + $meta->infos => [1], + ]); + } + + public function testArrayShapeTemplateRejectsUnknownProperties(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('The key "unknown" does not exist'); + + $meta = TypeCheckArrayShapeUserData::meta(); + new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'Moelleken', + $meta->infos => ['foo'], + 'unknown' => 'value', + ]); + } + + public function testPropertyTagsAndArrayShapeTemplateCannotBeMixed(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('Use either @property tags or array-shape annotations'); + + new TypeCheckMixedPropertyAnnotationsData(['id' => 1]); + } + + public function testPropertyTagsInParentAndArrayShapeInChildCannotBeMixed(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('Use either @property tags or array-shape annotations'); + + new TypeCheckMixedPropertyAnnotationsInheritanceData(['id' => 1]); + } + + /** + * Risk: optional shape keys skip the constructor-mismatch check but must still go + * through `checkType()` when a value is actually supplied; removing the per-key + * `$this->properties[$key]->checkType($value)` call would silently accept any value. + */ + public function testArrayShapeOptionalKeyIsTypeCheckedWhenPresent(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('Invalid type'); + + $meta = TypeCheckArrayShapeUserData::meta(); + new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'Moelleken', + $meta->infos => ['foo'], + $meta->city => new \stdClass(), // wrong type – must throw + ]); + } + + /** + * Risk: "optional" means the array key may be absent from the input, not that null + * is a valid value. If the `isOptional` flag were incorrectly widened to imply + * nullable, the type check would be silently skipped for null values. + * + * This exercises the post-construction (offsetSet) path which always runs checkType. + */ + public function testArrayShapeOptionalNonNullableKeyRejectsNull(): void + { + $this->expectException(\TypeError::class); + + // TypeCheckArrayShapeScoreData defines score?: int (optional, not nullable) + $model = new TypeCheckArrayShapeScoreData([]); + $model['score'] = null; // offsetSet always calls checkType; null ≠ int → throws + } + + /** + * Risk: if the `$requiredProperties = array_diff_key(…)` split were removed and all + * shape properties were treated as required, constructing the same model a second + * time (the cached path) would fail to exclude optional keys from the mismatch check. + * + * Uses a dedicated fixture so the cache state is deterministic within the test. + */ + public function testArrayShapeCachingPreservesOptionalPropertiesOnSecondInstantiation(): void + { + // First construction hits the uncached path. + $first = new TypeCheckArrayShapeCacheTestModel(['name' => 'Alice']); + // Second construction hits the CACHED path – optionalProperties must be restored. + $second = new TypeCheckArrayShapeCacheTestModel(['name' => 'Bob']); + + static::assertSame('Alice', $first['name']); + static::assertSame('Bob', $second['name']); + // Neither construction should have thrown a "Property mismatch" error because + // 'tag' is optional; if the cache fix is missing, the second would throw. + } + + /** + * Risk: the guard `$tag->getTemplateName() === 'T'` ensures that only the canonical + * `@template T of array{…}` form is used as a property map. If the check were + * removed, ANY template bound to an array shape would be treated as property metadata. + */ + public function testArrayShapeTemplateNameOtherThanTIsIgnored(): void + { + // TypeCheckArrayShapeWrongTemplateName uses @template Data of array{id: int}. + // The name guard must skip it, so no properties are registered and any key is + // accepted without type checking. + $model = new TypeCheckArrayShapeWrongTemplateName(['id' => 'not-an-int']); + static::assertSame('not-an-int', $model['id']); + } + + /** + * Risk: the @extends inline-shape form (`@extends Arrayy`) must be + * parsed even without a preceding @template T preamble. Removing that branch of + * `getArrayShapeItemsFromDocBlock()` would silently drop this annotation style. + */ + public function testArrayShapeInlineExtendsFormParsesShapeProperties(): void + { + $meta = TypeCheckArrayShapeExtendsOnlyData::meta(); + static::assertSame('score', $meta->score); + + $model = new TypeCheckArrayShapeExtendsOnlyData([$meta->score => 42]); + static::assertSame(42, $model[$meta->score]); + } + + public function testIntermediateArrayyExtendsShapeIsExposedViaMeta(): void + { + $meta = TypeCheckArrayShapeViaIntermediateBaseData::meta(); + + static::assertSame('id', $meta->id); + } + + public function testIntermediateArrayyExtendsShapeRejectsInvalidPropertyTypes(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessageMatches('#Invalid type: expected "id" to be of type \{int\}#'); + + new TypeCheckArrayShapeViaIntermediateBaseData(['id' => 'not-an-int']); + } + + /** + * Risk: the @extends FQCN guard (`in_array(…, [Arrayy::class, ArrayyStrict::class])`) + * must prevent shapes on unrelated classes from being parsed as property metadata. + * Removing the guard would inject spurious property definitions. + */ + public function testNonArrayyExtendsShapeIsNotParsed(): void + { + // TypeCheckNonArrayyExtendsData has @extends stdClass. + // The FQCN guard skips stdClass, so no shape properties should be registered; + // any key/value combination must be accepted without type checking. + $model = new TypeCheckNonArrayyExtendsData(['id' => 'not-an-int', 'extra' => true]); + static::assertSame('not-an-int', $model['id']); + static::assertSame(true, $model['extra']); + } + + /** + * Risk: `fromDocTypeObject()` is called with $type = null when a shape item carries + * no explicit type annotation. If the null guard (`if ($type) { … }`) were removed, + * the function would attempt `parseDocTypeObject(null)` and crash. The checker + * it returns must have an empty types list. + * + * A checker with empty types is maximally restrictive (it throws for all values), + * which is intentional; callers must not treat "no type annotation" as "accept all". + */ + public function testFromDocTypeObjectWithNullTypeReturnsCheckerWithEmptyTypes(): void + { + $checker = TypeCheckPhpDoc::fromDocTypeObject('myProp', null); + + static::assertSame([], $checker->getTypes()); + + // An empty types list means there is no declared type that can match, so + // checkType() throws for every value – verify the production-safe null path. + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('expected "myProp" to be of type {}'); + $nullValue = null; + $checker->checkType($nullValue); + } + + public function testFromDocTypeObjectWithParsedTypeKeepsPropertyNameInErrors(): void + { + $docBlock = DocBlockFactory::createInstance()->create(<<<'DOC' +/** + * @property int $myProp + */ +DOC); + $tag = $docBlock->getTagsByName('property')[0]; + + $checker = TypeCheckPhpDoc::fromDocTypeObject('myProp', $tag->getType()); + + static::assertSame(['int'], $checker->getTypes()); + + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('expected "myProp" to be of type {int}'); + $value = 'not-an-int'; + $checker->checkType($value); + } + + /** + * Risk: all shape keys, including optional ones, must be surfaced by meta() so that + * callers can use `$meta->city` as a type-safe key reference even when city may be + * absent from the constructor input. If optional keys were excluded from the property + * map, meta() would return empty strings for them. + */ + public function testArrayShapeMetaIncludesAllKeysIncludingOptional(): void + { + $meta = TypeCheckArrayShapeUserData::meta(); + + static::assertSame('id', $meta->id); + static::assertSame('firstName', $meta->firstName); + static::assertSame('lastName', $meta->lastName); + static::assertSame('city', $meta->city); // optional key + static::assertSame('infos', $meta->infos); + } + + /** + * Risk: post-construction writes via offsetSet must continue to be type-checked; + * removing checkType() from internalSet() would allow any value after construction. + */ + public function testArrayShapePostConstructionTypeCheckEnforced(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessageMatches('#Invalid type: expected "id" to be of type \{int\}#'); + + $meta = TypeCheckArrayShapeUserData::meta(); + $model = new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'M', + $meta->infos => [], + ]); + $model[$meta->id] = 'not-an-int'; // offsetSet → internalSet(…, true) → checkType + } + + /** + * Risk: post-construction writes of unknown keys must be rejected when + * checkPropertiesMismatch is true; removing the key-existence guard in checkType() + * would allow new keys to be silently injected into a shape-typed model. + */ + public function testArrayShapePostConstructionMismatchEnforced(): void + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('The key "ghost" does not exist'); + + $meta = TypeCheckArrayShapeUserData::meta(); + $model = new TypeCheckArrayShapeUserData([ + $meta->id => 1, + $meta->firstName => 'Lars', + $meta->lastName => 'M', + $meta->infos => [], + ]); + $model['ghost'] = 'injected'; // must throw – 'ghost' is not in the shape + } + /** * @return iterable}> */ @@ -392,3 +760,132 @@ final class TypeCheckDocOverridesNativeFixture */ public string $value = ''; } + +/** + * @template T of array{id: int, firstName: int|string, lastName: string, city?: \Arrayy\tests\CityData|null, infos: string[]} + * @extends \Arrayy\Arrayy, value-of, T> + */ +final class TypeCheckArrayShapeUserData extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; + + protected $checkForMissingPropertiesInConstructor = true; + + protected $checkPropertiesMismatchInConstructor = true; +} + +/** + * @property int $legacyId + * @template T of array{id: int} + * @extends \Arrayy\Arrayy, value-of, T> + */ +final class TypeCheckMixedPropertyAnnotationsData extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; +} + +/** + * @property int $legacyId + * @extends \Arrayy\Arrayy> + */ +abstract class TypeCheckPropertyTagParentData extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; +} + +/** + * @template T of array{id: int} + */ +final class TypeCheckMixedPropertyAnnotationsInheritanceData extends TypeCheckPropertyTagParentData +{ +} + +/** + * Optional key whose value type does NOT include null. "Optional" means the key + * may be absent; null must still be rejected when the key is present. + * + * @template T of array{score?: int} + * @extends \Arrayy\Arrayy, value-of, T> + */ +final class TypeCheckArrayShapeScoreData extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; + + protected $checkPropertiesMismatch = true; +} + +/** + * Used exclusively by testArrayShapeCachingPreservesOptionalPropertiesOnSecondInstantiation + * to exercise the static-cache restore of $optionalProperties. + * + * @template T of array{name: string, tag?: string} + * @extends \Arrayy\Arrayy, value-of, T> + */ +final class TypeCheckArrayShapeCacheTestModel extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; + + protected $checkPropertiesMismatch = true; + + protected $checkPropertiesMismatchInConstructor = true; + + protected $checkForMissingPropertiesInConstructor = true; +} + +/** + * Uses the inline @extends form to define the shape, with no @template T preamble. + * Both `@template T of array{…}` and `@extends Arrayy` must be supported. + * + * @extends \Arrayy\Arrayy, value-of, array{score: int}> + */ +final class TypeCheckArrayShapeExtendsOnlyData extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; + + protected $checkPropertiesMismatch = true; +} + +/** + * @template TShape + * @template TValue + * @extends \Arrayy\Arrayy> + */ +abstract class TypeCheckCustomArrayyBase extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; + + protected $checkPropertiesMismatch = true; + + protected $checkForMissingPropertiesInConstructor = true; +} + +/** + * @extends \Arrayy\tests\TypeCheckCustomArrayyBase + */ +final class TypeCheckArrayShapeViaIntermediateBaseData extends TypeCheckCustomArrayyBase +{ +} + +/** + * Uses @template with a name other than T – must be silently ignored by the + * `getTemplateName() === 'T'` guard in getArrayShapeItemsFromDocBlock(). + * + * @template Data of array{id: int} + * @extends \Arrayy\Arrayy> + */ +final class TypeCheckArrayShapeWrongTemplateName extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; +} + +/** + * Test fixture: the @extends annotation intentionally names a non-Arrayy class (stdClass) + * to verify that the FQCN guard in getArrayShapeItemsFromDocBlock() ignores the shape. + * The class itself still extends \Arrayy\Arrayy as normal. + * + * @extends stdClass + */ +final class TypeCheckNonArrayyExtendsData extends \Arrayy\Arrayy +{ + protected $checkPropertyTypes = true; +} diff --git a/tests/UserData.php b/tests/UserData.php index 944b62e..05dd226 100644 --- a/tests/UserData.php +++ b/tests/UserData.php @@ -8,7 +8,7 @@ * @property string $lastName * @property \Arrayy\tests\CityData|null $city * - * @extends \Arrayy\Arrayy + * @extends \Arrayy\Arrayy> */ class UserData extends \Arrayy\Arrayy { diff --git a/tests/UserDataTest.php b/tests/UserDataTest.php index 4d1bda0..06dcfed 100644 --- a/tests/UserDataTest.php +++ b/tests/UserDataTest.php @@ -9,7 +9,7 @@ */ final class UserDataTest extends \PHPUnit\Framework\TestCase { - public function testSetAndGet() + public function testSetAndGet(): void { $cityMeta = CityData::meta(); @@ -48,7 +48,7 @@ public function testSetAndGet() static::assertNull($model[3]); } - public function testByJsonMapper() + public function testByJsonMapper(): void { $json = '{"id":1,"firstName":"Lars","lastName":"Moelleken","city":{"name":"Düsseldorf","plz":null,"infos":["lall"]}}'; $userData = UserData::createFromJsonMapper($json); @@ -63,7 +63,7 @@ public function testByJsonMapper() /** * @depends testSetAndGet */ - public function testSetAndGetAgain() + public function testSetAndGetAgain(): void { $modelMeta = UserData::meta(); @@ -81,7 +81,7 @@ public function testSetAndGetAgain() static::assertNull($model[3]); } - public function testSetFail() + public function testSetFail(): void { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Invalid type'); @@ -97,7 +97,7 @@ public function testSetFail() static::assertInstanceOf(Arrayy::class, $model); } - public function testSetFailObject() + public function testSetFailObject(): void { $this->expectException(\TypeError::class);