Featured image of post 对于数组索引变化+引用参数共同导致出现的一个 bug

对于数组索引变化+引用参数共同导致出现的一个 bug

PHP 数组固然好用,但也要小心坑

今天, 我们老板在群里发出了一个bug, 然后我打开了项目, 进行本地复现. 过了一段时间. 终于复现了这个问题


大致代码如下

  1. 以下代码会导致移除第一项的时候, 把一个Collection数组转化成对象(JSON数据)
     protected function transformJson($items)
     {
         return Collection::make($items)
-            ->values()
             ->where('_remove_', '0')
+            ->values()
             ->map(fn($item) => Arr::except($item, '_remove_'))
             ->toJson();
  1. API获取数据的时候, 由于有这样的一段代码. 并且是函数的调用
public function index()
{
    // $json={"1":{"id": 2}}
    $data = Collection::make($json);
    // 由于进行了 filter, 所以得到了 0 的 index
    $index = $this->getRandomAd($data, [1]);

    // 因为 Collection 中只有 1 的 key, 所以返回了 null
    return $data->get($index);
}

protected function getRandomAd(Collection $data, $notIn=[])
{
    $index = -1;

    if (count($notIn) > 0) {
        $data = $data->filter(fn($item) => !in_array($item['id'], $notIn))->values();
    }

    // 由于上面进行了 filter, 导致这个`Collection`转变成了一个数组,index 从 0 开始.
    foreach ($data as $index => $item) {

        if ($item['id']) {
            return $index;
        }
    }

    // 这里返回了`Collection`的随机到的索引
    return $index;
}

  • getRandomAd这个方法的的排重filter是因为项目后期加了一个逻辑, 后面没想到是它来触发这个bug.
  • Collection的确是一个对象,PHP中对象作为参数传递也确实是一个引用. 但是由于直接的赋值,而不是在对象上修改数据, 导致外部的引用没有修改成功.(如果这时候使用transform而不是map就可以避免这个bug了)