是否可以输入多个提示类型?

问题描述 投票:21回答:6

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

例如参数$requester可以是UserFile

function log (User|File $requester) {

}
php php-7 type-hinting php-7.4
6个回答
29
投票

学术上,这称为type union

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日,Union Types PHP RFC被提议用于PHP 7.1。经过讨论和投票,该决议被拒绝,18反对,11反对。

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

该RFC有一些缺陷,但是被拒绝的主要原因是mainteners选民对变革的抵抗力很强,尤其是在涉及类型严格性和其他编程范式时(例如,“为什么当默认值接受所有类型的值时,需要类型联合“”这对性能不好“)。


10
投票

目前在PHP中是不可能的。但是,您可以拥有一个interface,并为interfaceUser实现它,然后将该接口用作File中的类型提示:

log()

4
投票

或者您可以为每种方法使用2种方法,而一种动态方法:

<?php
interface UserFile {
}

class User implements UserFile {
}
class File implements UserFile {
}

// snip

public function log (UserFile $requester) {
}
function logUser($requester)
{
  //
}

和动态的

function logFile($requester)
{
  //
}

3
投票

您可以检查内部函数的类型。

function log($requester)
{
  if ($requester instanceof File) {
    return $this->logFile($requester);
  }

  if ($requester instanceof User) {
    return $this->logUser($requester);
  }

  throw new LogMethodException();
}

1
投票

您可以为此创建父类:

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 {
    // ...
}

0
投票

自PHP 7.4起,将于2019年11月28日发布,这将是可能的>>,其中包括联合类型。

function log (Parent_class $requester) { // ... code } ,实现已经准备就绪。

[有一个proposal has been voted 61 in favour to 5 against提出这一点,在另一个答案中提到,但最终被拒绝了。

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

previous RFC

这意味着class F { public function foo (File|Resource $f) : int|float { /** implement this**// } } 期望F::foo()或资源,并且将返回Fileint

另外几点:

可空性

此外,您可以使用float声明联合。 null等效于A|null,但也可以使用更复杂的声明作为?A

“ False”伪类型

也可以将A|B|null类型用作联合类型声明的一部分。例如。 false。之所以包含此内容,主要是由于历史原因,因为某些内部函数会在某些类型的错误条件下返回int|false。参见false作为示例。

在这些情况下,更多现代功能可能会返回strpos()或引发异常,但是包括了此替代方法以解决旧代码。

在继承中添加和删除部分联合类型

对参数类型提示使用[[add联合类型是合法的(因此,使函数的限制较少),对返回类型提示使用remove联合类型(使返回类型更加具体)。] >鉴于上面的类null,这是合法的:

F

但这不是:

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

© www.soinside.com 2019 - 2024. All rights reserved.