是否可以在 PHP 7 上指定多种返回类型?

Posted

技术标签:

【中文标题】是否可以在 PHP 7 上指定多种返回类型?【英文标题】:Is it possible to specify multiple return types on PHP 7? 【发布时间】:2016-08-30 05:03:52 【问题描述】:

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

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

function test(): ?

    if ($this->condition === false) 
        return FailObject;
    

    return SucceedObject;

【问题讨论】:

仅当FailObjectSucceedObject 都共享一个接口或从一个共同的父级扩展时 【参考方案1】:

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

function test(): FailObject|SuccessObject 

另一种方法,自 PHP 4 起在所有版本中都可用,即两个对象共享一个接口。示例:

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

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

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


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

【讨论】:

你也可以在这里使用abstract class 这确实是限制性的:想想实体(例如,被 Doctrine 使用):不可能暗示返回到 null|Entity。真的限制... @Aerendir 解决方案/解决方法是让存储库方法返回一个包含空类型或实体的选项。下面是一个提供 Option 类型的包示例:github.com/schmittjoh/php-option @tangobango 如答案所述:不,RFC 被拒绝了。 @Aerendir null|Entity 在 PHP 7.1 中可用,具有可空类型:?Entity。见secure.php.net/manual/en/migration71.new-features.php。【参考方案2】:

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

function exampleFunction(string $input) : ?int

    // Do something

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

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

下面是该页面的引述,解释了用法: PHP 7.1 允许在类型声明前加上 ? —(例如函数 canReturnNullorString(): ?string)

另外,还有一个与此相关的线程:Nullable return types in PHP7

【讨论】:

"允许 void 和 null 返回类型"返回 null 对我有用,但 void 会引发异常。 “...或 null,没有返回...” 如果我使用“return;”错误变为:“具有返回类型的函数必须返回一个值”【参考方案3】:

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

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

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

【讨论】:

【参考方案4】:

自 PHP 8.0 this is possible.

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

function test(): Success|Failure

    if ($this->condition === false) 
        return new Failure();
    

    return new Success();

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

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

【讨论】:

【参考方案5】:

这是不正确的方法:

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

【讨论】:

异常应该用于控制应用程序的流程。您本质上将此处的异常视为 if 语句,这不是异常的正确用法。 你是说失败案例也不例外?嗯...最好返回一个“FailObject”并控制多个输出:if、elseif、elseif、else。 (否) 我建议代码结构正确,这样您就不需要依赖任何一个:) 必须设置严格类型来编写干净、可维护和健壮的代码。描述的情况(带有“FailObject”)是手动异常。控制流量也不例外。流程继续成功案例。您不必在应用控制器之前控制异常。

以上是关于是否可以在 PHP 7 上指定多种返回类型?的主要内容,如果未能解决你的问题,请参考以下文章

PHP 7 接口,返回类型提示和自我

如何在 php 7.1 中表示返回类型是当前子类型?

php判断两张图片是否相同

PHP如何检查一个数组内是不是存在指定元素

下载漏洞扫描工具Nikto

如果函数返回多种类型,我可以声明一个函数返回值吗? [复制]