instanceof
Узнайте, как оператор instanceof в PHP проверяет принадлежность объекта к классу, родительскому классу или интерфейсу — с примерами и подводными камнями.
Оператор PHP instanceof
instanceof — это оператор проверки типов в PHP. Он возвращает boolean (true или false), сообщая, принадлежит ли объект к заданному классу — или, что более полезно, принадлежит ли он к родительскому классу в цепочке наследования или реализует заданный интерфейс.
На этой странице рассматриваются синтаксис, поведение instanceof при наследовании и работе с интерфейсами, использование с именем класса в переменной, крайние случаи, которые часто удивляют (не-объекты, null, несуществующие имена классов), а также когда стоит применять instanceof, а когда лучше выбрать другой подход.
Если классы и объекты для вас в новинку, сначала прочитайте Классы и объекты PHP.
Синтаксис
$object instanceof ClassNameВыражение возвращает true, когда $object является экземпляром ClassName, любого класса, расширяющего ClassName, или любого класса, реализующего ClassName (когда ClassName — интерфейс). В противном случае возвращается false. Обратите внимание: синтаксис вызова метода отсутствует — instanceof является оператором, как и ===, а не функцией.
Базовая проверка
<?php
class MyClass {}
class MyOtherClass {}
$object = new MyClass();
if ($object instanceof MyClass) {
echo "The object is an instance of MyClass.";
} else {
echo "The object is not an instance of MyClass.";
}
// Output: The object is an instance of MyClass.
var_dump($object instanceof MyOtherClass);
// Output: bool(false)$object был создан из MyClass, поэтому первая проверка возвращает true. С MyOtherClass он никак не связан, поэтому эта проверка даёт false. Оба класса не связаны между собой, даже если выглядят похоже.
instanceof и наследование
Главная ценность instanceof состоит в том, что он обходит всю цепочку наследования. Дочерний объект является экземпляром своего родительского класса, поэтому проверка проходит успешно для каждого предка.
<?php
class Fruit {}
class Apple extends Fruit {}
class Banana extends Fruit {}
$apple = new Apple();
var_dump($apple instanceof Apple); // bool(true) — its own class
var_dump($apple instanceof Fruit); // bool(true) — its parent class
var_dump($apple instanceof Banana); // bool(false) — a sibling class$apple проходит проверку Fruit, потому что Apple расширяет Fruit. Проверка Banana не проходит, потому что Apple и Banana — это «братские» классы: ни один из них не наследует другой. Подробнее в разделе Наследование PHP.
instanceof и интерфейсы
instanceof чаще всего используется с интерфейсами. Поскольку любой класс, реализующий интерфейс, считается его экземпляром, можно проверять наличие возможности, не беспокоясь о конкретном классе.
<?php
interface Drawable {
public function draw(): string;
}
class Circle implements Drawable {
public function draw(): string { return "○"; }
}
class Square implements Drawable {
public function draw(): string { return "□"; }
}
$shapes = [new Circle(), new Square(), "not a shape"];
foreach ($shapes as $shape) {
if ($shape instanceof Drawable) {
echo $shape->draw();
}
}
// Output: ○□Строка "not a shape" пропускается, потому что не является Drawable. Это типичный сценарий использования: отфильтровать смешанный список до объектов, поддерживающих нужное поведение. Полная картина — в разделе Интерфейсы PHP.
Использование имени класса из переменной
В правой части может стоять строковая переменная с именем класса или интерфейса. Это удобно, когда тип определяется во время выполнения.
<?php
class Fruit {}
class Apple extends Fruit {}
$apple = new Apple();
$type = 'Fruit';
var_dump($apple instanceof $type); // bool(true)Можно также сравнить два объекта — $a instanceof $b работает, когда $b является объектом: проверяется, является ли $a экземпляром класса $b.
Крайние случаи и подводные камни
instanceof никогда не выбрасывает исключений и не генерирует предупреждений. Если левый операнд не является объектом, оператор просто возвращает false.
<?php
class Fruit {}
var_dump(null instanceof Fruit); // bool(false)
var_dump("Fruit" instanceof Fruit); // bool(false) — a string is not an object
var_dump(42 instanceof Fruit); // bool(false)Это делает instanceof безопасным для использования в качестве защитной проверки перед вызовом метода — без необходимости предварительно вызывать is_object(). Если нужно только проверить, является ли значение объектом любого класса, используйте is_object().
Один тонкий момент: если передать несуществующее имя класса как строковый литерал в правой части, PHP не выполняет автозагрузку и не генерирует ошибку — просто возвращает false. Опечатка в имени класса провалится молча. По возможности предпочитайте прямое указание имени класса ($x instanceof Fruit) — тогда парсер сможет его проверить.
Когда использовать instanceof — и когда нет
Используйте instanceof, когда у вас действительно есть значение, тип которого нельзя гарантировать: данные из json_decode, смешанная коллекция, плагин из пользовательского кода или блок catch, сужающий тип исключения.
<?php
try {
throw new InvalidArgumentException("bad input");
} catch (Exception $e) {
if ($e instanceof InvalidArgumentException) {
echo "Caught an argument error: " . $e->getMessage();
}
}
// Output: Caught an argument error: bad inputНе стоит разбрасывать проверки instanceof по всему коду для ветвления по типу — длинные цепочки if ($x instanceof A) … elseif ($x instanceof B) обычно сигнализируют о том, что лучше определить метод в каждом классе и вызывать его полиморфно. Используйте instanceof для защиты операции, а не в качестве замены наследованию.
Краткое резюме
$object instanceof ClassNameвозвращаетtrue, если объект является экземпляром класса, подкласса или реализованного интерфейса.- Оператор обходит всю цепочку наследования и сопоставляет интерфейсы — именно это делает его мощным инструментом.
- Он возвращает
false(но никогда не ошибку) дляnull, скалярных значений и прочих не-объектов, поэтому безопасен как защитная проверка. - Несуществующее имя класса в виде строки возвращает
falseбез предупреждения; предпочитайте прямое указание имени класса. - Применяйте его для проверки типа неизвестного значения перед операцией — не как замену полиморфизму.