这是使用 php 7 个断言的 Class 不变性的有效示例吗?
Is this a valid example of Class invariances using php 7 asserts?
我正在尝试更好地理解里氏原理使用的 Class 不变性。
我知道某些语言 like D have native support to invariant,但是,在 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 的 Class 继承不变性违规的有效示例吗?
- GoodPerson 是 Liskov 的 Classe 不变性的有效示例吗?
我可以使用断言创建合约吗?
没有
- 断言应仅用作调试功能
- 断言不应用于输入参数检查等正常运行时操作
BadPerson 是 Liskov 的 Class 继承不变性违规的有效示例吗?
是
Preconditions cannot be strengthened in a subtype.
但是你的代码没有任何意义
首先,只有在您尝试设置或获取动态 属性 时才会调用您的 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
并将检查放在基础 class 构造函数中。为什么?因为您的属性是 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 不变性的有效示例吗?
是
我正在尝试更好地理解里氏原理使用的 Class 不变性。
我知道某些语言 like D have native support to invariant,但是,在 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 的 Class 继承不变性违规的有效示例吗?
- GoodPerson 是 Liskov 的 Classe 不变性的有效示例吗?
我可以使用断言创建合约吗?
没有
- 断言应仅用作调试功能
- 断言不应用于输入参数检查等正常运行时操作
BadPerson 是 Liskov 的 Class 继承不变性违规的有效示例吗?
是
Preconditions cannot be strengthened in a subtype.
但是你的代码没有任何意义
首先,只有在您尝试设置或获取动态 属性 时才会调用您的 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
并将检查放在基础 class 构造函数中。为什么?因为您的属性是 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 不变性的有效示例吗?
是