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); }
深层子项处理说明
- 新增/合并深层子项:执行
$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"));是替换)。 - 删除深层子项:传递对应键为
null即可,比如$session->set_data("cart", array("items" => null));,后续的array_filter会移除cart下的items键。 - 自动清理空父数组(可选):如果需要在子项被删除后自动移除空的父数组,可以新增递归过滤函数:
// 递归过滤空数组(可选) 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
相关产品推荐
相关产品推荐

