我有一些方法可以返回两种类型中的一种。我正在使用一个利用MVC框架,因此特别是重构这几个函数并不具吸引力。
是否有可能声明返回其中一种类型并在其他任何情况下失败?
function test(): ?
{
if ($this->condition === false) {
return FailObject;
}
return SucceedObject;
}
我有一些方法可以返回两种类型中的一种。我正在使用一个利用MVC框架,因此特别是重构这几个函数并不具吸引力。
是否有可能声明返回其中一种类型并在其他任何情况下失败?
function test(): ?
{
if ($this->condition === false) {
return FailObject;
}
return SucceedObject;
}
从PHP 8+开始,您可以使用联合类型:
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
。null|Entity
。非常受限制... - Aerendir?Entity
可以获得 null|Entity
。请参阅 https://secure.php.net/manual/en/migration71.new-features.php。 - 0b10011正如主教所指出的那样,有一个添加多个返回类型的RFC。然而,我想补充一下,在PHP7.1中您现在可以像这样指定可为空的返回类型:
function exampleFunction(string $input) : ?int
{
// Do something
}
这个函数需要一个字符串作为输入,并在int前面添加问号,从而允许它返回null或整数。
下面是官方文档链接: http://php.net/manual/en/functions.returning-values.php
这里引用了该页面的一段话来解释用法: PHP 7.1可以通过在类型声明前加上?来允许void和null返回类型——(例如:function canReturnNullorString(): ?string)
此外,这里还有一个与此相关的主题:Nullable return types in PHP7
PHP自7.2版本开始支持对象返回类型
http://php.net/manual/zh/migration72.new-features.php
function test(object $obj) : object
// return any type of object ...
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
}
FailObject
和SucceedObject
共享一个接口或继承自公共父类时,条件才成立。 - Mark Baker