2013-01-20 119 views
8

创建无法在PHP中更改的对象是一个好主意吗?PHP中的不可变对象?

例如一个具有setter方法的日期对象,但它们将始终返回对象的新实例(具有修改日期)。

这些对象是否会让其他使用该类的人感到困惑,因为在PHP中,您通常期望对象发生更改?

$obj = new Object(2); 

$x = $obj->add(5); // 7 
$y = $obj->add(2); // 4 
+0

评论你看到具有要这样做类什么好处?我可能会认为一个更好的方法是简单地否定* settability *(是的,我做了这个),你不想改变属性,迫使它们根据需要创建一个新的实例。编辑:是的,什么ThiefMaster说:) –

+0

http:// stackoverflow。com/questions/7317037/php-immutable-public-member-fields 这个例子可以帮助你下载 –

回答

5

一个不可变的对象在初始创建后不能被修改,所以setter方法没有意义,因为它违背了基本原则。

您可以通过操作类成员可见性并重写magic __set()方法来实现一些变通方法来模拟PHP中的不变性,但它不能保证不可变,因为不变性不是该语言的一个功能。我相信有人曾经写过一个扩展,以便在PHP中提供不可变的值类型,尽管如此,您可以通过它获得Google的支持。

+2

PHP RFC:不可变类和属性https://wiki.php.net/rfc/immutability –

+0

关于“有setter方法没有意义”:一个方法'add'(就像问题中提到的那样)可能有意义通过返回具有修改状态的新对象来创建不可变对象。 –

17

不可变对象没有setter方法。期。

每个人都会希望setXyz()方法具有void返回类型(或者在松散类型的语言中不返回任何内容)。如果你将setter方法添加到你的不可变对象中,它将会把人们搞糊涂,并导致丑陋的错误。

+1

以及它们不会像set()那样被调用,但我不知道如何调用它们。 addetter方法? :) – Elfy

+0

尽管这些“所有人”中的某些人不会惊讶地接收到setter的对象的实例,以允许方法链接;-) –

+4

@Elfy将它们称为“with”方法。 '$ obj-> withMyProp($ x)'返回一个新的实例*,其中*“MyProp”设置为'$ x'。 – mpen

8

在我看来,对象应该是不可变的值对象。除此之外,除非您在整个应用程序中共享对象,否则它没有多大优势。

这里有一些错误的答案,一个不可改变的对象可以有setter。以下是PHP中不可变对象的一些实现。

示例#1。

class ImmutableValueObject 
{ 
    private $val1; 
    private $val2; 

    public function __construct($val1, $val2) 
    { 
     $this->val1 = $val1; 
     $this->val2 = $val2; 
    } 

    public function getVal1() 
    { 
     return $this->val1; 
    } 

    public function getVal2() 
    { 
     return $this->val2; 
    } 
} 

正如你可以看到一旦实例化你不能改变任何值。

实施例2:与setters

class ImmutableValueObject 
{ 
    private $val1; 
    private $val2; 

    public function __construct($val1, $val2) 
    { 
     $this->val1 = $val1; 
     $this->val2 = $val2; 
    } 

    public function getVal1() 
    { 
     return $this->val1; 
    } 

    public function withVal1($val1) 
    { 
     $copy = clone $this; 
     $copy->val1 = $val1; 

     return $copy; // here's the trick: you return a new instance! 
    } 

    public function getVal2() 
    { 
     return $this->val2; 
    } 

    public function withVal2($val2) 
    { 
     $copy = clone $this; 
     $copy->val2 = $val2; 

     return $copy; 
    } 
} 

有几个实现可能的,并且这绝不是排他性列表。请记住,通过Reflection,总有一种方法可以在PHP中解决这个问题,所以不变性在您的脑海中始终是最重要的!

将不可变对象作为最终对象也是很好的做法。

编辑:

  • 改变setX的用于withX
  • 增加了有关最终
+0

应该'返回$ this;'实际返回'$ copy'? –

+0

修正了错误,谢谢那 –

+0

“在计算机科学中,增变器方法是一种用来控制变量变化的方法,它们也被广泛称为setter方法”.__不可变对象不能有setters__。他的方法不会改变对象的内部状态。他们只是创建一个新的实例。这是一个很大的不同。 –