是否可以键入多个类型的提示?从 PHP 8.0 开始,通过包含联合类型,这是可能的。

2022-08-30 09:02:42

是否可以允许使用类型提示的两种不同类型?

例如,参数可以是或:$requesterUserFile

function log (User|File $requester) {

}

答案 1

从 PHP 8.0 开始,通过包含联合类型,这是可能的

该提案已以61票赞成,5票反对,实施准备就绪。

之前有一个RFC提出了这个问题,在另一个答案中提到过,但那个答案最终被拒绝了。

它将完全按照您问题中的示例工作:

class F
{
   public function foo (File|Resource $f) : int|float { /** implement this**// }
}

这意味着 需要 一个 或 一个资源,并将返回 一个 或 .F::foo()Fileintfloat

另外几点:

可空性

此外,还可以使用 声明并集。 等价于 ,但更复杂的声明也是可能的。nullA|null?AA|B|null

“假”伪型

也可以将该类型用作联合类型声明的一部分。例如.这主要是因为历史原因,因为某些内部函数在某些类型的错误条件下返回。请参阅 strpos() 作为示例。falseint|falsefalse

在这些情况下,更现代的函数可能应该返回或引发异常,但包含此替代方法是为了考虑遗留代码。null

在继承时添加和删除联合类型的一部分

为参数类型提示添加联合类型(从而使函数的限制性降低)和删除返回类型提示的联合类型(使返回类型更具体)是合法的。

给定上面的类,这是合法的:F

class G extends F
{
    public function foo(File|Resource|string $f) : int { /** **/ }
}

但事实并非如此:

class H extends F
{
    public function foo(File $f) : int|float|bool { /** **/ }
}

答案 2

在学术上,这称为类型联合

PHP 中的并集类型

您可以通过创建接口,父类型等来作弊,如其他答案中所述,但是除了为项目增加复杂性和LoC之外,还有什么意义呢?另外,这不适用于标量类型,因为您无法扩展/实现标量类型。

而不是使代码更具可读性,你会得到相反的结果。除非这些类/接口已经存在并且它们因为OOP而在这里,而不是为了解决类型提示问题。

解决方法

PHP中的规范答案是...好吧,只是不要放一个类型提示。该语言被认为没有复杂而强大的类型系统,试图解决该语言的缺陷并不是一个好的答案。

相反,请正确记录您的函数:

/**
 * Description of what the function does.
 *
 * @param User|File $multiTypeArgument Description of the argument.
 *
 * @return string[] Description of the function's return value.
 */
function myFunction($multiTypeArgument)
{

这至少会带来对自动完成和静态代码分析的IDE支持。在处理私人项目,网站等时就足够了。

在设计公共API(PHP库等)时,有时您可能希望对API使用者的输入更加防御。

那么@tilz0R答案就是要走的路:

function log($message) {
    if (!is_string($message) && !$message instanceof Message) {
        throw new \InvalidArgumentException('$message must be a string or a Message object.');
    }

    // code ...
}

PHP(几乎)具有联合类型的那一天

2015 年 2 月 14 日,PHP 7.1 提出了联合类型 PHP RFC。经过讨论和投票,它被拒绝了,18个“不”对11个“是”。

如果 RFC 已被接受,PHP 将具有与您显示的方式完全相同的联合类型 ()。User|File

RFC有一些缺陷,但它被拒绝的主要原因是维护者选民对更改非常抗拒,特别是当它涉及类型严格性和其他编程范例时(例如,“当默认值采用所有类型的值时,为什么我们需要类型联合”“这对性能不利”)。


推荐