Проверка, реализует ли класс экземпляра интерфейс?

Учитывая экземпляр класса, можно ли определить, реализует ли он конкретный интерфейс? Насколько мне известно, встроенной функции для этого напрямую нет. Какие у меня есть варианты (если есть)?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
160
0
96 938
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий
interface IInterface
{
}

class TheClass implements IInterface
{
}

$cls = new TheClass();
if ($cls instanceof IInterface) {
    echo "yes";
}

Вы можете использовать оператор instanceof. Чтобы использовать его, левый операнд - это экземпляр класса, а правый операнд - это интерфейс. Он возвращает истину, если объект реализует определенный интерфейс.

Обратите внимание, что это не будет полезно, если вы пытаетесь определить конструктор класса.

AaA 23.11.2020 11:12

nlaq указывает, что instanceof можно использовать для проверки того, является ли объект экземпляром класса, реализующего интерфейс.

Но instanceof не делает различий между типом класса и интерфейсом. Вы не знаете, является ли объект класс, который случайно называется IInterface.

Вы также можете использовать API отражения в PHP, чтобы проверить это более конкретно:

$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
  print "Yep!\n";
}

См. http://php.net/manual/en/book.reflection.php

Это можно использовать в "статических" классах.

Znarkus 23.08.2009 13:41

См. Также class_implements()

John Carter 16.11.2011 01:54

@therefromhere: Спасибо, хороший совет. Это часть расширения SPL. В моем ответе использовалось расширение Reflection.

Bill Karwin 16.11.2011 02:01

Если вы используете пространства имен, тогда не будет неоднозначности между интерфейсами и классами с одинаковыми именами, и вы можете снова безопасно использовать instanceof.

flu 21.03.2012 20:18

+1 для class_implements(), так как он, очевидно, быстрее вызывает class_implements, а затем in_array, вместо того, чтобы делать полное отражение

Nickolaus 17.03.2017 17:20

Как указывает оттуда, вы можете использовать class_implements(). Как и в случае с Reflection, это позволяет указать имя класса в виде строки и не требует наличия экземпляра класса:

interface IInterface
{
}

class TheClass implements IInterface
{
}

$interfaces = class_implements('TheClass');

if (isset($interfaces['IInterface'])) {
    echo "Yes!";
}

class_implements() является частью расширения SPL.

См .: http://php.net/manual/en/function.class-implements.php

Тесты производительности

Некоторые простые тесты производительности показывают стоимость каждого подхода:

Учитывая экземпляр объекта

Object construction outside the loop (100,000 iterations)
 ____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 140 ms           | 290 ms     | 35 ms      |
'--------------------------------------------'

Object construction inside the loop (100,000 iterations)
 ____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 182 ms           | 340 ms     | 83 ms      | Cheap Constructor
| 431 ms           | 607 ms     | 338 ms     | Expensive Constructor
'--------------------------------------------'

Учитывая только имя класса

100,000 iterations
 ____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 149 ms           | 295 ms     | N/A        |
'--------------------------------------------'

Где дорогой __construct ():

public function __construct() {
    $tmp = array(
        'foo' => 'bar',
        'this' => 'that'
    );  

    $in = in_array('those', $tmp);
}

Эти тесты основаны на этот простой код.

is_subclass_of - также хороший вариант для облегчения будущих поисков (для PHP 5.3.7+):

if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
    echo 'I can do it!';
}

Вы также можете сделать следующее

public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
   //.....
}

Это вызовет исправляемую ошибку, если $objectSupposedToBeImplementing не реализует интерфейс YourInterface.

Обновлять

is_aфункция здесь отсутствует в качестве альтернативы.

Я провел несколько тестов производительности, чтобы проверить, какой из заявленных способов наиболее эффективен.

Результаты более 100 тыс. Итераций

      instanceof [object] took   7.67 ms | +  0% | ..........
            is_a [object] took  12.30 ms | + 60% | ................
             is_a [class] took  17.43 ms | +127% | ......................
class_implements [object] took  28.37 ms | +270% | ....................................
       reflection [class] took  34.17 ms | +346% | ............................................

Добавлены точки, чтобы на самом деле «почувствовать» разницу.

Создано этим: https://3v4l.org/8Cog7

Заключение

Если у вас есть объект для проверки, используйте instance of, как указано в принятом ответе.

Если у вас есть класс для проверки, используйте is_a.

Бонус

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

Пример: is_a(<className>, <interfaceName>, true);

Он вернет bool. Третий параметр «allow_string» позволяет ему проверять имена классов без, создающие экземпляр класса.

Другие вопросы по теме