在PHP中重写子类中的函数时更改返回类型?

时间:2009-11-24 04:08:02

标签: php function override return-type

这不好吗?或者这在PHP框架中很常见?

例如,在父类中,有一个save()函数,它返回数据库中受影响的行数。然后在子类中,我重写此函数以进行一些预验证,并且还想简单地返回成功/失败的布尔值。

8 个答案:

答案 0 :(得分:5)

我同意一致认为改变返回值的类型(甚至含义)是不好的。

以下是一个不好的例子:

假设您有一个接受字符串和'Writer'的函数:

function printThroughWriter(String $text, Writer $writer) {
    $count = $writer->write($text);
    print "Writer '".get_class($writer)."' printed $count characters.";
}

这是最初的'作家'课程:

class Writer {
    public function write(String $text) {
        print $text;
        return strlen($text);
    }
}

如果我们将'LazyWriter'传递给函数

,该怎么办?
class LazyWriter extends Writer {
    public function write(String $text) {
        return true;
    }
}

假设Writer::write()的返回值是printThroughWriter中的字符数已被破坏,从而导致不一致。

答案 1 :(得分:3)

是的,这很糟糕。该方法的客户很难知道要期待。除非,该方法旨在处理它(在这种情况下,它似乎不是)。

我会强烈反对。

答案 2 :(得分:3)

您应该覆盖基础代码,而不是合同。

所以,不,改变返回值(这是合同的一部分)并不好。

答案 3 :(得分:2)

虽然在PHP中没有强制执行返回类型,但最好与重写方法保持一致,因为否则意味着您将增加耦合并减少封装。

考虑公共方法及其在出口和设备方面的退货类型。任何设备都应该能够插入任何插座,并且每个插座应该向每个设备输出相同的能量,除非插座是专门为特定类型的设备设计的。如果有人认为绿色出口应输出一定量的能量,而另一个则输出红色能量,会发生什么。突然间,您必须始终关注设备正在处理的特定类型的插座。

设计公共方法和属性完全相同,重写的方法和属性应始终表现一致,无论访问它们的上下文如何。

答案 4 :(得分:2)

我同意,这通常是一个坏主意。

如果你迫切需要从函数中传递另一个值,除了它的返回值,你可以添加一个pass-by-reference参数。或者,如果出现错误消息,请使用例外。

答案 5 :(得分:2)

继承的想法是允许客户端交换使用类的子类型。如果要更改子类型的返回类型,那么您正在破坏继承的规范实用程序,并最终会造成混淆: “我在这里采用了一种类型的集合,但是myCollection.add()会给我一个布尔值或者添加的元素或其他东西吗?我不知道!我不能再用这种类型做任何事了!我我将不得不为每个子类型创建一个方法来处理这个问题!“

答案 6 :(得分:1)

您可以从重写方法返回更多指定类型,例如返回类型的后代实例,而不会违反合同。

如果重写的方法返回了一个布尔值,则重写方法可以返回一个数字,如果0返回值对应于将导致重写方法返回FALSE并且非零值对应的条件到TRUE返回值。如果有人在返回值上使用相同的比较运算符(===),这仍然可能会导致问题,但是通常只有在(例如)方法可能同时返回FALSE和{{1}时才会看到此问题在不同的条件下。

在您的示例中,覆盖返回类型并不比重写的返回类型更具体,因此您不应该这样做。

答案 7 :(得分:0)

我最终在这里寻找正确的做事方式。 就我而言,我是在谈论测试课程:

  • 原始方法返回了 bool :成功|失败
  • 测试方法返回一个数组,以返回一些 debug信息

这就是我解决的方法:

  • 在方法名称前面添加“ test”前缀;
  • 在php doc注释中,我添加了@see标记,后跟原始方法名称;

我真的很喜欢这个解决方案,因为通过CtrlStorm并单击phpStorm,可以找到原始方法。

在其他情况下,可能不会更改返回类型,正如其他人所解释的那样,但是see标记可以类似的方式使用。

希望有帮助!继续摇摆;)