PHP中实现对象属性/数组深层元素赋值的函数问题求助
PHP中实现对象属性/数组深层元素赋值的函数问题求助
你好呀!当然可以写出这样的深层赋值函数~我先帮你分析下现有setValue函数的问题,再给出修复后的版本:
现有代码的核心问题
- 私有属性访问权限问题:你用匿名函数直接访问对象的私有属性,即便通过
call绑定了$this,但匿名函数不属于类的成员,没有权限访问私有/受保护属性,这会直接导致赋值失败甚至报错。 - 引用处理不当:处理对象时,你没有用引用接收属性值,后续的赋值无法传递到原对象上;另外当中间节点不存在时,没有自动创建对应的结构(数组/对象),导致赋值流程直接中断。
- 闭包语法错误:你的
$getter和$setter闭包后面加了(...),这会直接执行闭包但未传参,属于明显的语法错误。
修复后的完整实现
我们用PHP反射来解决私有属性访问问题,同时优化引用处理和缺失节点的自动创建,下面是完善后的函数:
function setValue(string $name, mixed &$initial, mixed $value): void { $keys = explode('.', $name); $current = &$initial; foreach ($keys as $index => $key) { $isLast = $index === count($keys) - 1; // 处理数组类型 if (is_array($current)) { if ($isLast) { $current[$key] = $value; break; } // 节点不存在时自动创建空数组 if (!isset($current[$key])) { $current[$key] = []; } $current = &$current[$key]; continue; } // 处理对象类型 if (is_object($current)) { $reflection = new ReflectionObject($current); try { $property = $reflection->getProperty($key); $property->setAccessible(true); if ($isLast) { $property->setValue($current, $value); break; } $nextValue = $property->getValue($current); // 节点为空时自动创建空数组(可根据需求改为创建对象) if ($nextValue === null) { $nextValue = []; $property->setValue($current, $nextValue); } $current = &$nextValue; } catch (ReflectionException $e) { // 属性不存在时中断流程,可根据需求自定义处理 break; } continue; } // 既不是数组也不是对象,无法继续深入,中断赋值 break; } } function getValue(string $name, mixed $initial): mixed { $keys = explode('.', $name); $current = $initial; foreach ($keys as $key) { if (is_array($current) && isset($current[$key])) { $current = $current[$key]; } elseif (is_object($current)) { $reflection = new ReflectionObject($current); try { $property = $reflection->getProperty($key); $property->setAccessible(true); $current = $property->getValue($current); } catch (ReflectionException $e) { return null; } } else { return null; } } return $current; }
测试验证
用你提供的测试代码验证,会得到预期结果:
class MyFoo { private MyBar $bar; private array $array; public function setBar(MyBar $bar): static { $this->bar = $bar; return $this; } public function setArray(array $array): static { $this->array = $array; return $this; } } class MyBar { private MyFoo $foo; private array $array; public function setFoo(MyFoo $foo): static { $this->foo = $foo; return $this; } public function setArray(array $array): static { $this->array = $array; return $this; } } $instance = (new MyFoo()) ->setBar( (new MyBar()) ->setFoo( (new MyFoo()) ->setArray( [ 'myBar' => (new MyBar()) ->setArray( [ 'deep' => [ 'myFoo' => (new MyFoo()) ->setBar( (new MyBar()) ->setArray(['test' => 'is Test']) ) ] ] ) ] ) ) ); echo getValue('bar.foo.array.myBar.array.deep.myFoo.bar.array.test', $instance) . PHP_EOL; // 输出:is Test setValue('bar.foo.array.myBar.array.deep.myFoo.bar.array.test', $instance, 'Set Test'); echo getValue('bar.foo.array.myBar.array.deep.myFoo.bar.array.test', $instance) . PHP_EOL; // 输出:Set Test
补充说明
- 用**反射(Reflection)**是PHP中访问非公开属性的标准可靠方式,避免了权限问题。
- 如果需要在中间节点不存在时自动创建对象而非数组,可以扩展
setValue函数,比如传入目标类名来实例化,这可以根据你的实际需求调整。 - 代码中加入了异常处理,避免因属性不存在导致致命错误,你可以根据业务逻辑修改异常处理逻辑。
备注:内容来源于stack exchange,提问作者UKRman
相关产品推荐
相关产品推荐

