这是使用 php 7 断言的类不变性的有效示例吗?



我试图最好地理解Liskov原理使用的类不变性。

我知道像 D 这样的语言对不变性有原生支持,但是,在 PHP 中使用断言,我尝试组合魔术方法并断言:

<?php
class Person {
protected string $name;
protected string $nickName;
protected function testContract(){
assert(($this->name != $this->nickName));
}
public function __construct(string $name, string $nickName){
$this->name = $name;
$this->nickName = $nickName;
}
public function __set($name, $value){
$this->testContract();
$this->$name = $value;
}
public function __get($name){
$this->testContract();
return $this->$name;
}
}
class GoodPerson extends Person {
public function getFullName(){
return $this->name." ".$this->nickName. "!!!";
}
}
class BadPerson extends Person {
protected function testContract(){
assert(($this->name != ""));
}
}
$gp = new GoodPerson("João", "Joãozinho");
echo $gp->nickName;
echo $gp->getFullName();
$bp = new BadPerson("João", "João");
echo $bp->nickName;
  • 我可以使用断言来创建合约吗?
  • BadPerson 是 Liskov 的继承类不变性违规的有效例子吗?
  • GoodPerson是Liskov的Classe In不变性的有效例子吗?

我可以使用断言来创建合约吗?

来自 PHP 文档

  • 断言应仅用作调试功能
  • 断言不应用于正常的运行时操作,如输入参数检查

BadPerson 是 Liskov 的继承类不变性违规的有效例子吗?

是的

在子类型中不能加强前提条件。

但是你的代码没有任何意义

首先,只有当您尝试设置或获取动态属性时,才会调用您的testContract方法,它将检查您通过constructor传递的参数

public function __set($name, $value){
$this->testContract();
$this->$name = $value;
}

在这里,您基本上测试构造函数参数,但在魔术方法(__set(

因此,为了使该检查有效,您需要像这样调用__set

$gp = new BadPerson("João", "Joãozinho");
$gp->name = ''; // This line here invokes __set magic method

因此,您真正需要做的是摆脱testContract并将检查放在基类构造函数中。为什么?因为属性是protected的,所以客户端设置它们的唯一机会是通过构造函数

public function __construct(string $name, string $nickName){
if ($name != "" && $name != $nickName)
throw new Exception('Name must not be empty and must not equal Nickname');
$this->name = $name;
$this->nickName = $nickName;
}

GoodPerson是Liskov的Classe In不变性的有效例子吗?

是的

相关内容

  • 没有找到相关文章

最新更新