PHP中的不可变对象?

Elf*_*lfy 12 php class immutability

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

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

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

$obj = new Object(2);

$x = $obj->add(5); // 7
$y = $obj->add(2); // 4
Run Code Online (Sandbox Code Playgroud)

Thi*_*ter 24

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

每个人都期望一个setXyz()方法具有void返回类型(或者在松散类型的语言中不返回任何内容).如果你确实为你的不可变对象添加了setter方法,那么它会让人感到困惑并导致丑陋的bug.

  • @Elfy称他们为"with"方法.`$ obj-> withMyProp($ x)`返回一个新实例*,*"MyProp"设置为`$ x`. (8认同)
  • 尽管“每个人”中的一些人在收到 setter 对象的实例时不会感到惊讶,以允许方法链接;-) (2认同)

Thé*_*héo 11

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

这里有一些错误的答案,一个不可变的对象可以有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;
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所见,一旦实例化,您就无法更改任何值.

例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;
    }
}
Run Code Online (Sandbox Code Playgroud)

有几种实现可能,这绝不是排他性列表.请记住,使用Reflection总有一种方法可以在PHP中解决这个问题,所以最终你的不变性就在你的脑海中!

将不可变对象作为最终对象通常也是一种好习惯.

编辑:

  • 更改了withX的setX
  • 添加了关于最终的评论

  • 使用'setX'或'changeX'名称也是一个坏主意.这些名称强烈暗示对象的内部状态将发生变化.这不是真的.更好的做法是使用例如'withX'. (4认同)
  • “在计算机科学中,mutator 方法是一种用于控制变量更改的方法。它们也被广泛称为 setter 方法”。__不可变对象不能有 setter__。他的方法不会改变对象的内部状态。__他们只是创建了一个新实例__。这是一个很大的不同。 (2认同)

pip*_*ull 5

不可变对象在初始创建后不能更改,因此使用setter方法没有意义,因为它违背了基本原则.

您可以通过操纵类成员可见性并覆盖magic __set()方法来实现一些变通方法来模拟PHP中的不变性,但不能保证不可变,因为不变性不是语言的一个特性.我相信有人曾经写过一个扩展来在PHP中提供一个不可变的值类型,所以你可以谷歌为此.

  • PHP RFC:不可变类和属性https://wiki.php.net/rfc/immutability (6认同)
  • 关于“设置方法没有意义”:通过返回具有修改状态的新对象,方法`add`(如问题中提到的方法)可能在不可变对象中有意义。 (3认同)