Php 是否可以键入多个类型的提示?

Php 是否可以键入多个类型的提示?,php,type-hinting,php-8,Php,Type Hinting,Php 8,我可以允许两种不同的类型使用类型提示吗 例如,参数$requester可以是用户或文件: function log (User|File $requester) { } 您可以在函数中检查类型 function log ($requester) { if ($requester instanceof User || $requester instanceof File) { //Do your job } } 您可以为这两个对象创建父类: abstract

我可以允许两种不同的类型使用类型提示吗

例如,参数
$requester
可以是
用户
文件

function log (User|File $requester) {

}

您可以在函数中检查类型

function log ($requester) {
    if ($requester instanceof User || $requester instanceof File) {
        //Do your job
    }
}

您可以为这两个对象创建父类:

abstract class Parent_class {}
class User extends Parent_class {
    // ...
}
class File extends Parent_class {
    // ...
}
并在函数中使用它

function log (Parent_class $requester) {
    // ... code
}

这在PHP中目前是不可能的。但是,您可以拥有一个,并为
用户
文件
实现它,然后将该接口用作
日志()中的类型提示:


学术上,这被称为

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有一些缺陷,但被拒绝的主要原因是,维护者选民非常抵制更改,特别是当涉及类型严格性和其他编程范式时(例如,“当默认值采用所有类型的值时,为什么我们需要类型联合”和“这对性能不好”).

或者每个方法可以有两种方法和一种动态方法:

函数日志用户($requester)
{
//
}
函数日志文件($requester)
{
//
}
还有动态的

函数日志($requester)
{
if($requester instanceof File){
返回$this->logFile($requester);
}
if($requester instanceof User){
返回$this->logUser($requester);
}
抛出新的LogMethodException();
}
从PHP 8.0开始,通过包含联合类型,这将是可能的。 已启动,并且已准备好实施。

还有一个提议,在另一个答复中提到,但最后被拒绝了

其工作原理与您问题中的示例完全相同:

class F
{
   public function foo (File|Resource $f) : int|float { /** implement this**// }
}
这意味着
F::foo()
需要一个
文件或一个资源,并将返回
int
float

还有几点:

空属性 此外,还可以使用
null
声明联合
A | null
相当于
?A
,但也可以使用更复杂的声明
A | B | null

“假”伪类型 也可以使用
false
类型作为联合类型声明的一部分。例如
int | false
。这主要是因为历史原因,因为某些内部函数在某些类型的错误条件下返回
false
。请看一个例子

在这些情况下,更现代的函数可能会返回
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 { /** **/ }
}

如果这两个类都有一个共同的继承或接口(例如,
Loggable
),那么你可以将它用于typehintPossible的副本,我有点不相信这一点,但我只是检查了一下,伤心地去看了看RFC来思考它,然后决定去看RFC索引,联合类型V2位于RFC列表的顶部。哇!它实际上是在6天前开始讨论的这也是第一次在GH上讨论RFC。迷人的时机lol@i336_是的,我还认为它将与此进行斗争——我反复遇到的联合类型的主要需求之一是ArrayAccess不允许传递数组。我从来没有找到一个好的解决方案来解决这个问题,默认情况下,在这些情况下根本没有任何类型的暗示。for Union TYPE在PHP8中被接受和实现。您能为PHP8输入提示异常吗?为什么不能?异常是类。我的意思是类型暗示一个方法可能会抛出一个异常,而不是返回它<代码>myMethod():void | MyException
不起作用这是一个返回类型提示。对于该语法,您说“此方法返回
void
MyException
的一个实例”。对于“可能引发异常”没有语法,您需要使用注释或属性。
class H extends F
{
    public function foo(File $f) : int|float|bool { /** **/ }
}