当前位置: 首页 > 知识库问答 >
问题:

利斯科夫替换原则和PHP接口

傅志文
2023-03-14

以下代码是否直接违反了Liskov替换原则:
子类不应破坏父类的类型定义。

class Baz {}
class Foo extends Baz {}

interface a
{
    public function baz(Baz $baz);
}

class b implements a
{
    public function baz(Foo $foo)
    {
    }
}

结果如下:

致命错误:b::baz(Foo $foo)的声明必须与a::baz(Baz $baz)兼容

共有1个答案

益泰平
2023-03-14

你的例子是非法的,但这并不违反LSP。你的问题是定义一个接口,并期望在实现它的时候遵守契约。

重要的是要记住,LSP最终处理的是对象,而不是类。

通过实现接口a然后尝试使方法签名不兼容,类b的用户可能会尝试调用b::baz()并失败,因为a::baz()的签名需要Baz,而您在b::baz()上的不兼容实现需要实例Foo

E、 例如,如果你的提议是合法的,这可能会发生:

$baz = new Baz();

$b = new b();

// since a::baz(Baz) is specified, the class user believes this
// should be possible, but your illegal implementation
// breaks that expectathtml" target="_blank">ion

$b->baz($baz); // Not accepted!

这根本不会破坏LSP。

正确实现接口 a 的类仍然可以接受类 FooBaz 的对象,因为可以使用子类型的对象而不是超类型的对象,正如 LSP 所说。

你不能写一个带有不兼容签名的方法,未来的协变和逆变支持也不允许这样做。

关于返回类型和参数类型中的协方差和逆差支持:PHP 7.4中提供了支持,将于2019年底发布。

你可以在这里阅读(被接受的)提案的细节。

> 仅返回类型

  • 支持协方差(因此,如果父类或接口声明返回类型 T,则定义现在可以指定 T 的子类)

    参数类型将支持逆变(这样,如果父类或接口声明了< code>T的参数类型,子类或实现类现在可以将< code>T的超类型声明为参数类型)

    在确定方法与其父级方法的兼容性时,只要新类型仍接受父级指定的类型,引擎现在就应该允许不太具体的参数类型和更具体的返回类型。换句话说:参数类型可以替换其超类型之一,返回类型可以替换子类型。

    同样,这将允许LSP支持,并允许类用户能够信任他们正在编程的抽象,而不必检查他们正在使用的具体类的细节。

  •  类似资料:
    • 我认为是这样的,因为子类在被替换时的行为不像基类,而且它抛出了一个RuntimeException? 我不完全确定,我想知道我的假设是否正确

    • 现在,让我们来看看“燃料”类: 以上是完成的所有抽象类,现在让我们看看具体的实现。首先,fuel的两个具体实现,包括一些贫血接口,以便我们可以正确地键入-提示/嗅探它们: 最后,我们有了车辆的具体实现,它确保使用正确的燃料类型(接口)为特定的车辆类别加油,如果不兼容则抛出异常: null

    • 我正在详细学习LSP,我确实理解为什么强化先决条件违反了这一原则(使用来自http://www.ckode.dk/programming/solid-principles-part-3-liskovs-substitution-principle/#contravariance): 在这里,我清楚地看到,对于基类有效的东西对于它的派生类将失败。换句话说,在不改变行为的情况下,我无法用基类的导数替换

    • 这是在一次采访中问我的。 我回答他说,对于相同的输入集,父母和孩子都应该产生相同的输出集。如果子节点想要扩展父节点的功能,它应该只在父节点支持范围之外的新输入上执行。这样,孩子将维持其父母签订的合同。 我给他举了一个例子,一个api可能正在使用这样的父级 如果这个孩子在这里产生了不同的输出,那么这个孩子就违反了它的父母签订的合同。 他对我的回答不满意,并告诉我这是简单的压倒一切,不违反LSP。所以

    • 子类型的实际后置条件是通过组合(使用逻辑)基类型的后置条件和子类型的后置条件来创建的,这使得得到的后置条件更具限制性 以下是加强前置条件和削弱后置条件的例子,结果违反了LSP(链接): > 假设基类使用成员int。现在您的子类型要求int为正。这是强化的前提条件,现在任何以前用负整数工作得很好的代码都被破坏了。 示例: 基类postcondition保证方法的返回值在范围内,但随后子类型将post

    • 概述 在工作初期,我们可能会经常会有这样的感觉,自己的代码接口设计混乱、代码耦合较为严重、一个类的代码过多等等,自己回头看的时候都觉得汗颜。再看那些知名的开源库,它们大多有着整洁的代码、清晰简单的接口、职责单一的类,这个时候我们通常会捶胸顿足而感叹:什么时候老夫才能写出这样的代码! 相关资料 iOS AFNetworking2.0源码解析 AFNetworking源码 单一原则(Single Re