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

问题描述 投票:3回答:8

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

php function overriding return-type
8个回答
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中的字符数的假设已被破坏,从而导致不一致。


3
投票

是的,这很糟糕。该方法的客户很难知道该期望什么。除非如此,该方法旨在处理该问题(在这种情况下,它看起来好像不是这样)。

我将强烈建议不要这样做。


3
投票

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

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


2
投票

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

从插座和设备的角度考虑公共方法及其返回类型。除非插座是专门为特定类型的设备设计的,否则任何设备都应能够插入任何插座,并且每个插座应向每个设备输出相同量的能量。如果有人决定绿色插座应输出一种能量而红色插座应输出另一种能量,将会发生什么。突然,您必须始终关心设备要处理的特定插座类别。

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


2
投票

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

如果您急需从函数中传递除返回值以外的另一个值,则可以添加一个按引用传递参数。或者,如果出现错误消息,请使用“异常”。


2
投票

继承的思想是允许客户互换使用类的子类型。如果要更改子类型的返回类型,那么您将破坏继承的规范实用程序,最终将造成混乱:“这里我使用的是Collection类型,但是myCollection.add()是否会向我返回一个布尔值或所添加的元素或其他内容?我不知道!我无法使用这种类型做任何事情!我我将不得不为每个子类型创建一个方法来处理此问题!“


1
投票

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

如果覆盖的方法返回一个布尔值,则如果0返回值对应于导致覆盖方法返回FALSE的条件,并且非零值对应于TRUE,则覆盖的方法可以返回一个数字。返回值。如果有人在返回值上使用相同的比较运算符(===),这仍然可能潜在地引起问题,但是您通常仅在(例如)方法可能在不同条件下同时返回FALSE0时看到此错误。 >

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

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

  • 原始方法返回了bool
:成功|失败
  • 测试方法返回了array代替,返回了一些debug info
  • 这就是我解决的方法:

    • [在方法名称前面添加了“测试”前缀;
  • 在php doc注释中,我添加了@see标记,后跟原始方法名称;
  • 我真的很喜欢这种解决方案,因为通过CtrlStorm并单击phpStorm,可以得到原始方法。

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

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


    0
    投票

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

    © www.soinside.com 2019 - 2024. All rights reserved.