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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 15:18:05