是否可以在 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;
【问题讨论】:
仅当FailObject
和SucceedObject
都共享一个接口或从一个共同的父级扩展时
【参考方案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();
这是可能的事实并不意味着它总是可取的。在许多(可能是大多数)情况下,使用不同答案中建议的接口(例如Result
,Failure
和Failure
都将实现)仍然是更可取的。
但在其他情况下,联合类型可以作为弱类型的替代方案。例如。一个同时接受string
和int
的方法,或者描述像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 上指定多种返回类型?的主要内容,如果未能解决你的问题,请参考以下文章