PHP可变变量操作数组/对象失效,Twig自定义函数赋值失败
问题分析
你的核心问题有两个:
- 值传递而非引用传递:代码中
$array = $originalArray;是值拷贝,后续修改的是副本,原对象/数组根本没被改动,返回的副本也因为可变变量的逻辑错误没正确赋值。 - 可变变量的动态赋值逻辑不可靠:通过拼接字符串生成变量访问路径的方式,无法正确处理数组与对象混合的嵌套结构,且语法上存在隐患。
解决方案
替换掉可变变量的写法,改用循环遍历键路径的方式,同时处理引用传递(对象默认是引用,数组需要显式引用),兼容数组和公共对象的混合嵌套,还能自动创建不存在的中间节点。
修正后的PHP实现
/** * 向数组/公共对象中精准赋值,替代Twig的merge方法 * * @param array|object $target 要赋值的目标数组或公共访问对象 * @param mixed $value 要设置的值 * @param string ...$keys 嵌套的键路径(前缀array_表示数组键,否则为对象属性) * @return array|object 修改后的目标 */ public function arrayKeyValueSetter($target, $value, ...$keys) { // 处理数组的引用传递,对象默认是引用类型 $current = is_array($target) ? &$target : $target; foreach ($keys as $index => $key) { // 判断当前键是数组键还是对象属性 $isArrayKey = str_starts_with($key, 'array_'); $realKey = $isArrayKey ? substr($key, 6) : $key; // 如果是最后一个键,直接赋值 if ($index === count($keys) - 1) { if ($isArrayKey) { $current[$realKey] = $value; } else { $current->$realKey = $value; } break; } // 自动创建不存在的中间节点 if ($isArrayKey) { if (!isset($current[$realKey]) || !is_array($current[$realKey])) { $current[$realKey] = []; } $current = &$current[$realKey]; } else { if (!isset($current->$realKey) || !is_object($current->$realKey)) { $current->$realKey = new stdClass(); } $current = $current->$realKey; } } return $target; }
关键改进点
- 引用处理:数组使用
&实现引用传递,确保修改的是原数组;对象本身是引用类型,无需额外处理。 - 键路径遍历:通过循环逐个处理嵌套键,避免可变变量的语法陷阱。
- 自动创建中间节点:如果嵌套路径中的某个节点不存在,自动创建数组或空对象,避免报错。
- 灵活参数:使用可变参数
...$keys替代多个固定参数,支持任意深度的嵌套。
Twig调用调整
改用可变参数后,直接按顺序传递键路径即可:
{% if value is defined and value is not null %} {% set form = form|array_key_value_setter(value.id, 'children', 'array_media', 'vars', 'array_contentHasMediaId') %} {% endif %}
验证结果
现在调用dump(form.children.media.vars.contentHasMediaId)会正确输出你设置的value.id值。
内容的提问来源于stack exchange,提问作者Erick Est
相关产品推荐
相关产品推荐

