Подсказка типа php Можно ли разрешить два типа?

Могу ли я разрешить два разных типа, используя подсказки типа? Например. Параметр 1 может быть либо из двух классов

function log (User|File $requester) {
}

Ответ 1

Академически это называется союзом типов.

Объединение типов в PHP

Вы можете обманывать, создавая интерфейсы, родительские типы и т.д., Как упоминалось в других ответах, но какой смысл, кроме добавления сложности и LoC в ваш проект? Кроме того, это не может работать для скалярных типов, так как вы не можете расширить/реализовать скалярный тип.

Вместо того, чтобы сделать код более читабельным, вы получите обратное. За исключением случаев, когда эти классы/интерфейсы уже существуют, и они находятся здесь из-за ООП, а не для решения проблемы хинтинга типов.

обходные

Канонический ответ в PHP... ну, просто не ставьте подсказку типа. Считалось, что язык не имеет сложной и мощной системы типов, и попытка обойти недостатки языка не является хорошим ответом.

Вместо этого, документируйте свою функцию правильно:

/**
 * Description of what the function does.
 *
 * @param User|File $multiTypeArgument Description of the argument.
 *
 * @return string[] Description of the function 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 (почти) были типы объединения

14 февраля 2015 года было предложено объединение типов PHP RFC для PHP 7.1. После обсуждения и голосования было отклонено 18 "нет" против 11 "да".

Если бы RFC был принят, в PHP были бы типы объединения в точности так, как вы показали (User|File).

RFC имел некоторые недостатки, но главная причина, по которой он был отклонен, заключается в том, что избиратели, поддерживающие поддержку, весьма сопротивляются изменениям, особенно когда речь идет о строгости типов и других парадигмах программирования (например, "зачем нам нужны объединения типов, когда по умолчанию все типы значений "и", что не хорошо для производительности ").

Ответ 2

В настоящее время это невозможно в PHP. Однако вы можете иметь interface и реализовать его для User и File, а затем использовать этот интерфейс в качестве подсказки типа в log():

<?php
interface UserFile {
}

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

// snip

public function log (UserFile $requester) {
}

Ответ 3

Вы можете проверить внутреннюю функцию типа.

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

Ответ 4

Вы можете создать родительский класс для этих двух:

abstract class Parent_class {}
class User extends Parent_class {
    // ...
}
class File extends Parent_class {
    // ...
}

И используйте его в функции

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

Ответ 5

Или вы можете иметь 2 метода для каждого и один динамический метод:

function logUser($requester)
{
  //
}
function logFile($requester)
{
  //
}

И динамический

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

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

  throw new LogMethodException();
}