diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index c14465c6b3fa..106e5316f956 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -4,13 +4,43 @@ use ArgumentCountError; use ArrayAccess; +use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Contracts\Support\Jsonable; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; +use JsonSerializable; +use Traversable; +use UnitEnum; +use WeakMap; class Arr { use Macroable; + /** + * Get the underlying array of items from the given argument. + * + * @param mixed $items + * @return array + */ + public static function from($items) + { + if (is_array($items)) { + return $items; + } + + return match (true) { + $items instanceof WeakMap => throw new InvalidArgumentException('Arrays cannot be extracted from instances of WeakMap.'), + $items instanceof Enumerable => $items->all(), + $items instanceof Arrayable => $items->toArray(), + $items instanceof Traversable => iterator_to_array($items), + $items instanceof Jsonable => json_decode($items->toJson(), true), + $items instanceof JsonSerializable => (array) $items->jsonSerialize(), + $items instanceof UnitEnum => [$items], + default => (array) $items, + }; + } + /** * Determine whether the given value is array accessible. * diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index dd4d5ab292a2..4032b6696d6f 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -11,13 +11,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Enumerable; use Illuminate\Support\HigherOrderCollectionProxy; -use InvalidArgumentException; use JsonSerializable; use Symfony\Component\VarDumper\VarDumper; -use Traversable; use UnexpectedValueException; -use UnitEnum; -use WeakMap; /** * @template TKey of array-key @@ -1022,20 +1018,7 @@ public function __get($key) */ protected function getArrayableItems($items) { - if (is_array($items)) { - return $items; - } - - return match (true) { - $items instanceof WeakMap => throw new InvalidArgumentException('Collections can not be created using instances of WeakMap.'), - $items instanceof Enumerable => $items->all(), - $items instanceof Arrayable => $items->toArray(), - $items instanceof Traversable => iterator_to_array($items), - $items instanceof Jsonable => json_decode($items->toJson(), true), - $items instanceof JsonSerializable => (array) $items->jsonSerialize(), - $items instanceof UnitEnum => [$items], - default => (array) $items, - }; + return Arr::from($items); } /** diff --git a/tests/Support/Common.php b/tests/Support/Common.php new file mode 100644 index 000000000000..2a5c5b333a21 --- /dev/null +++ b/tests/Support/Common.php @@ -0,0 +1,62 @@ + 'bar']; + } +} + +class TestJsonableObject implements Jsonable +{ + public function toJson($options = 0) + { + 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); + } +} diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 2c5f6c224e67..a93689d9b4e8 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -10,8 +10,22 @@ use PHPUnit\Framework\TestCase; use stdClass; +include_once 'Common.php'; + class SupportArrTest extends TestCase { + public function testFrom() + { + $this->assertSame(['foo' => 'bar'], Arr::from(new TestArrayableObject)); + $this->assertSame(['foo' => 'bar'], Arr::from(new TestJsonableObject)); + $this->assertSame(['foo' => 'bar'], Arr::from(new TestJsonSerializeObject)); + $this->assertSame(['foo'], Arr::from(new TestJsonSerializeWithScalarValueObject)); + + $subject = [new stdClass, new stdClass]; + $items = new TestTraversableAndJsonSerializableObject($subject); + $this->assertSame($subject, Arr::from($items)); + } + public function testAccessible() { $this->assertTrue(Arr::accessible([])); diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index dc82699b9329..2e6532111688 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -8,7 +8,6 @@ use CachingIterator; use Exception; use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Contracts\Support\Jsonable; use Illuminate\Support\Collection; use Illuminate\Support\HtmlString; use Illuminate\Support\ItemNotFoundException; @@ -16,7 +15,6 @@ use Illuminate\Support\MultipleItemsFoundException; use Illuminate\Support\Str; use InvalidArgumentException; -use IteratorAggregate; use JsonSerializable; use Mockery as m; use PHPUnit\Framework\Attributes\DataProvider; @@ -24,10 +22,10 @@ use ReflectionClass; use stdClass; use Symfony\Component\VarDumper\VarDumper; -use Traversable; use UnexpectedValueException; use WeakMap; +include_once 'Common.php'; include_once 'Enums.php'; class SupportCollectionTest extends TestCase @@ -5816,30 +5814,6 @@ public function offsetUnset($offset): void } } -class TestArrayableObject implements Arrayable -{ - public function toArray() - { - return ['foo' => 'bar']; - } -} - -class TestJsonableObject implements Jsonable -{ - public function toJson($options = 0) - { - return '{"foo":"bar"}'; - } -} - -class TestJsonSerializeObject implements JsonSerializable -{ - public function jsonSerialize(): array - { - return ['foo' => 'bar']; - } -} - class TestJsonSerializeToStringObject implements JsonSerializable { public function jsonSerialize(): string @@ -5848,34 +5822,6 @@ public function jsonSerialize(): string } } -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); - } -} - class TestCollectionMapIntoObject { public $value;