我在升级之前在PHP5.4上测试我现有的代码。我发现以下代码不再有效,因为PHP已经收紧了它的继承模型。由于这种紧缩,我一直在阅读SOLID,特别是Liskov's substitution principle(我是一名自学成才的程序员),以便我可以改进我的代码,而不会受到未来“紧张”的影响。< / p>
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";
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';
}
}
但是修复是否符合Liskov的替换原则,因为该函数显然不接受任何参数类型?如果没有,我怎么能编写一个可以执行我需要的可继承函数 - 比较相同类型的2个对象 - 并遵守良好的OOD原则?
答案 0 :(得分:3)
首先:PHP 5.3的行为是bug,所以你不能用它来判断任何其他方法。
展望未来,您的5.3版本代码中已经违反了LSP。考虑:
interface IComparable {
public function equals(self $other);
}
这表示“任何IComparable
可以将自己与任何其他IComparable
进行比较”(比较的语义对于讨论并不重要)。 class A
然后继续违反LSP,因为它不支持与任何IComparable
的比较 - 只是那些碰巧是A
个实例。
PHP 5.4版本没有违反LSP,因为IComparable
的新版本说“我可以将自己与任何其他对象进行比较”,这正是class A
所做的。
如果您的意图是保留5.3版本合同,那么IComparable
应该阅读
interface IComparable {
public function equals(IComparable $other);
}
和class A
当然会使用相同的签名。这不会违反LSP 和,它可以在两个版本中正常工作。
如果您的意图是声明“IComparable
实例可以将自己与相同类型的实例进行比较,无论是什么”,那么您运气不好,因为此合同无法使用方法签名和类型提示来表达
更新:原来你的意图是声明“这个类的实例可以自我比较”而IComparable
只是为了强迫你不要忘记这样做。
在这种情况下,解决方案就是忘记IComparable
并在self
的签名中使用A::compare()
。你确实失去了编译器,迫使你记住定义必要的方法,但这是一个小问题(特别是因为接口只声明了一个方法)。
答案 1 :(得分:0)
我认为您的界面和类需要按如下方式编写才能更加健壮:
interface IComparable
{
/**
* @return boolean
*/
public function equals(IComparable $other);
/**
* @return mixed
*/
public function getValue();
}
class A implements IComparable{
protected $var;
public function __construct($v){
$this->var=$v;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->var;
}
/**
* @param IComparable $other
* @return boolean
*/
public function equals(IComparable $other)
{
return ( $this->getValue() === $other->getValue() );
}
}
php中的self关键字指的是当前类,我建议不要将它用于类型提示参数,因为它不太清楚方法参数是什么。
关于你的equals和Liskov Substitution的实施,这是你触及的一个有趣的主题。我会看到here有关平等和Liskov的有趣讨论。