From 337a8ab4446aa9970c1a65ae4d693d0084c18db9 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 13 May 2025 12:05:48 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(tests):=20=E6=B7=BB=E5=8A=A0=20arrayab?= =?UTF-8?q?le=20=E5=92=8C=20from=20=E6=96=B9=E6=B3=95=E7=9A=84=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B=E5=8F=8A=E7=9B=B8=E5=85=B3=E8=BE=85?= =?UTF-8?q?=E5=8A=A9=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/macros/output/Hyperf/Collection/Arr.php | 25 +++++++ src/macros/src/ArrMixin.php | 40 +++++++++-- tests/Macros/ArrTest.php | 45 ++++++++++++ tests/Macros/Stubs/Common.php | 76 +++++++++++++++++++++ 4 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 tests/Macros/Stubs/Common.php diff --git a/src/macros/output/Hyperf/Collection/Arr.php b/src/macros/output/Hyperf/Collection/Arr.php index 68b19631c..a3d4871b4 100644 --- a/src/macros/output/Hyperf/Collection/Arr.php +++ b/src/macros/output/Hyperf/Collection/Arr.php @@ -16,6 +16,16 @@ class Arr { + /** + * Determine whether the given value is arrayable. + * + * @param mixed $value + * @return bool + */ + public static function arrayable($value) + { + } + /** * Get an array item from an array using "dot" notation. * @return array @@ -43,6 +53,21 @@ public static function float(ArrayAccess|array $array, string|int|null $key, ?fl { } + /** + * Get the underlying array of items from the given argument. + * + * @template TKey of array-key = array-key + * @template TValue = mixed + * + * @param array|Enumerable|Arrayable|WeakMap|Traversable|Jsonable|JsonSerializable|object $items + * @return ($items is WeakMap ? list : array) + * + * @throws InvalidArgumentException + */ + public static function from($items) + { + } + /** * Get an integer item from an array using "dot" notation. * @return int diff --git a/src/macros/src/ArrMixin.php b/src/macros/src/ArrMixin.php index af17b4c25..9b398bf8c 100644 --- a/src/macros/src/ArrMixin.php +++ b/src/macros/src/ArrMixin.php @@ -13,14 +13,29 @@ use ArrayAccess; use Hyperf\Collection\Arr; +use Hyperf\Collection\Enumerable; +use Hyperf\Contract\Arrayable; +use Hyperf\Contract\Jsonable; use InvalidArgumentException; +use JsonSerializable; +use Traversable; +use WeakMap; /** * @mixin Arr */ class ArrMixin { - public static function array() + public function arrayable() + { + return fn ($value) => is_array($value) + || $value instanceof Arrayable + || $value instanceof Traversable + || $value instanceof Jsonable + || $value instanceof JsonSerializable; + } + + public function array() { return function (ArrayAccess|array $array, string|int|null $key, ?array $default = null) { $value = Arr::get($array, $key, $default); @@ -38,7 +53,7 @@ public static function array() /** * Get a boolean item from an array using "dot" notation. */ - public static function boolean() + public function boolean() { return function (ArrayAccess|array $array, string|int|null $key, ?bool $default = null) { $value = Arr::get($array, $key, $default); @@ -56,7 +71,7 @@ public static function boolean() /** * Get a float item from an array using "dot" notation. */ - public static function float() + public function float() { return function (ArrayAccess|array $array, string|int|null $key, ?float $default = null) { $value = Arr::get($array, $key, $default); @@ -71,10 +86,25 @@ public static function float() }; } + public function from() + { + return fn ($items) => match (true) { + is_array($items) => $items, + $items instanceof Enumerable => $items->all(), + $items instanceof Arrayable => $items->toArray(), + $items instanceof WeakMap => iterator_to_array($items, false), + $items instanceof Traversable => iterator_to_array($items), + $items instanceof Jsonable => json_decode($items->toJson(), true), + $items instanceof JsonSerializable => (array) $items->jsonSerialize(), + is_object($items) => (array) $items, + default => throw new InvalidArgumentException('Items cannot be represented by a scalar value.'), + }; + } + /** * Get an integer item from an array using "dot" notation. */ - public static function integer() + public function integer() { return function (ArrayAccess|array $array, string|int|null $key, ?int $default = null) { $value = Arr::get($array, $key, $default); @@ -92,7 +122,7 @@ public static function integer() /** * Get a string item from an array using "dot" notation. */ - public static function string() + public function string() { return function (ArrayAccess|array $array, string|int|null $key, ?string $default = null) { $value = Arr::get($array, $key, $default); diff --git a/tests/Macros/ArrTest.php b/tests/Macros/ArrTest.php index 040e89227..01b31b9f3 100644 --- a/tests/Macros/ArrTest.php +++ b/tests/Macros/ArrTest.php @@ -10,6 +10,26 @@ */ use Hyperf\Collection\Arr; +require_once __DIR__ . '/Stubs/Common.php'; + +test('test arrayable', function () { + $this->assertTrue(Arr::arrayable([])); + $this->assertTrue(Arr::arrayable(new FriendsOfHyperf\Tests\Macros\Stubs\TestArrayableObject())); + $this->assertTrue(Arr::arrayable(new FriendsOfHyperf\Tests\Macros\Stubs\TestJsonableObject())); + $this->assertTrue(Arr::arrayable(new FriendsOfHyperf\Tests\Macros\Stubs\TestJsonSerializeObject())); + $this->assertTrue(Arr::arrayable(new FriendsOfHyperf\Tests\Macros\Stubs\TestTraversableAndJsonSerializableObject())); + + $this->assertFalse(Arr::arrayable(null)); + $this->assertFalse(Arr::arrayable('abc')); + $this->assertFalse(Arr::arrayable(new stdClass())); + $this->assertFalse(Arr::arrayable((object) ['a' => 1, 'b' => 2])); + $this->assertFalse(Arr::arrayable(123)); + $this->assertFalse(Arr::arrayable(12.34)); + $this->assertFalse(Arr::arrayable(true)); + $this->assertFalse(Arr::arrayable(new DateTime())); + $this->assertFalse(Arr::arrayable(static fn () => null)); +}); + test('test getsAString', function () { $test_array = ['string' => 'foo bar', 'integer' => 1234]; @@ -73,6 +93,31 @@ Arr::float($test_array, 'string'); }); +test('test from', function () { + $this->assertSame(['foo' => 'bar'], Arr::from(['foo' => 'bar'])); + $this->assertSame(['foo' => 'bar'], Arr::from((object) ['foo' => 'bar'])); + $this->assertSame(['foo' => 'bar'], Arr::from(new FriendsOfHyperf\Tests\Macros\Stubs\TestArrayableObject())); + $this->assertSame(['foo' => 'bar'], Arr::from(new FriendsOfHyperf\Tests\Macros\Stubs\TestJsonableObject())); + $this->assertSame(['foo' => 'bar'], Arr::from(new FriendsOfHyperf\Tests\Macros\Stubs\TestJsonSerializeObject())); + $this->assertSame(['foo'], Arr::from(new FriendsOfHyperf\Tests\Macros\Stubs\TestJsonSerializeWithScalarValueObject())); + + $this->assertSame(['name' => 'A'], Arr::from(TestEnum::A)); + $this->assertSame(['name' => 'A', 'value' => 1], Arr::from(TestBackedEnum::A)); + $this->assertSame(['name' => 'A', 'value' => 'A'], Arr::from(TestStringBackedEnum::A)); + + $subject = [new stdClass(), new stdClass()]; + $items = new FriendsOfHyperf\Tests\Macros\Stubs\TestTraversableAndJsonSerializableObject($subject); + $this->assertSame($subject, Arr::from($items)); + + $items = new WeakMap(); + $items[$temp = new class {}] = 'bar'; + $this->assertSame(['bar'], Arr::from($items)); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Items cannot be represented by a scalar value.'); + Arr::from(123); +}); + test('test getsABoolean', function () { $test_array = ['string' => 'foo bar', 'boolean' => true]; diff --git a/tests/Macros/Stubs/Common.php b/tests/Macros/Stubs/Common.php new file mode 100644 index 000000000..3a7cdb8dd --- /dev/null +++ b/tests/Macros/Stubs/Common.php @@ -0,0 +1,76 @@ + 'bar']; + } +} + +class TestJsonableObject implements Jsonable +{ + public function __toString(): string + { + return '{"foo":"bar"}'; + } + + public function toJson($options = 0): string + { + return '{"foo":"bar"}'; + } +} + +class TestJsonSerializeObject implements JsonSerializable +{ + public function jsonSerialize(): array + { + return ['foo' => 'bar']; + } +} + +class TestJsonSerializeWithScalarValueObject implements JsonSerializable +{ + public function jsonSerialize(): string + { + return 'foo'; + } +} + +class TestTraversableAndJsonSerializableObject implements IteratorAggregate, JsonSerializable +{ + public $items; + + public function __construct($items = []) + { + $this->items = $items; + } + + public function getIterator(): Traversable + { + return new ArrayIterator($this->items); + } + + public function jsonSerialize(): array + { + return json_decode(json_encode($this->items), true); + } +} From b4be761950617a933642dc9893e841645ff03f77 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 13 May 2025 12:10:26 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(ArrMixin):=20=E4=BF=AE=E5=A4=8D=20Jsona?= =?UTF-8?q?ble=20=E6=8E=A5=E5=8F=A3=E7=9A=84=E5=A4=84=E7=90=86=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E4=BD=BF=E7=94=A8=20=5F=5FtoString()=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E6=9B=BF=E4=BB=A3=20toJson()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/macros/src/ArrMixin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros/src/ArrMixin.php b/src/macros/src/ArrMixin.php index 9b398bf8c..5da4135ef 100644 --- a/src/macros/src/ArrMixin.php +++ b/src/macros/src/ArrMixin.php @@ -94,7 +94,7 @@ public function from() $items instanceof Arrayable => $items->toArray(), $items instanceof WeakMap => iterator_to_array($items, false), $items instanceof Traversable => iterator_to_array($items), - $items instanceof Jsonable => json_decode($items->toJson(), true), + $items instanceof Jsonable => json_decode($items->__toString(), true), $items instanceof JsonSerializable => (array) $items->jsonSerialize(), is_object($items) => (array) $items, default => throw new InvalidArgumentException('Items cannot be represented by a scalar value.'),