diff --git a/src/Util.php b/src/Util.php index 072fae6..18c5b33 100644 --- a/src/Util.php +++ b/src/Util.php @@ -14,4 +14,12 @@ public static function normalizeIndex(int $index, int $containerLength, bool $th } return $index < 0 ? $containerLength + $index : $index; } + + public static function isArraySequential(array $source): bool + { + if (!function_exists('array_is_list')) { + return array_keys($source) === range(0, count($source) - 1); + } + return array_is_list($source); + } } diff --git a/src/Views/ArrayView.php b/src/Views/ArrayView.php index 9a993fa..d1ed7b4 100644 --- a/src/Views/ArrayView.php +++ b/src/Views/ArrayView.php @@ -9,6 +9,7 @@ use Smoren\ArrayView\Exceptions\LengthError; use Smoren\ArrayView\Exceptions\NotSupportedError; use Smoren\ArrayView\Exceptions\ReadonlyError; +use Smoren\ArrayView\Exceptions\ValueError; use Smoren\ArrayView\Interfaces\ArraySelectorInterface; use Smoren\ArrayView\Interfaces\ArrayViewInterface; use Smoren\ArrayView\Selectors\MaskSelector; @@ -57,6 +58,10 @@ public static function toView(&$source, ?bool $readonly = null): ArrayView */ public function __construct(&$source, ?bool $readonly = null) { + if (is_array($source) && !Util::isArraySequential($source)) { + throw new ValueError('Cannot create view for non-sequential array.'); + } + $this->source = &$source; $this->readonly = $readonly ?? (($source instanceof ArrayViewInterface) ? $source->isReadonly() : false); $this->parentView = ($source instanceof ArrayViewInterface) ? $source : null; diff --git a/tests/unit/ArrayView/NonSequentialErrorTest.php b/tests/unit/ArrayView/NonSequentialErrorTest.php new file mode 100644 index 0000000..2128776 --- /dev/null +++ b/tests/unit/ArrayView/NonSequentialErrorTest.php @@ -0,0 +1,60 @@ +expectException(ValueError::class); + ArrayView::toView($nonSequentialArray); + } + + public function dataProviderForNonSequentialError(): array + { + return [ + [fn () => ['test' => 1]], + [fn () => [1 => 1]], + [fn () => [0 => 1, 2 => 2]], + [fn () => [0 => 1, -1 => 2]], + [fn () => [0 => 1, 'a' => 2]], + [static function () { + $array = [1, 2, 3, 4, 5]; + unset($array[0]); + return $array; + }], + [static function () { + $array = [1, 2, 3, 4, 5]; + unset($array[1]); + return $array; + }], + [static function () { + $array = [1, 2, 3, 4, 5]; + $array[6] = 111; + return $array; + }], + [static function () { + $array = [1, 2, 3, 4, 5]; + $array[-1] = 111; + return $array; + }], + [static function () { + $array = [1, 2, 3, 4, 5]; + $array[-2] = 111; + return $array; + }], + [static function () { + $array = [1, 2, 3, 4, 5]; + $array['test'] = 111; + return $array; + }], + ]; + } +}