是否可以在PHP7上指定多个返回类型


Is it possible to specify multiple return types on PHP 7?

我有一些方法可以返回两种返回类型之一。我使用的是一个利用MCV的框架,所以重构这几个函数特别没有吸引力。

是否可以声明返回类型返回一个或另一个,而在其他任何事情上都失败?

function test(): ?
{
    if ($this->condition === false) {
        return FailObject;
    }
    return SucceedObject;
}

从PHP 8+开始,您可以使用联合类型:

function test(): FailObject|SuccessObject {}

另一种方法是让两个对象共享一个接口,这在自PHP4以来的所有版本中都可用。示例:

interface ReturnInterface {}
class FailObject implements ReturnInterface {}
class SuccessObject implements ReturnInterface {}
function test(): ReturnInterface {}

在本例中,ReturnInterface为空。它的存在支持所需的返回类型声明。

您还可以使用一个基类,可能是抽象类。


对我来说,对于这个用例,接口比联合类型更清晰、更可扩展。例如,如果我以后想要一个WarnObject,我只需要将其定义为扩展ReturnInterface,而不是遍历所有签名并将其更新为FailObject|SuccessObject|WarnObject

正如bishop所指出的,有一个RFC用于添加多个返回类型。然而,我想补充一下,从PHP7.1开始,您现在可以指定一个可以为null的返回类型,如下所示:

function exampleFunction(string $input) : ?int
{
    // Do something
}

因此,这个函数将接收一个字符串,通过在int之前添加问号,可以让它返回null或整数。

以下是文档链接:http://php.net/manual/en/functions.returning-values.php

下面引用该页面中的一句话来解释用法:PHP 7.1允许void和null返回类型,方法是在类型声明前面加一个?--(例如函数canReturnNullorString():?字符串)

此外,这里还有另一个与此相关的线程:PHP7 中的可为null的返回类型

PHP从7.2开始支持对象返回类型

http://php.net/manual/en/migration72.new-features.php

function test(object $obj) : object
// return any type of object ...

由于PHP 8.0,这是可能的。

您现在可以使用并集类型来指定以下内容:

function test(): Success|Failure
{
    if ($this->condition === false) {
        return new Failure();
    }
    return new Success();
}

这是可能的事实并不意味着它总是可取的。在许多(可能是大多数)情况下,使用不同答案中建议的接口(例如ResultFailureFailure都将实现)仍然是非常可取的。

但在其他情况下,联合类型可以替代弱类型。例如,一个同时接受stringint的方法,或者描述函数(如stripos())的返回类型,该函数返回int|false

这不是正确的方式:

function test(): ?
{
    if ($this->condition === false) {
        return FailObject;
    }
    return SucceedObject;
}

多次返回类型是一种糟糕的做法良好做法:

您应该定义一个例外:

class FailObjectException extends 'Exception
{
    private $exampleExtraInfo;
    public function __construct($exampleExtraInfo, $message)
    {
        parent::__construct($message);
        $this->exampleExtraInfo = $exampleExtraInfo;
    }
    public function exampleExtraInfo(): int
    {
        return $this->exampleExtraInfo;
    }
}

现在,您可以定义如下函数:

function test(): SucceedObject
{
    if ($this->condition === false) {
        throw new FailObjectException(...,...);
    }
    return SucceedObject;
}

并将此功能与try/catch一起使用:

try{
    $succeedObject = $any->test();
} catch (FailObjectException $exception){
    //do something
}