dna*_*irl 5 php liskov-substitution-principle
我在升级之前在PHP5.4上测试我现有的代码.我发现以下代码不再有效,因为PHP已经收紧了它的继承模型.由于这种紧缩,我一直在阅读有关SOLID,特别是Liskov的替代原则(我是一名自学成才的程序员),这样我就可以改进我的代码,而不会受到未来"拧紧"的影响.
interface IComparable {
public function equals(self $other);
}
class A implements IComparable{
protected $var;
public function __construct($v){
$this->var=$v;
}
public function equals(self $other){
return ($this->var == $other->var) ? 'equal' : 'different';
}
}
$a1= new A(7);
$a2= new A(5);
$a3= new A(5);
echo $a1->equals($a2),"\n";
echo $a2->equals($a3),"\n";
Run Code Online (Sandbox Code Playgroud)
PHP致命错误:A :: equals()的声明必须与IComparable :: equals兼容(IComparable $ other)
如果我以这种方式编写代码,我可以避免php5.4错误:
interface IComparable {
public function equals($other);
}
class A implements IComparable{
protected $var;
public function __construct($v){
$this->var=$v;
}
public function equals($other){
if(get_class($other) != get_class($this)) return false;
return ($this->var == $other->var) ? 'equal' : 'different';
}
}
Run Code Online (Sandbox Code Playgroud)
但修正是否符合Liskov的替换原则,因为该函数显然不接受任何参数类型?如果没有,我怎么能编写一个可以执行我需要的可继承功能 - 比较相同类型的2个对象 - 并遵守良好的OOD原则?
首先:PHP 5.3的行为是一个bug,所以你不能用它作为判断任何其他方法的标准。
展望未来,您的 5.3 版本代码中已经违反了 LSP。考虑:
interface IComparable {
public function equals(self $other);
}
Run Code Online (Sandbox Code Playgroud)
这表示“任何人都IComparable可以将自己与任何其他人进行比较IComparable”(比较的语义对于讨论并不重要)。thenclass A继续违反 LSP,因为它不支持与任何实例进行比较IComparable——仅与那些恰好是A实例的实例进行比较。
PHP 5.4 版本并没有违反 LSP,因为新版本IComparable说“我可以将自己与任何其他对象进行比较”,这也正是这样做class A的。
如果您的意图是保留 5.3 版本合同,那么IComparable应该阅读
interface IComparable {
public function equals(IComparable $other);
}
Run Code Online (Sandbox Code Playgroud)
当然class A会使用相同的签名。这不会违反 LSP ,并且可以在两个版本中正常工作。
如果您的意图是声明“IComparable实例可以将自身与相同类型的实例进行比较,无论是什么”,那么您就不走运了,因为该契约无法使用方法签名和类型提示来表达。
更新:事实证明,您的意图是声明“此类的实例可以相互比较”,IComparable其目的只是为了迫使您不要忘记这样做。
在这种情况下,解决方案就是简单地忘记并在 的签名中IComparable使用。您确实会失去编译器的强迫您记住定义必要方法的能力,但恕我直言,这是一个小问题(特别是因为接口仅声明一个方法)。selfA::compare()