这不是关于真实代码的问题,只是讨论。在我看来,能够将对象作为常量引用传递会很好。
$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调用或其他内容)?
答案 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());
但是如果你需要很多数据,那就麻烦了。