From a0124c301f62f4ceea72abee803aa0e4d00c4239 Mon Sep 17 00:00:00 2001 From: joaol23 Date: Sun, 14 Apr 2024 23:29:24 -0300 Subject: [PATCH 1/2] feat: adding typedArrays types so that we can assure that an array is really what we want it to be --- .gitignore | 1 + src/Type.php | 10 ++++ src/TypedArray.php | 95 +++++++++++++++++++++++++++++++++++ tests/Array/AsArrayClass.php | 38 ++++++++++++++ tests/Array/AsArrayInt.php | 26 ++++++++++ tests/Array/asArrayString.php | 32 ++++++++++++ 6 files changed, 202 insertions(+) create mode 100644 src/TypedArray.php create mode 100644 tests/Array/AsArrayClass.php create mode 100644 tests/Array/AsArrayInt.php create mode 100644 tests/Array/asArrayString.php diff --git a/.gitignore b/.gitignore index 2e9998e..b74ef03 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /vendor/ *.swp *.swo +/.idea diff --git a/src/Type.php b/src/Type.php index de7c5d1..bfbd163 100644 --- a/src/Type.php +++ b/src/Type.php @@ -42,6 +42,16 @@ public function as(string $type): mixed return $this->variable; } + /** + * Create a new TypedArray instance. + * + * @return TypedArray + */ + public function asArrayOf(): TypedArray + { + return new TypedArray($this->variable); + } + /** * Asserts and narrow down the type to string. * diff --git a/src/TypedArray.php b/src/TypedArray.php new file mode 100644 index 0000000..8a47dc1 --- /dev/null +++ b/src/TypedArray.php @@ -0,0 +1,95 @@ +. + * + * @phpstan-assert-if-true int[] $this->variable + * + * @phpstan-return (TVariable is int[] ? int[] : never) + */ + public function int(): array + { + /** @phpstan-assert non-empty-array $this->variable */ + if (! is_array($this->variable) || $this->variable === []) { + throw new TypeError('Array must be a non-empty array of specified int.'); + } + + foreach ($this->variable as $item) { + if (! is_int($item)) { + throw new TypeError('Array value {'.$item.'} is not [int].'); + } + } + + return $this->variable; + } + + /** + * Asserts and narrow down the type to array. + * + * @phpstan-assert-if-true string[] $this->variable + * + * @phpstan-return (TVariable is string[] ? string[] : never) + */ + public function string(): array + { + /** @phpstan-assert non-empty-array $this->variable */ + if (! is_array($this->variable) || $this->variable === []) { + throw new TypeError('Array must be a non-empty array of specified string.'); + } + + foreach ($this->variable as $item) { + if (! is_string($item)) { + throw new TypeError('Array value {'.$item.'} is not [string].'); + } + } + + return $this->variable; + } + + /** + * Asserts and narrow down the type to the given type. + * + * @template TAs + * + * @param class-string $type + * + * @phpstan-return TAs[] + */ + public function class(string $type): array + { + /** @phpstan-assert non-empty-array $this->variable */ + if (! is_array($this->variable) || $this->variable === []) { + throw new TypeError('Array must be a non-empty array of specified '.$type.'.'); + } + + foreach ($this->variable as $item) { + if (! is_object($item) || ! $item instanceof $type) { + throw new TypeError('Array value {'.$item.'} is not ['.$type.'].'); + } + } + + return $this->variable; + } +} diff --git a/tests/Array/AsArrayClass.php b/tests/Array/AsArrayClass.php new file mode 100644 index 0000000..a64b2ba --- /dev/null +++ b/tests/Array/AsArrayClass.php @@ -0,0 +1,38 @@ +asArrayOf() + ->class(Test::class); + + expect($userArray)->toBeArray(); + foreach ($userArray as $value) { + expect($value)->toBeInstanceOf(Test::class); + } +}); + +test('not Test array', function (): void { + $variable = new Test(); + $variable = [$variable, 7415541]; + + type($variable) + ->asArrayOf() + ->class(Test::class); +})->throws(TypeError::class, 'Array value {7415541} is not [Test].'); + +test('empty array', function (): void { + $variable = []; + + type($variable) + ->asArrayOf() + ->class(Test::class); +})->throws(TypeError::class, 'Array must be a non-empty array of specified Test.'); diff --git a/tests/Array/AsArrayInt.php b/tests/Array/AsArrayInt.php new file mode 100644 index 0000000..0492d76 --- /dev/null +++ b/tests/Array/AsArrayInt.php @@ -0,0 +1,26 @@ +asArrayOf()->int(); + + expect($intArray)->toBeArray(); + foreach ($intArray as $value) { + expect($value)->toBeInt(); + } +}); + +test('not int array', function (): void { + $variable = [7415541, 'error', 4134]; + + type($variable)->asArrayOf()->int(); +})->throws(TypeError::class, 'Array value {error} is not [int].'); + +test('empty array', function (): void { + $variable = []; + + type($variable)->asArrayOf()->int(); +})->throws(TypeError::class, 'Array must be a non-empty array of specified int.'); diff --git a/tests/Array/asArrayString.php b/tests/Array/asArrayString.php new file mode 100644 index 0000000..ca7f579 --- /dev/null +++ b/tests/Array/asArrayString.php @@ -0,0 +1,32 @@ +asArrayOf() + ->string(); + + expect($stringArray)->toBeArray(); + foreach ($stringArray as $value) { + expect($value)->toBeString(); + } +}); + +test('not string array', function (): void { + $variable = ['test', 7415541, 4134]; + + type($variable) + ->asArrayOf() + ->string(); +})->throws(TypeError::class, 'Array value {7415541} is not [string].'); + +test('empty array', function (): void { + $variable = []; + + type($variable) + ->asArrayOf() + ->string(); +})->throws(TypeError::class, 'Array must be a non-empty array of specified string.'); From b7f9c15a80b8691e81c03fd701490b3fb633b894 Mon Sep 17 00:00:00 2001 From: joaol23 Date: Sun, 14 Apr 2024 23:31:28 -0300 Subject: [PATCH 2/2] refactor: update namespace --- src/TypedArray.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TypedArray.php b/src/TypedArray.php index 8a47dc1..a944f9f 100644 --- a/src/TypedArray.php +++ b/src/TypedArray.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AnotherLibrary\TypeGuard; +namespace GlossPHP\TypeGuard; use TypeError;