PHP中的常量非修改对象引用

时间:2011-04-06 00:40:10

标签: php oop

这不是关于真实代码的问题,只是讨论。在我看来,能够将对象作为常量引用传递会很好。

$c = Coordinate;
unsafe_func($c); // this should be ok
unsafe_func(... constant reference ... $c); // this should fail on write to $c

我知道有一个选项来传递像set(clone $c)这样的对象的克隆,这会保留原$c未被unsafe_func()修改,但如果我想要一个对象实例?

我想出的是使用__set()__get()魔术方法的包装类(代码:https://gist.github.com/904897),在每次__set()调用时抛出异常。它允许我这样做:

class CoordinateConst extends stdConst {};
unsafe_func(new CoordinateConst($c)); // exception: can not be modified!

我不喜欢的解决方案是,通过引入CoordinateConst,我必须删除Coordinate typehints。但是如果我扩展Coordinate类,则不会为可见属性调用__set()方法。

问题:是否有更常见的方法来执行此操作,或者您是否愿意避免使用此类代码(通过传递对象克隆,包装unsafe_func调用或其他内容)?

1 个答案:

答案 0 :(得分:2)

您的解决方案有效地阻止了公共属性的写入。如果坐标具有如下函数,则坐标不会是常量引用:

public function setX($x) {
    $this->x = $x;
}

另一种选择(但更多代码取决于你想要的频率),就是创建类的ReadOnly版本。

我知道在Java和C#中它通常应用于集合。 C#有一个ReadOnlyCollection<T>,它只是一个包装器/代理,就像你在那里做的那样。

所以我解决问题的方法是创建:

class ReadOnlyCoordinate { 
    private $coordinate;

    public function __construct(Coordinate $coordinate) {
        $this->coordinate = $coordinate;
    }

    public function getX() {
        return $this->coordinate->getX();
    }

当然,您可以扩展Coordinate,然后在设置任何属性的函数上抛出异常。


然后查看整个问题,如果您不希望Coordinate成员/ setter暴露给unsafe_func,那么您可能只能发送所需的数据。这当然取决于它需要多少坐标数据。

e.g。

unsafe_func($coordinate->getRequiredData());

但是如果你需要很多数据,那就麻烦了。