php - 我对 Liskov 替换原则有什么误解

标签 php liskov-substitution-principle

我以为我了解 LSP,但看来我完全错了。我有以下类(class):

class PrimitiveValue {
}

class StringValue extends PrimitiveValue {
}

class A {
    public function foo(StringValue $value) {
    }
}

class B extends A {
    public function foo(PrimitiveValue $value) {
    }
}

注意基类A接受子类 StringValue作为参数类型,子类B接受父类PrimitiveValue。我之所以这样说,是因为到处都会有人问类似的问题,只是类型相反。

根据我的理解,B 类中的方法 foo() 接受父方法接受的任何内容,再加上更多,因为它接受基类型 PrimitiveValue。因此,任何只看到类 A 的调用者都会传递 B 可以处理的值,而不会违反 LSP。知道它是 B 的调用者可以做出更强的假设,并可以自由传递其他 PrimitiveValue 子类型。

然而,当我执行代码时,出现错误:

严格 (2048):B::foo() 的声明应与 A::foo(StringValue $value) 兼容 [APP/Controller/TestLocalController.php,第 17 行]

我哪里错了?我认为最有帮助的是一个示例,说明如何传递违反代码对该值所做假设的值。假设很清楚我要实现的目标,还请添加有关如何正确执行此操作的代码。

最佳答案

What am I getting wrong? I think most helpful would be an example of how a value can be passed that violates the assumptions the code makes about that value.

你没有误解LSP,在子类方法中允许更大的类型并不违反原则;事实上,你所描述的是contravariant method argument types。 ,由于设计或实现困难,PHP 不支持某些内容。

就个人而言,我对这种方法的唯一保留意见是子类中较弱类型的处理被父类(super class)隐藏了。

Assuming that it is clear what I'm trying to achieve, please also add code on how to do it correctly.

PHP 中的方法参数类型是不变的,即每个参数的类型(如果在父级中提供)在覆盖方法时必须完全匹配。虽然此行为已在 past 中讨论过再次长大recently随着return type hinting的介绍,即使在下一个主要版本中也不能保证可用。

为了克服这个问题,您目前被迫让原始类型和派生类型都实现相同的接口(interface),然后在父类和子类中使用该接口(interface),如 this answer 所述。 .

关于php - 我对 Liskov 替换原则有什么误解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28362180/

相关文章:

php - "Notice: Undefined variable"、 "Notice: Undefined index"、 "Warning: Undefined array key"和 "Notice: Undefined offset"使用 PHP

php - 当点击提交按钮时是否发送单独表单中的输入?

php - 如果我用一个用户登录,它会用任何密码登录

java - 当 "if else"/"instance of"是不可避免的时候,除了使用访问者模式,我们如何改进设计呢?

oop - Java LSP "derived object can substitute base object"

php - 从 php 文件运行命令时出现 SQL 错误

php - 数据库中编辑类别时出错

c++ - 使用 C++ 继承来增强具有所有权语义的类

oop - 里氏替换原理的例子是什么?

java - LSP 对像 Ruby 这样的动态类型语言也有意义吗?