我有一些方法可以返回两种返回类型之一。我使用的是一个利用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();
}
这是可能的事实并不意味着它总是可取的。在许多(可能是大多数)情况下,使用不同答案中建议的接口(例如Result
,Failure
和Failure
都将实现)仍然是非常可取的。
但在其他情况下,联合类型可以替代弱类型。例如,一个同时接受string
和int
的方法,或者描述函数(如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
}