我认为“......必须与...兼容”才能执行Liskov替换原则。但我不确定LSP是什么意思?
我有这样的代码:
class General
{
public static function create(): General
{
return new static;
}
public function doSomething()
{
echo get_class($this) . ' speaking!' . PHP_EOL;
}
}
class Specific extends General
{
public static function create(): Specific
{
return parent::create();
}
}
function doSomething(General $object)
{
$object->doSomething();
}
doSomething(General::create());
doSomething(Specific::create());
产生:
PHP致命错误:声明特定:: create():具体必须与General :: create()兼容:General in ...
LSP通常被引用为:
使用指针或对基类的引用的函数必须能够 在不知情的情况下使用派生类的对象。
据我所知,这并没有违反。那么这里有什么问题?是否有一些与LSP无关的特殊限制?这是PHP中的错误吗?在不知情的情况下我做错了吗?
更新:我找到了这个帖子(Parameter type covariance in specializations)。我理解并完全同意那里的例子违反了LSP。但我的情况有所不同(事实上相反)。
答案 0 :(得分:1)
http://php.net/manual/en/functions.returning-values.php
覆盖父方法时,子方法必须匹配父方法上的任何返回类型声明。如果父级没有定义返回类型,则子方法可以这样做。
您的Specific::create
函数应指明General
返回类型。
否则,为Specific::create
编写的代码在运行General::create
时可能会中断,因为它会收到不同的类。
答案 1 :(得分:0)
LSP说明方法参数必须是协变量,而返回值必须是协变量。
在您的情况下,您有满足LSP的协变返回类型。
问题出在PHP本身。此限制与LSP无关,只是早期版本的PHP尚未实现。
从PHP 7.2(7.4)开始,它现在完全支持LSP,即参数相反和返回值相关:substring
UPD。。但是您的代码还包含另一个问题:您的\Specific::create()
方法必须返回Specific
的实例(如您在其签名中所声明的那样),但它会尝试返回\General::create()
返回的值表示为General
(并且我们知道General
的实例不是instanceof Specific
)。这是相当误导的。例如。 PhpStorm会警告您:Return value is expected to be 'Specific', 'General' returned
。
但是PHP不会对此引发错误。
可以通过在\General::create()
中添加PhpDoc来解决此问题:
class General
{
/**
* @return static
*/
public static function create(): General
{
return new static;
}