當心 Collection 的 slice 方法,它會偷偷修改你的陣列

allencao發表於2020-02-26

slice 的問題

在一次介面輸出時,使用了slice的方法,結果導致返回的 json 陣列變成了物件。
檢視 slice 原始碼:

    /**
     * Slice the underlying collection array.
     *
     * @param  int  $offset
     * @param  int  $length
     * @return static
     */
    public function slice($offset, $length = null)
    {
        return new static(array_slice($this->items, $offset, $length, true));
    }

請注意到 array_slice 的第四個引數傳了 true,此引數為 preserve_keys,預設為 false。array_slice 預設會重新排序並重置陣列的數字索引,設定為 true 則儲存原 key。

php 陣列預設是索引陣列,有預設的自增數字 key,一旦陣列key被修改很大可能變成關聯陣列,此時不再擁有自增數字 key。

因此 array_slice 傳入索引陣列,並且start不從0開始,preserve_keys=true,則返回關聯陣列。

索引陣列轉為json後是陣列,而關聯陣列轉為json後是物件。

php -a
php > $a = [1,2,3,4,5,6];
php > $e = array_slice($a, 1, 4, true);
php > echo json_encode($e);
{"1":2,"2":3,"3":4,"4":5}
php > $e = array_slice($a, 0, 4, true);
php > echo json_encode($e);
[1,2,3,4]
php > $e = array_slice($a, 1,4);
php > echo json_encode($e);
[2,3,4,5]

要小心類似的 array 函式還有很多,例如 array_filter。

解決辦法

array_values 可以將任何陣列轉變為索引陣列,但要小心會拋棄原來的 key。
在 Laravel 的Collection 中可以使用 values 方法:

$models = Model::where()->get();
$models->slice(1,3)->values(); //返回索引陣列
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章