是否可以在 PHP 7 上指定多个 return 类型?

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

我有一些方法可以 return 两种 return 类型之一 。我正在使用一个利用 MCV 的框架,因此重构这几个函数特别没有吸引力。

是否可以声明 return 类型 return 一个或另一个并在其他任何事情上失败?

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

    return SucceedObject;
}

从 PHP 8+ 开始,您可以使用 union types:

function test(): FailObject|SuccessObject {}

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

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

在此示例中,ReturnInterface 为空。它的存在本身就支持所需的 return 类型声明。

您也可以使用基础,可能是抽象的,class。


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

正如 bishop 所指出的,有一个用于添加多个 return 类型的 RFC。但是,我想我会补充说,从 PHP7.1 开始,您现在可以像这样指定可为 null 的 return 类型:

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

所以这个函数将接受一个字符串,并通过在 int 之前添加问号,您允许它 return 为 null 或整数。

这是文档的 link: http://php.net/manual/en/functions.returning-values.php

这是该页面上解释用法的引述: PHP 7.1 通过在类型声明前加上 ? 来允许 void 和 null return 类型。 —(例如函数 canReturnNullorString(): ?string)

此外,还有一个与此相关的话题:

PHP 从 7.2 开始支持对象 return 类型

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

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

这不是正确的方法:

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

    return SucceedObject;
}

多个 return 类型是不好的做法。 好的做法:

你应该定义一个例外:

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
}

因为 PHP 8.0 this is possible.

您现在可以使用联合类型来指定:

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

    return new Success();
}

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

但在其他情况下,联合类型可以作为弱类型的替代方案。例如。接受 stringint 的方法,或者描述函数的 return 类型,如 stripos(),其中 returns int|false