这不是一个关于实际代码的问题,只是供讨论。在我看来,能够将对象作为常量引用传递是很好的。
$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()
修改,但是如果我想有一个单一的对象实例呢?
我想到的是一个包装器类(代码:https://gist.github.com/904897)使用__set()
和__get()
魔术方法,在每个__set()
调用上抛出异常。它允许我这样做:
class CoordinateConst extends stdConst {};
unsafe_func(new CoordinateConst($c)); // exception: can not be modified!
我不喜欢的解决方案是,通过引入CoordinateConst,我必须删除坐标类型提示。但是,如果我扩展坐标类,__set()
方法不调用可见属性。
您的解决方案有效地防止了公共属性被写入。如果坐标有如下函数,那么它就不是常量引用:
public function setX($x) {
$this->x = $x;
}
另一种选择(但需要更多的代码,这取决于您想要执行的频率)是创建类的只读版本。
我知道在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
,那么也许你只能发送所需的数据。这当然取决于它需要多少坐标数据。
。
unsafe_func($coordinate->getRequiredData());
但是如果你需要大量的数据,这将成为一个麻烦