You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP自定义Session处理类如何实现多维数组的合并更新?

自定义Session处理器多维数组更新问题解决方案

原问题场景与代码

我为脚本编写了自定义Session处理器,通过数据库层存储和管理Session数据,数据以JSON对象形式存储,读写时进行编解码。当前set_data方法代码如下:

private $data = array();
// Set data for the session handler. If you pass a variable
// as null, it will be deleted from the array.
function set_data($name, $data) {
    // Check if the field exists already or not
    if (array_key_exists($name, $this->data)) {
        // Check if the data being added is an array or not
        if (is_array($this->data[$name]) && is_array($data)) {
            $this->data[$name] = array_merge($this->data[$name], array_intersect_key($data, $this->data[$name]));
        } else {
            $this->data[$name] = $data;
        }
    } else {
        $this->data[$name] = $data;
    }
    // Remove NULL entries from the data set
    $this->data = array_filter($this->data, function($var){return $var !== null;});
    $database->update("sessions", json_encode($this->data), $this->session_id);
}

问题现象

执行以下代码后:

$session->set_data("cart", array("items" => array(1,2,3)));
$session->set_data("cart", array("categories" => array("a","b","c")));

cart数组仅保留items子项,无法新增categories子项,期望cart同时包含两个子数组。原代码仅支持覆盖、替换或删除子项,无法在父级数组下新增子项。

问题根源

原代码使用array_merge结合array_intersect_key的逻辑,只会合并原数组中已存在的键,新传入的键(如categories)会被过滤掉,完全不支持多维数组的新增子项需求;同时没有处理深层子数组的合并逻辑。

修改方案:递归实现多维数组合并

需要新增一个递归数组合并函数,当父项和新数据均为数组时,递归合并所有子项(包括新增键),同时保留原有的NULL删除逻辑。

修改后的完整代码

private $data = array();

// 递归合并数组:保留原数组所有键,新增新数组的键,子数组递归合并
private function recursive_array_merge($original, $new) {
    foreach ($new as $key => $value) {
        if (isset($original[$key]) && is_array($original[$key]) && is_array($value)) {
            // 子项均为数组,递归合并
            $original[$key] = $this->recursive_array_merge($original[$key], $value);
        } else {
            // 原键不存在或非数组,直接赋值(支持覆盖/新增)
            $original[$key] = $value;
        }
    }
    return $original;
}

// Set data for the session handler. If you pass a variable
// as null, it will be deleted from the array.
function set_data($name, $data) {
    if (array_key_exists($name, $this->data)) {
        if (is_array($this->data[$name]) && is_array($data)) {
            // 替换原逻辑为递归合并
            $this->data[$name] = $this->recursive_array_merge($this->data[$name], $data);
        } else {
            $this->data[$name] = $data;
        }
    } else {
        $this->data[$name] = $data;
    }

    // 移除顶层NULL项
    $this->data = array_filter($this->data, function($var){
        return $var !== null;
    });

    // 更新数据库
    $database->update("sessions", json_encode($this->data), $this->session_id);
}

深层子项处理说明

  1. 新增/合并深层子项:执行$session->set_data("cart", array("items" => array(4,5)));时,会递归合并cart->items数组,最终items变为[1,2,3,4,5];若需要直接替换而非合并,只需传入非数组值(如$session->set_data("cart", array("items" => array(4,5)));是合并,$session->set_data("cart", array("items" => "new list"));是替换)。
  2. 删除深层子项:传递对应键为null即可,比如$session->set_data("cart", array("items" => null));,后续的array_filter会移除cart下的items键。
  3. 自动清理空父数组(可选):如果需要在子项被删除后自动移除空的父数组,可以新增递归过滤函数:
// 递归过滤空数组(可选)
private function recursive_filter_empty($array) {
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $array[$key] = $this->recursive_filter_empty($value);
            if (empty($array[$key])) {
                unset($array[$key]);
            }
        }
    }
    return $array;
}

然后在array_filter之后调用:

$this->data = $this->recursive_filter_empty($this->data);

这样当cart因子项被删除变为空数组时,会被自动从顶层数据中移除。

内容的提问来源于stack exchange,提问作者Kaboom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 02:25:32