我正在阅读:https://www.simonholywell.com/post/2017/03/php-and-immutability/
并举了一个例子,因此它是完美的不可变类:
class Immutable {
private $skater, $trick;
public function __construct($skater, $trick) {
$this->skater = $skater;
$this->trick = $trick;
}
public function getSkater() {
return $this->skater;
}
public function getTrick() {
return $this->trick;
}
}
到目前为止,一切都很好。但并非易碎,如文章所述:
$x = new Immutable('Hawk', 'Frontside 540');
$x->__construct('Song', 'Darkslide');
它是这样重写的:
class Immutable {
private $skater, $trick;
private $mutable = true;
public function __construct($skater, $trick) {
if (false === $this->mutable) {
throw new \BadMethodCallException('Constructor called twice.');
}
$this->skater = $skater;
$this->trick = $trick;
$this->mutable = false;
}
public function getSkater() {
return $this->skater;
}
public function getTrick() {
return $this->trick;
}
}
但是现在更改mute
值本身会破坏不变性,对吗? :)
答案 0 :(得分:2)
不,这不会,因为仅在构造函数中设置了值,此后再也不会更改。因此,它符合不变性的定义。我将User.Identity.GetUserId<int>().
重命名为$mutable
之类的东西,因为您不能真正使用该属性更改类的可变属性,在我看来,它的名称具有误导性。
但是,在某种程度上,PHP完全不可能实现对象不变性,因为:
不可移植性并不意味着存储在计算机内存中的对象是不可写的。相反,不变性是一种编译时结构,它指示程序员可以通过对象的常规接口执行的操作,不一定表明他们可以绝对执行的操作
(来源:Wikipedia)
由于PHP中没有“编译时”并且$isCreated
属性是在运行时评估的,因此从一开始就似乎违反了这一概念。
在另一个级别上,使用相同的引号,“普通界面”将是您的第一个示例所表示的内容。直接而不是通过$mutable
调用构造函数方法完全超出了任何常规用法。因此,您可以说没有属性设置器的类通过“通过普通接口”的约定已经不可变。
基本上,您是在询问一个学术问题,但尝试解决一个绝对确定的现实问题,实例化后在任何情况下都不能更改对象的属性。但是“不变性”的概念并不适用。
答案 1 :(得分:1)
两者之间基本没有区别
private $mutable = true;
然后在构建时将其更改为false
,然后:
private $skater
,然后将其更改为其他内容(在构建时)。当您不设置初始值时,您的意思是:
private $skater = null;
您可以通过在设置值之前执行var_dump($this->skater)
来方便地进行检查,它会显示null
。因此,实际上,在第一个示例中,您已经将null值更改为其他值。 sandbox那么在构造过程中更改null
与更改false
之间的区别到底是什么?
无论您是否考虑“不可变”都是一个见解。 PHP中唯一不可变的是常量。
答案 2 :(得分:0)
只要您的不可变类仅接受原始数据类型(例如字符串,int,float,bool),则您的类应该是相当不可变的。但是一旦传递了对象或流,它就不会一成不变。即使有了Value Objects,要获得真正的不可变对象也不容易。