PHP: полный мануал с примерами, функциями и ООП
Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Дерево руководства
Глава 68 · От первого объекта к диагностике
Информация о классах и объектах: полный справочник функций
Узнать тип и происхождение объекта, проверить объявление и доступность, отличить исходные настройки от текущих данных и безопасно исследовать структуру программы.
Узнать, какой объект пришёл в обработчик
Объект и имя его класса — разные значения
Создадим Delivery и получим строковое имя для понятной диагностической записи.
- 1class Delivery {}↓
Объявлено описание класса; экземпляра пока нет.
- 2$delivery = new Delivery↓
Создан один объект, доступный через переменную.
- 3get_class($delivery)↓
Функция получает объект и возвращает строку Delivery.
- 4$name = …↓
Имя сохранено в новой переменной. Объект не изменён.
- 5echo $name
На экране Delivery; имя помогает диагностике, а не проверке прав.
Имя класса не равно ID экземпляра и не доказывает доступность каждого его метода. Эти вопросы разбираются отдельными функциями.
Обработчик получил настройки, но для диагностики надо понять, относятся они к каталогу или доставке. Получим две строки с фактическими именами классов. Никаких сетевых запросов имя класса не выполняет.
class CatalogOptions {} объявляет вид объекта; пустые фигурные скобки означают отсутствие собственных полей и методов. new создаёт экземпляр. Параметр object $options допускает любой объект, а get_class($options) получает его имя строкой. return возвращает сообщение; точка соединяет строки. Для обычной операции предпочтительнее конкретный интерфейс, а здесь широкий object нужен именно диагностике.
Сначала можно пройти карточку товара и аргументы и результат функции. Имя класса не доказывает правильность настройки, наличие соединения или права пользователя.
<?php
declare(strict_types=1);
class DeliveryOptions {}
class CatalogOptions {}
function describeInput(object $options): string
{
return 'Обработчик получил: ' . get_class($options);
}
echo describeInput(new CatalogOptions()), "\n";
echo describeInput(new DeliveryOptions()), "\n";
Ожидаемый результат
Обработчик получил: CatalogOptions
Обработчик получил: DeliveryOptions
get_class возвращает имя реального класса экземпляра. Так видно, какой объект передан в ошибочном месте. Для ограничения рабочего входа лучше конкретный тип или интерфейс в параметре: диагностическое имя не заменяет договор и авторизацию.
Если слово «объект» пока не связано с задачей, пройдите два отдельных экземпляра и их данные. В этой главе функции исследуют уже описанные классы; они не заменяют урок создания класса, методов и свойств. Для вызова, параметра и результата есть начальная ступень.
Сначала сформулировать вопрос, затем выбрать функцию
| Вопрос | Функции | Чего результат не обещает |
|---|---|---|
| Что это за экземпляр? | get_class, get_parent_class | Имя не равно праву на действие и не является постоянным ID объекта |
| Описан ли тип? | class_exists, interface_exists, trait_exists, enum_exists | Наличие не означает возможность new, совместимый конструктор или рабочую сеть |
| Подходит ли тип? | is_a, is_subclass_of | Интерфейс задаёт программный контракт, не авторизацию пользователя |
| Объявлен ли член? | method_exists, property_exists | Объявленное может быть private, неинициализированным или нечитабельным |
| Какие данные доступны? | get_object_vars, get_class_vars | Текущие значения экземпляра и исходные значения класса различаются |
| Что загружено в текущем процессе? | get_declared_classes, get_declared_interfaces, get_declared_traits | Это не полный каталог файлов и установленных Composer-пакетов |
| От какого класса пришёл статический вызов? | get_called_class | Это другой вопрос, чем место объявления метода |
| Как временно поддержать прежнее имя? | class_alias | Псевдоним не создаёт независимый тип или новое поведение |
Существование, доступность, значение и право пользователя — четыре разных проверки. Для известного контракта параметр интерфейсного типа и обычный вызов часто яснее, чем поиск имён методов. Для диагностики дополнительных признаков подходят Reflection и объявивший метод класс.
Строка имени, импорт use и автозагрузка
Имя класса в коде и произвольная строка — разные вещи. Запись PaymentClient::class даёт корректное имя с учётом namespace/use, но сама не загружает класс и не вызывает конструктор. class_exists обычно может вызвать автозагрузчик, если имя ещё неизвестно; false во втором аргументе запрещает именно эту попытку. Такой false не доказывает, что пакета нет на диске.
- Имя уже объявлено → ответ true без создания экземпляра
- Имя неизвестно → зарегистрированному autoloader передаётся это имя
- Загрузчик может подключить PHP-файл; его верхний уровень исполняется
- Если тип объявлен, проверка возвращает true; иначе false, если загрузчик не выбросил ошибку
Этот процесс объясняет, почему проверка иногда не является «чистым чтением». Исключение или ошибка внутри autoloader не превращается автоматически в false. Имена из HTTP не следует напрямую использовать для new или require: сначала выбирают разрешённую операцию из собственной карты. Путь файлов и PSR-4 разобраны в Composer и автозагрузке.
<?php
declare(strict_types=1);
namespace Demo\Shipping {
class Client {}
}
namespace Demo\Report {
use Demo\Shipping\Client as DeliveryClient;
echo 'Полное имя: ', DeliveryClient::class, "\n";
echo class_exists(DeliveryClient::class, false) ? "Клиент уже загружен\n" : "Определения пока нет\n";
echo class_exists('DeliveryClient', false) ? "Короткая строка найдена\n" : "Импорт не применяется к произвольной строке\n";
}
Ожидаемый результат
Полное имя: Demo\Shipping\Client
Клиент уже загружен
Импорт не применяется к произвольной строке
use задаёт соответствие имени при разборе PHP-кода. Строка "DeliveryClient" не проходит такую подстановку. ::class получает корректное полное имя, но само по себе не запускает конструктор и не требует автозагрузки. Второй аргумент false запрещает попытку автозагрузки этой проверки.
Читать описание класса и состояние объекта отдельно
В книге PHP.net общий пример соединяет базовый класс, потомка, свойства и методы. Ниже тот же учебный приём на собственном примере доставки: класс задаёт начальную стоимость, экземпляр меняет её, а диагностика показывает разницу. Это локальные условные числа, не реальное списание денег.
- Delivery описывает default feeKopecks = 30000 и метод label
- ExpressDelivery расширяет Delivery; создан отдельный объект
- Его feeKopecks меняют на 50000: описание default остаётся 30000
- get_class_vars читает defaults; get_object_vars читает доступное текущее состояние
<?php
declare(strict_types=1);
class Delivery
{
public int $feeKopecks = 30000;
public function label(): string { return 'Доставка'; }
}
class ExpressDelivery extends Delivery {}
$delivery = new ExpressDelivery();
$delivery->feeKopecks = 50000;
$defaults = get_class_vars(Delivery::class);
$current = get_object_vars($delivery);
echo 'Исполнитель: ', get_class($delivery), "\n";
echo 'Родитель: ', get_parent_class($delivery), "\n";
echo 'По умолчанию: ', $defaults['feeKopecks'], " коп.\n";
echo 'Для этого заказа: ', $current['feeKopecks'], " коп.\n";
Ожидаемый результат
Исполнитель: ExpressDelivery
Родитель: Delivery
По умолчанию: 30000 коп.
Для этого заказа: 50000 коп.
get_class_vars читает доступные начальные значения класса, get_object_vars — доступные текущие свойства экземпляра. Состав зависит от области видимости. Это не универсальный дамп всего внутреннего состояния и не вызов виртуальных свойств через __get.
Упражнение: добавьте второй экземпляр ExpressDelivery, не меняйте его feeKopecks и сравните результаты. Ожидается 50000 копеек у первого, 30000 у второго и default 30000. Затем добавьте private-поле: внешний get_object_vars его не покажет. Это граница текущей области доступа, а не пропавшее значение. Разбор полей и hooks находится в карточках get_object_vars и get_mangled_object_vars.
Доступность, версии и цена исследования
Сигнатура — краткий контракт вызова. object требует экземпляр, string — строку, object|string разрешает оба варианта; bool обозначает true/false, array — массив. $autoload = true задаёт значение при пропуске аргумента. Запись = ? в двух исторических сигнатурах означает специальное отсутствие аргумента, а не значение, которое нужно печатать в своём коде. Не передавайте null вместо пропущенного аргумента. Общая механика разобрана в параметрах и возвращаемом результате.
В примерах с declare(strict_types=1) неподходящие типы скалярных параметров встроенных функций приводят к TypeError; в слабом режиме некоторые скаляры могут преобразоваться, а null у ненулевых встроенных параметров deprecated с PHP 8.1. Специальные старые разборщики имени класса имеют отдельные границы, указанные в карточках. Отсутствующий обязательный аргумент или лишний аргумент встроенной функции обычно даёт ArgumentCountError. Это ошибка вызова, а не отрицательный результат проверки. Не ловите все Throwable ради false: так можно скрыть сбой подключаемого файла.
Эти функции относятся к PHP Core: отдельная установка PECL, Composer или настройка подключения расширения не нужна. У книги нет отдельных страниц setup, configuration или constants; свои INI-режимы для неё не придуманы. Ограничения управляемой среды и общая настройка disable_functions рассматриваются отдельно в настройке PHP. Наличие функции не отменяет требований версии: enum_exists требует PHP 8.1, get_mangled_object_vars — 7.4; поддержка alias встроенного класса появилась в 8.3.
Вызовы get_class() и get_parent_class() без аргумента устарели с PHP 8.3. Старый __autoload удалён в PHP 8.0, поэтому его карточка показывает миграцию, а не действующий шаблон. Неопределённое имя у проверок *_exists обычно даёт false, но у get_class_methods/get_class_vars/get_parent_class в современном PHP может быть TypeError. Ошибки автозагрузки проходят наружу.
Перечисление всех классов/методов/полей строит массив, который занимает память. Повторять его для каждого товара в большом цикле обычно незачем: описание схемы можно вычислить в нужной области и переиспользовать. Не кешируйте доступность без учёта scope и не храните «все объявления» как вечный список при динамической загрузке. Для PHP 8.4+ hooks и lazy-инициализаторы могут добавить выполнение кода при чтении свойств; это важнее неподтверждённых обещаний, какая проверка «быстрее».
Вся категория: точные карточки и соседние инструменты
| Функция | Для чего открыть |
|---|---|
__autoload | Узнать удалённый механизм автозагрузки в старом проекте и заменить его современной регистрацией загрузчика. |
class_alias | Временно поддержать старое имя класса при переименовании, сохранив тот же тип. |
class_exists | Проверить, объявлен ли класс, при необходимости дав автозагрузчику найти его файл. |
enum_exists | Проверить, что имя относится именно к перечислению, а не к обычному классу. |
get_called_class | Получить класс, от имени которого продолжается поздно связанный статический вызов. |
get_class | Получить имя класса уже созданного объекта для диагностики. |
get_class_methods | Получить имена методов, доступных из текущей области, чтобы исследовать установленный клиент. |
get_class_vars | Посмотреть доступные исходные значения свойств класса, не создавая объект и не запуская конструктор. |
get_declared_classes | Получить снимок классов, уже известных текущему PHP-процессу. |
get_declared_interfaces | Исследовать интерфейсы, объявленные к текущему моменту выполнения. |
get_declared_traits | Получить имена трейтов, уже объявленных в этом процессе. |
get_mangled_object_vars | Исследовать сырое хранилище объекта, включая закрытые поля и их владельцев. |
get_object_vars | Получить доступные текущие не-static свойства конкретного объекта как массив. |
get_parent_class | Узнать непосредственного родителя объекта или класса, например при исследовании расширения. |
interface_exists | Проверить именно объявление интерфейса, например при поддержке необязательного пакета. |
is_a | Проверить, является ли объект или разрешённое имя данным типом, включая сам тип и его потомков. |
is_subclass_of | Проверить наследование или реализацию интерфейса, исключив совпадение с самим исходным типом. |
method_exists | Узнать, объявлен ли метод, не смешивая это с возможностью и разрешением его вызвать. |
property_exists | Проверить наличие свойства, даже если оно содержит null или ещё не инициализировано. |
trait_exists | Узнать, объявлен ли трейт, не путая наличие трейта с его использованием конкретным классом. |
Часть карточек уже использовалась в прикладных главах; их прежние адреса сохранены. Ссылки выше ведут к тем же дополненным карточкам. class_parents, class_implements, class_uses и spl_object_id принадлежат SPL; ReflectionClass и ReflectionProperty — отдельной книге Reflection. Они связаны с задачей, но не подменяют официальный список этой категории.
Исследование не должно подменять нормальный вызов
Для диагностики полезны имя класса, перечень доступных членов и проверка загруженности. Для обычной доставки надёжнее передать DeliveryCalculator в типизированный параметр и вызвать calculate. method_exists не доказывает допустимость внешнего вызова; is_callable учитывает свой договор, включая магические вызовы. Полные карточки ниже сохраняют параметры, возвраты и ограничения каждой функции.
Попробуйте. У delivery переопределите текущее feeKopecks, затем сравните get_class_vars и get_object_vars.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
get_parent_classУзнать непосредственного родителя объекта или класса, например при исследовании расширения.
PHP 4+ · Core
get_parent_class(object|string $object_or_class = ?): string|falseУзнать непосредственного родителя объекта или класса, например при исследовании расширения.
- ExpressDelivery наследует Courier
- Courier наследует Delivery
- get_parent_class(ExpressDelivery::class) возвращает Courier, один шаг вверх
| Вход / результат | Точный смысл |
|---|---|
| $object_or_class | Экземпляр или полное имя существующего класса. Строка может вызвать автозагрузку. |
| Результат | Имя только непосредственного родителя; false, если родительского класса нет. Реализованные интерфейсы сюда не входят. |
| Без аргумента | Берёт контекст класса вызова; deprecated с PHP 8.3. Вне класса без аргумента возвращает false с диагностикой deprecated. |
| Ошибки | В PHP 8 неизвестное имя не является допустимым классом: TypeError. Ошибки autoloader могут пройти наружу. Старое описание false для отсутствующего класса нельзя переносить на PHP 8. |
extends объявляет наследование; ::class получает строку имени. Это инструмент объяснения происхождения, а не доказательство совместимости бизнес-поведения.
<?php
declare(strict_types=1);
class Delivery {}
class Courier extends Delivery {}
class ExpressDelivery extends Courier {}
echo get_parent_class(ExpressDelivery::class), "\n";
var_dump(get_parent_class(Delivery::class));
Ожидаемый результат
Courier
bool(false)
У самого Delivery родителя нет. var_dump показывает логическое false, которое echo было бы трудно заметить.
<?php
declare(strict_types=1);
class Importer {}
class FileImporter extends Importer {}
class CsvImporter extends FileImporter {}
$name = CsvImporter::class;
$chain = [$name];
while (($parent = get_parent_class($name)) !== false) {
$chain[] = $parent;
$name = $parent;
}
echo implode(' -> ', $chain), "\n";
Ожидаемый результат
CsvImporter -> FileImporter -> Importer
while повторяет шаг, пока найден родитель. !== false отличает окончание цепочки от имени; [] дописывает элемент. Начальная строка взята из известного класса, а не из HTTP. Для готового списка предков есть SPL class_parents; интерфейсы перечисляет class_implements.
<?php
declare(strict_types=1);
try {
get_parent_class('MissingImporter');
} catch (TypeError $error) {
echo "В конфигурации нет такого класса\n";
}
Ожидаемый результат
В конфигурации нет такого класса
try/catch здесь специально показывает современный сбой контракта. В обычной конфигурации проверяйте разрешённую карту обработчиков при запуске; не скрывайте так произвольные ошибки их конструктора.
Рядом: get_class, is_subclass_of, class_exists. Как выбрать проверку.
get_called_classПолучить класс, от имени которого продолжается поздно связанный статический вызов.
PHP 5.3+ · Core
get_called_class(): stringПолучить класс, от имени которого продолжается поздно связанный статический вызов.
- CsvReport::label() вызывает унаследованный метод
- Метод объявлен в Report, но called class — CsvReport
- Строка CsvReport попадает в диагностическую подпись
| Вход / результат | Точный смысл |
|---|---|
| Параметры | Нет. Это не функция с объектом или строкой имени на входе. |
| Результат | Имя called class; в статическом методе обычно то же имя, что static::class. Место объявления может быть другим. |
| Ошибки / версии | Доступна с PHP 5.3. Вне классового контекста с PHP 8 выбрасывает Error; раньше warning и false. |
Двойное двоеточие выбирает статический метод класса. Такой метод работает без new; внутри него нет $this. Унаследованный код может сохранять информацию, какой потомок начал вызов.
<?php
declare(strict_types=1);
class Report
{
public static function label(): void
{
echo self::class, ' / ', get_called_class(), "\n";
}
}
class CsvReport extends Report {}
CsvReport::label();
Ожидаемый результат
Report / CsvReport
self::class фиксирован местом объявления. get_called_class читает текущий контекст позднего связывания, а не имя файла и не весь стек.
<?php
declare(strict_types=1);
class Report
{
protected static function auditLabel(): string
{
return 'Сборка ' . get_called_class();
}
public static function build(): string
{
return static::auditLabel();
}
}
class SalesReport extends Report {}
class StockReport extends Report {}
echo SalesReport::build(), "\n";
echo StockReport::build(), "\n";
Ожидаемый результат
Сборка SalesReport
Сборка StockReport
Общий код получает нужную подпись для двух отчётов. Вызов static::auditLabel сохраняет late binding. Здесь нет файла журнала и секретных данных; реальный журнал передавайте отдельной зависимостью.
Не считайте это универсальным «кто меня вызвал»: явный нефоровардинг-вызов другого класса может изменить called class; parent::/self:: и static:: имеют правила позднего связывания. Если нужен путь выполнения, используйте debugger или безопасный backtrace. Разбор: статические вызовы и позднее связывание.
Рядом: get_class, get_parent_class. Как выбрать проверку.
is_aПроверить, является ли объект или разрешённое имя данным типом, включая сам тип и его потомков.
PHP 4.2+ · Core
is_a(mixed $object_or_class, string $class, bool $allow_string = false): boolПроверить, является ли объект или разрешённое имя данным типом, включая сам тип и его потомков.
- Объект Courier реализует Delivery
- is_a($courier, Delivery::class) проверяет отношение типов
- true позволяет выбрать ветку, но не даёт пользователю право оформлять заказ
| Вход / результат | Точный смысл |
|---|---|
| $object_or_class | Обычно объект. Строка рассматривается как имя типа только при allow_string=true; прочие неподходящие значения дают false. |
| $class | Имя проверяемого класса или интерфейса. Импорт use к строке в кавычках не применяется; используйте ::class. |
| $allow_string | По умолчанию false. true разрешает строку первым аргументом и возможную автозагрузку этого имени. |
| Результат / ошибки | true для самого типа, наследника или реализации интерфейса; иначе false. Ошибка загрузчика не гарантированно превращается в false. Имена типов сравниваются без учёта регистра. |
Проверка интерфейса удобна на границе, где получено неизвестное значение. Внутри заранее известной системы параметр типа Delivery обычно делает ту же гарантию понятнее, ещё до тела функции.
<?php
declare(strict_types=1);
interface Delivery {}
class Courier implements Delivery {}
$delivery = new Courier;
var_dump(is_a($delivery, Delivery::class));
var_dump(is_a($delivery, Courier::class));
Ожидаемый результат
bool(true)
bool(true)
implements означает выполнение интерфейсного контракта. Для известного объекта оператор $delivery instanceof Delivery часто проще. is_a полезна, когда имя целевого типа хранится в переменной.
<?php
declare(strict_types=1);
interface Exporter { public function export(): string; }
class CsvExporter implements Exporter
{
public function export(): string { return "Название;Цена\nЧай;25900"; }
}
$formats = ['csv' => CsvExporter::class];
$selected = $formats['csv'];
if (!is_a($selected, Exporter::class, true)) { throw new LogicException('Неподходящий экспортёр'); }
echo (new $selected())->export(), "\n";
Ожидаемый результат
Название;Цена
Чай;25900
Третий аргумент true разрешает строковое имя класса. По умолчанию is_a не проверяет такую строку как экземпляр. Имя берётся из своей карты, а не из URL. Проверка соответствия интерфейсу не заменяет авторизацию пользователя на сам экспорт.
Если цель — только наследник без самого базового класса, нужна is_subclass_of. Не включайте allow_string лишь ради «чтобы работало» для свободного ввода: автозагрузчик выполняет PHP-код. Проверка принадлежности типа не проверяет пользовательские права и состояние внешнего сервиса.
Рядом: is_subclass_of, class_exists, interface_exists. Как выбрать проверку.
class_aliasВременно поддержать старое имя класса при переименовании, сохранив тот же тип.
PHP 5.3+; internal classes PHP 8.3+ · Core
class_alias(string $class, string $alias, bool $autoload = true): boolВременно поддержать старое имя класса при переименовании, сохранив тот же тип.
- Класс ShippingClient уже содержит реализацию
- class_alias связывает старое имя DeliveryClient с тем же типом
- new DeliveryClient создаёт ShippingClient; отдельного класса-потомка не появляется
| Вход / результат | Точный смысл |
|---|---|
| $class | Имя исходного существующего класса. Допускаются также интерфейсы, трейты и enum как именованные типы. |
| $alias | Новое имя-псевдоним, включая namespace при необходимости; это строка, use к ней не применяется. |
| $autoload | При true (default) PHP пробует загрузить исходный тип. false разрешает только уже объявленный. |
| Результат | true при регистрации, false с E_WARNING, если исходный тип не найден или имя уже занято. Псевдоним регистрируется в нижнем регистре; типы регистронезависимы. |
| Версии / ограничения | Функция с PHP 5.3. Встроенные классы разрешены с PHP 8.3. Зарезервированные имена вроде self запрещены и могут завершить выполнение фатально; используйте фиксированные корректные имена. |
Псевдоним полезен как миграционный мост: старый код продолжает загружаться, пока вызовы переводят на новое имя. Он не оборачивает методы и не отделяет настройки экземпляров от исходного класса.
<?php
declare(strict_types=1);
class ShippingClient
{
public function label(): string { return 'Доставка заказа готова'; }
}
if (!class_alias(ShippingClient::class, 'DeliveryClient', false)) {
throw new RuntimeException('Не удалось зарегистрировать старое имя');
}
$legacyClient = new DeliveryClient();
echo $legacyClient->label(), "\n";
echo 'Реальный класс: ', get_class($legacyClient), "\n";
Ожидаемый результат
Доставка заказа готова
Реальный класс: ShippingClient
class_alias регистрирует второе имя того же класса. Старый код может создавать DeliveryClient, но объект имеет исходную идентичность класса ShippingClient. Это не наследование и не новая реализация. Третий false запрещает попытку автозагрузки исходного имени.
<?php
declare(strict_types=1);
namespace Shop\Shipping { class Client {} }
namespace {
$legacy = 'LegacyDeliveryClient';
if (!class_exists($legacy, false)) {
class_alias(\Shop\Shipping\Client::class, $legacy, false);
}
$client = new LegacyDeliveryClient;
echo get_class($client), "\n";
var_dump(is_subclass_of($client, \Shop\Shipping\Client::class));
}
Ожидаемый результат
Shop\Shipping\Client
bool(false)
Проверка предотвращает повторную регистрацию в этом учебном bootstrap. В реальном проекте имя может быть занято чужим типом: не продолжайте молча, а проверьте контракт и завершите настройку с понятной ошибкой. Это не наследование, поэтому is_subclass_of относительно исходного типа даёт false.
<?php
declare(strict_types=1);
set_error_handler(static function (int $level, string $message): bool {
echo $level === E_WARNING ? "warning\n" : "другая ошибка\n";
return true;
});
try {
var_dump(class_alias('MissingClient', 'LegacyClient', false));
} finally {
restore_error_handler();
}
Ожидаемый результат
warning
bool(false)
Пример намеренно подавляет стандартный текст только в собственном временном обработчике, затем обязательно восстанавливает его. Нельзя принимать warning за успешный alias. Не регистрируйте псевдонимы из пользовательского ввода.
Рядом: class_exists, get_class, is_subclass_of. Как выбрать проверку.
get_class_methodsПолучить имена методов, доступных из текущей области, чтобы исследовать установленный клиент.
PHP 4+ · Core
get_class_methods(object|string $object_or_class): arrayПолучить имена методов, доступных из текущей области, чтобы исследовать установленный клиент.
| Вход / результат | Точный смысл |
|---|---|
| $object_or_class | Объект или полное имя существующего класса; строка может включить автозагрузку. |
| Результат | Массив имён методов, в том числе унаследованных доступных методов. Параметры, return-типы и исходный код в него не входят. |
| Область доступа | Снаружи видны public, из класса могут быть видны его private/protected. Динамические имена, обслуживаемые __call, не перечисляются. |
| Ошибки / версии | Неверный объект/имя, включая неизвестный класс, в PHP 8 приводит к TypeError. Методам не передаются аргументы и их тела не выполняются; загрузчик может выполняться. |
Массив — список строк, а не набор callable. sort ниже нужен только для устойчивого порядка вывода: список исследования не должен зависеть от порядка объявления в исходном файле.
<?php
declare(strict_types=1);
class Client
{
public function listOrders(): array { return []; }
private function token(): string { return 'demo'; }
}
$methods = get_class_methods(Client::class);
sort($methods);
echo implode(', ', $methods), "\n";
Ожидаемый результат
listOrders
Метод token объявлен, но недоступен внешнему коду. Строка listOrders не означает, что запрос был отправлен: тело метода вообще не запускалось.
<?php
declare(strict_types=1);
class BaseClient { public function ping(): void {} }
class Client extends BaseClient
{
private function sign(): void {}
public static function internalNames(): array
{
$names = get_class_methods(self::class);
sort($names);
return $names;
}
}
$outside = get_class_methods(Client::class);
sort($outside);
echo implode(', ', $outside), "\n";
echo implode(', ', Client::internalNames()), "\n";
Ожидаемый результат
internalNames, ping
internalNames, ping, sign
Внутренний вызов выполняется в области Client и видит sign. ping пришёл от родителя. Поэтому кеш такого списка, построенный внутри класса, нельзя бездумно выдавать как внешнее API.
Для документации с параметрами переходите к ReflectionMethod и исследованию клиента. Для известной операции используйте интерфейс и прямой вызов. Не превращайте этот список в публичный HTTP-диспетчер: существование метода не проверяет права пользователя.
Рядом: method_exists, get_class, class_exists. Как выбрать проверку.
get_class_varsПосмотреть доступные исходные значения свойств класса, не создавая объект и не запуская конструктор.
PHP 4+ · Core
get_class_vars(string $class): arrayПосмотреть доступные исходные значения свойств класса, не создавая объект и не запуская конструктор.
- Delivery задаёт fee=300 по умолчанию
- У экземпляра fee уже 700; static count изменён отдельно
- get_class_vars возвращает первоначальные значения описания класса
| Вход / результат | Точный смысл |
|---|---|
| $class | Полное имя класса, только строка. Для объекта сначала get_class или $object::class. Неизвестное имя может включить autoload. |
| Результат | Ассоциативный массив propertyName => defaultValue для видимых из текущей области свойств; включаются доступные static. Это defaults, а не текущее значение static. |
| Scope / значения | Снаружи доступны public; внутри собственной области также private/protected. Неназначенное нетипизированное поле имеет null; typed без значения здесь представлено null, хотя читать его у экземпляра нельзя. |
| Ошибки / PHP 8.4 | В PHP 8 неизвестный класс — TypeError; объект вместо строки не является допустимым входом (может дать Error преобразования). Virtual hook-свойство не имеет default storage и не включается; backed берётся без выполнения getter. |
Функция помогает проверить настройку простого класса. Она не заменяет схему валидации или конструктор: defaults не описывают все ограничения, обязательность и правила изменения.
<?php
declare(strict_types=1);
class Delivery
{
public $fee = 300;
public static $count = 0;
}
$delivery = new Delivery;
$delivery->fee = 700;
Delivery::$count = 2;
$defaults = get_class_vars(Delivery::class);
echo $defaults['fee'], ' / ', $defaults['count'], "\n";
echo $delivery->fee, ' / ', Delivery::$count, "\n";
Ожидаемый результат
300 / 0
700 / 2
::$count читает общее static-свойство. get_class_vars возвращает default 0, а не текущие 2. ->fee относится к конкретному экземпляру.
<?php
declare(strict_types=1);
class ExportSettings
{
public $format = 'csv';
private $separator = ';';
public static function defaultSeparator(): string
{
$defaults = get_class_vars(self::class);
return $defaults['separator'];
}
}
$outside = get_class_vars(ExportSettings::class);
echo implode(', ', array_keys($outside)), "\n";
echo ExportSettings::defaultSeparator(), "\n";
Ожидаемый результат
format
;
Внутри класса доступен его private default. В реальном экспортере обычный метод или константа чаще яснее отражения всех полей; пример объясняет область доступа и почему результаты двух вызовов отличаются.
<?php
declare(strict_types=1);
class Order { public int $number; }
$defaults = get_class_vars(Order::class);
echo $defaults['number'] === null ? "В описании нет присвоенного начального номера\n" : "Начальный номер задан\n";
$order = new Order();
$property = new ReflectionProperty(Order::class, 'number');
echo $property->isInitialized($order) ? "Номер можно читать\n" : "Экземпляр ещё требует инициализации номера\n";
Ожидаемый результат
В описании нет присвоенного начального номера
Экземпляр ещё требует инициализации номера
get_class_vars представляет такое поле через null в своём массиве, но int-свойство экземпляра не получило null и не стало читаемым. Для конкретного экземпляра используйте isInitialized, а обязательные данные передавайте конструктору.
Не применяйте функцию в каждой итерации по заказам: описание одного класса не меняется от заказа к заказу. Для подробной схемы используйте ReflectionProperty; для текущих значений public-свойств экземпляра — get_object_vars. Массив defaults не является безопасным набором разрешённых полей HTTP.
Рядом: get_object_vars, get_class, property_exists. Как выбрать проверку.
get_mangled_object_varsИсследовать сырое хранилище объекта, включая закрытые поля и их владельцев.
PHP 7.4+ · Core
get_mangled_object_vars(object $object): arrayИсследовать сырое хранилище объекта, включая закрытые поля и их владельцев.
- Parent и Child имеют разные private-поля с одинаковым простым именем
- В хранилище ключ включает имя объявившего класса
- Сырые ключи различают поля; удаление префикса потеряет это различие
| Вход / результат | Точный смысл |
|---|---|
| $object | Любой объект; неподходящий тип — TypeError. Функция доступна с PHP 7.4. |
| Результат | Массив хранимых не-static свойств независимо от visibility; typed без значения пропускаются. Public-ключ обычный, protected начинается с NUL * NUL, private — NUL DeclaringClass NUL. |
| NUL / вложенность | NUL — байт 0, не четыре печатных символа \0. Вложенные объекты остаются теми же объектами: глубокого клонирования нет. |
| PHP 8.4 | Не вызывает get hooks и не включает virtual-свойства без хранилища. Сам по себе не инициализирует lazy-объект; результат может быть пустым/частичным. |
Это низкоуровневая диагностика собственного контролируемого объекта. Private ограничивает обычный доступ, но не шифрует значение. Не используйте функцию как короткий способ «вывести объект в JSON» или записать его целиком в журнал.
<?php
declare(strict_types=1);
class Delivery
{
public $label = 'Курьер';
protected $zone = 'A';
private $cost = 300;
}
$values = get_mangled_object_vars(new Delivery);
foreach ($values as $key => $value) {
echo str_replace("\0", '|', $key), '=', $value, "\n";
}
Ожидаемый результат
label=Курьер
|*|zone=A
|Delivery|cost=300
Замена NUL на | нужна только для видимого учебного вывода; это не безопасная сериализация. Обычный внешний get_object_vars вернул бы только label.
<?php
declare(strict_types=1);
class BaseClient { private $mode = 'base'; }
class ReportClient extends BaseClient { private $mode = 'report'; }
$values = get_mangled_object_vars(new ReportClient);
echo $values["\0BaseClient\0mode"], "\n";
echo $values["\0ReportClient\0mode"], "\n";
Ожидаемый результат
base
report
Класс-владелец является частью ключа. Если отрезать префикс и оставить mode, одно значение перезапишет другое. Для конвертации в модель пишите явное отображение полей, а не угадывайте структуру чужого объекта.
<?php
declare(strict_types=1);
class Label
{
public string $text = 'shop' {
get => strtoupper($this->text);
}
public string $caption { get => 'Заголовок'; }
}
$label = new Label;
$raw = get_mangled_object_vars($label);
echo $raw['text'], "\n";
echo implode(', ', array_keys($raw)), "\n";
echo get_object_vars($label)['text'], "\n";
Ожидаемый результат
shop
text
SHOP
PHP 8.4+. text имеет хранилище и getter; raw читает shop напрямую. caption — virtual и в raw отсутствует. Высокоуровневый get_object_vars читает вычисляемое SHOP. Выбирать нужно нужный смысл данных, а не «короткую функцию».
<?php
declare(strict_types=1);
class Order { public int $number; }
$order = (new ReflectionClass(Order::class))->newLazyGhost(
static function (Order $order): void { $order->number = 41; }
);
var_dump(property_exists($order, 'number'));
var_dump(get_mangled_object_vars($order));
echo get_object_vars($order)['number'], "\n";
Ожидаемый результат
bool(true)
array(0) {
}
41
PHP 8.4+. Структура number уже существует, но значение ещё не загружено. Сырой снимок не запускает initializer. get_object_vars после этого запрашивает значения и инициализирует объект.
Рядом: get_object_vars, get_class_vars, property_exists. Как выбрать проверку.
interface_existsПроверить именно объявление интерфейса, например при поддержке необязательного пакета.
PHP 5.0.2+ · Core
interface_exists(string $interface, bool $autoload = true): boolПроверить именно объявление интерфейса, например при поддержке необязательного пакета.
- Пакет может объявить PaymentGateway
- interface_exists узнаёт, доступно ли описание контракта
- is_a($client, PaymentGateway::class) отдельно проверяет конкретного исполнителя
| Вход / результат | Точный смысл |
|---|---|
| $interface | Полное имя интерфейса; сопоставление объявленных имён нечувствительно к регистру. |
| $autoload | true разрешает автозагрузку неизвестного имени, false проверяет только уже объявленное. |
| Результат / ошибки | true только для интерфейса. Существование класса с таким именем не подходит. Ошибки autoloader не поглощаются. |
| Версия / граница | PHP 5.0.2+. Не проверяет, что конкретный объект implements этот интерфейс; это задача instanceof/is_a. |
Интерфейс описывает обязательные методы без создания объекта. Условная проверка полезна на границе совместимости пакетов; внутри своего приложения зависимость обычно объявляют явно и считают обязательной.
<?php
declare(strict_types=1);
interface Delivery {}
class Courier implements Delivery {}
var_dump(interface_exists(Delivery::class, false));
var_dump(interface_exists(Courier::class, false));
var_dump(class_exists(Delivery::class, false));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
Имя класса и имя интерфейса относятся к разным видам объявления. Наличие Courier не превращает его имя в интерфейс.
<?php
declare(strict_types=1);
$contract = 'OptionalVendor\\AuditSink';
if (interface_exists($contract, false)) {
echo "Контракт внешнего аудита загружен\n";
} else {
echo "Работаем с локальным учебным журналом\n";
}
Ожидаемый результат
Работаем с локальным учебным журналом
Имя вымышленное, режим выбран сознательно. false означает «ещё не объявлен», а не «не установлен». Если подключён Composer и разрешена загрузка, используйте default true. Для обязательного аудита нельзя молча выбирать запасной режим: завершите настройку с понятной ошибкой.
Рядом: class_exists, is_a, get_declared_interfaces. Как выбрать проверку.
trait_existsУзнать, объявлен ли трейт, не путая наличие трейта с его использованием конкретным классом.
PHP 5.4+ · Core
trait_exists(string $trait, bool $autoload = true): boolУзнать, объявлен ли трейт, не путая наличие трейта с его использованием конкретным классом.
- trait DemoLog содержит общий метод
- trait_exists(DemoLog::class) проверяет наличие этого набора реализации
- Использование use DemoLog в Client — отдельный факт о Client
| Вход / результат | Точный смысл |
|---|---|
| $trait | Имя трейта с namespace; объявленные имена проверяются без учёта регистра. |
| $autoload | true разрешает загрузку, false смотрит только текущие объявления. |
| Результат / ошибки | true для трейта, false для других видов/отсутствия. Ошибка загрузчика может прервать проверку. |
| Версия / граница | PHP 5.4+. Трейт не является типом объекта для is_a/instanceof; он добавляет реализацию в классы при их объявлении. |
Эта проверка нужна диагностике библиотек, а не каждому вызову метода. Если класс уже объявлен с use, реализация встроена в его состав; менять набор трейтов объекта во время работы таким способом нельзя.
<?php
declare(strict_types=1);
trait DemoLog { public function label(): string { return 'demo'; } }
class Client { use DemoLog; }
var_dump(trait_exists(DemoLog::class, false));
var_dump(class_exists(DemoLog::class, false));
echo (new Client)->label(), "\n";
Ожидаемый результат
bool(true)
bool(false)
demo
use внутри класса включает методы трейта. Это другое употребление use, чем импорт имени namespace.
<?php
declare(strict_types=1);
trait DemoLog {}
class LoggedClient { use DemoLog; }
class PlainClient {}
var_dump(trait_exists(DemoLog::class));
foreach ([LoggedClient::class, PlainClient::class] as $name) {
$used = class_uses($name);
echo $name, ': ', isset($used[DemoLog::class]) ? 'есть' : 'нет', "\n";
}
Ожидаемый результат
bool(true)
LoggedClient: есть
PlainClient: нет
SPL class_uses возвращает непосредственно используемые трейты и не обходит автоматически родителей и вложенные трейты. Для полного дерева нужен отдельный обход. Нельзя делать is_a($client, DemoLog::class) вместо такой диагностики.
Если нужно обещать метод log всем клиентам, интерфейс выражает контракт, а трейт может отдельно переиспользовать реализацию. Практический путь: общий logger B24 и Telegram.
Рядом: get_declared_traits, interface_exists, class_exists. Как выбрать проверку.
enum_existsПроверить, что имя относится именно к перечислению, а не к обычному классу.
PHP 8.1+ · Core
enum_exists(string $enum, bool $autoload = true): boolПроверить, что имя относится именно к перечислению, а не к обычному классу.
- Status содержит допустимые состояния заказа
- enum_exists проверяет вид объявления Status
- Отдельно Status::tryFrom проверяет значение paid, а не существование типа
| Вход / результат | Точный смысл |
|---|---|
| $enum | Имя перечисления с namespace; сопоставление объявленного имени регистронезависимо. |
| $autoload | По умолчанию true, неизвестное имя может загрузиться. false не запускает загрузчики. |
| Результат | true и для pure enum, и для backed enum; false для обычного класса или неизвестного имени. |
| Версия / границы | PHP 8.1+. Не проверяет конкретный case/value; для строки значения backed enum используют tryFrom/from. Ошибки autoloader могут пройти наружу. |
Перечисление задаёт ограниченный набор вариантов. ::Paid обозначает один case, а ::class — имя самого enum. Сначала различим типы, затем отдельно проверим значение из данных.
<?php
declare(strict_types=1);
enum Status { case Paid; }
class Settings {}
var_dump(enum_exists(Status::class, false));
var_dump(class_exists(Status::class, false));
var_dump(enum_exists(Settings::class, false));
Ожидаемый результат
bool(true)
bool(true)
bool(false)
PHP 8.1+. class_exists включает enum; для точного вопроса выбирайте enum_exists.
<?php
declare(strict_types=1);
enum Status: string { case New = 'new'; case Paid = 'paid'; }
$enum = Status::class;
if (enum_exists($enum, false)) {
foreach (['paid', 'unknown'] as $value) {
$status = Status::tryFrom($value);
echo $status?->name ?? 'Недопустимый статус', "\n";
}
}
Ожидаемый результат
Paid
Недопустимый статус
PHP 8.1+. : string связывает case со строковым значением; tryFrom возвращает case или null. ?-> не читает свойство у null, ?? даёт запасной текст. Проверка наличия enum сама по себе не валидирует unknown. Для параметризованного произвольного enum отдельно проверьте BackedEnum и ожидаемый тип значений.
Рядом: class_exists, get_declared_classes, is_a. Как выбрать проверку.
get_declared_classesПолучить снимок классов, уже известных текущему PHP-процессу.
PHP 4+ · Core
get_declared_classes(): arrayПолучить снимок классов, уже известных текущему PHP-процессу.
- До подключения файла снимаем набор имён
- require подключает учебный класс, выполняет верхний уровень файла
- Разность после/до показывает только новые объявления этого процесса
| Вход / результат | Точный смысл |
|---|---|
| Параметры | Нет. Функция не принимает папку проекта или namespace. |
| Результат | Массив имён объявленных классов: встроенных, пользовательских, enum и зарегистрированных class-alias; набор зависит от окружения и уже загруженных файлов. Занятое встроенным классом имя нельзя повторно объявить для своего класса. |
| Порядок / версии | С PHP 7.4 конкретный порядок результата не гарантируется. Не сравнивайте вывод целиком с универсальным списком. |
| Граница | Не сканирует файлы и не вызывает загрузчик ради обнаружения всех Composer-классов. Обычный успешный результат — массив, в том числе с множеством системных имён. |
Снимок полезен для локальной диагностики: что действительно загрузилось при включении расширения проекта. Для реестра плагинов лучше явная карта или метаданные пакета, поскольку «всё известное процессу» включает посторонние типы.
<?php
declare(strict_types=1);
class Delivery {}
$names = get_declared_classes();
var_dump(in_array(Delivery::class, $names, true));
Ожидаемый результат
bool(true)
in_array с true проверяет точное совпадение строки. Полный массив зависит от установленных расширений, поэтому тестирует только собственное объявление.
<?php
declare(strict_types=1);
$before = get_declared_classes();
require __DIR__ . '/exporters.php';
$added = array_values(array_diff(get_declared_classes(), $before));
sort($added);
echo implode(', ', $added), "\n";
Ожидаемый результат
CsvExporter, XmlExporter
array_diff оставляет новые значения, array_values пересобирает числовые ключи. Объявления намеренно вынесены в отдельный файл: без этого раннее объявление в том же файле могло бы уже присутствовать в первом снимке. Реальный подключаемый файл способен объявить и другие классы.
В списке также могут оказаться анонимные классы со служебными именами и aliases в нижнем регистре. Не превращайте имя из этого массива напрямую в путь, URL или команду. Если нужны только конкретные исполнители интерфейса, фильтруйте свою разрешённую карту через is_a/is_subclass_of.
Рядом: get_declared_interfaces, get_declared_traits, class_exists, is_subclass_of. Как выбрать проверку.
get_declared_interfacesИсследовать интерфейсы, объявленные к текущему моменту выполнения.
PHP 5+ · Core
get_declared_interfaces(): arrayИсследовать интерфейсы, объявленные к текущему моменту выполнения.
- Подключаем файл контрактов интеграции
- В таблицу интерфейсов добавляется Delivery
- Разность снимков показывает новый контракт; исполнителя это ещё не создаёт
| Вход / результат | Точный смысл |
|---|---|
| Параметры | Нет. Функция не получает объект. |
| Результат | Массив имён всех объявленных интерфейсов, включая системные и загруженные пользовательские. Набор зависит от расширений и загрузки проекта. |
| Граница / версия | PHP 5+. Не ищет незагруженные файлы; не отвечает, какие интерфейсы реализует отдельный объект. Для этого class_implements либо проверка известного контракта. |
Список — средство диагностики пакета. Он не является списком работающих интеграций: интерфейс описывает, что должен уметь класс, но сам запросы не отправляет.
<?php
declare(strict_types=1);
interface Delivery {}
var_dump(in_array(Delivery::class, get_declared_interfaces(), true));
Ожидаемый результат
bool(true)
Объявление interface добавило имя в таблицу; new и implements здесь ещё не было.
<?php
declare(strict_types=1);
$before = get_declared_interfaces();
require __DIR__ . '/contracts.php';
$added = array_values(array_diff(get_declared_interfaces(), $before));
sort($added);
echo implode(', ', $added), "\n";
Ожидаемый результат
Delivery, PaymentGateway
Такой контроль полезен при исследовании bootstrap. В приложении обычно обращаются к известному имени напрямую; не выполняют полный обход интерфейсов на каждом HTTP-запросе.
Не полагайтесь на порядок списка. Добавление расширения меняет окружение, а загрузка файла — состояние текущего процесса. Для одного конкретного имени дешевле по смыслу и понятнее interface_exists; измерения времени здесь не подменяют выбор нужного вопроса.
Рядом: interface_exists, get_declared_classes, is_a. Как выбрать проверку.
get_declared_traitsПолучить имена трейтов, уже объявленных в этом процессе.
PHP 5.4+ · Core
get_declared_traits(): arrayПолучить имена трейтов, уже объявленных в этом процессе.
- Файл diagnostics.php объявляет трейт DemoLog
- get_declared_traits видит добавленное имя
- Класс может использовать его позже; сейчас это только наличие реализации
| Вход / результат | Точный смысл |
|---|---|
| Параметры | Нет. Функция не принимает имя класса. |
| Результат | Массив объявленных имён трейтов; если ни одного нет, пустой массив. Это снимок уже загруженного кода. |
| Граница / версия | PHP 5.4+. Не сканирует Composer-пакеты, не загружает всё автоматически и не определяет, какие трейты использует конкретный класс. |
Трейт переиспользует методы, но не является экземпляром или интерфейсным обещанием. Полный список нужен при исследовании загрузки, а не для каждого обычного вызова метода.
<?php
declare(strict_types=1);
trait DemoLog {}
var_dump(in_array(DemoLog::class, get_declared_traits(), true));
Ожидаемый результат
bool(true)
Трейт объявлен, хотя ни один класс его пока не использует.
<?php
declare(strict_types=1);
$before = get_declared_traits();
require __DIR__ . '/diagnostics.php';
$added = array_values(array_diff(get_declared_traits(), $before));
sort($added);
echo implode(', ', $added), "\n";
Ожидаемый результат
DemoLog, RequestLabel
Временный fixture не пишет настоящий журнал. В большом проекте список служит диагностике: для явной зависимости подключите пакет и используйте его контракт.
Для одного имени применяют trait_exists; для непосредственно использованных трейтов класса — SPL class_uses, а полное дерево родителей/вложенных трейтов обходят отдельно. Сортировка нужна лишь для удобного устойчивого отображения.
Рядом: trait_exists, get_declared_classes, get_declared_interfaces. Как выбрать проверку.
__autoloadУзнать удалённый механизм автозагрузки в старом проекте и заменить его современной регистрацией загрузчика.
PHP 5; deprecated 7.2; removed 8.0 · Core
__autoload(string $class): void — исторический callback; удалён в PHP 8.0Узнать удалённый механизм автозагрузки в старом проекте и заменить его современной регистрацией загрузчика.
- Нужен объект Delivery, но имя ещё не объявлено
- Современный loader получает строку Delivery и подключает известный файл
- После объявления PHP продолжает исходное new; именно оно создаёт объект
| Вход / результат | Точный смысл |
|---|---|
| $class | PHP передавал имя ещё не найденного класса/интерфейса. Функцию определял разработчик; это был специальный callback, а не универсальная готовая функция загрузки. |
| Результат / действие | Возвращаемое значение не предоставляло класс: тело должно было подключить файл и объявить нужный тип. При сохранении неизвестного типа исходная операция могла завершиться ошибкой. |
| Жизненный цикл | Механизм появился в PHP 5, deprecated с PHP 7.2, удалён в PHP 8.0. Определение function __autoload в современном PHP приводит к фатальной ошибке. |
| Современная замена | spl_autoload_register регистрирует callable и позволяет несколько загрузчиков; Composer создаёт готовый vendor/autoload.php. |
В старом проекте вы можете увидеть function __autoload. Не запускайте его в PHP 8 и не пытайтесь спрятать определение за function_exists. Ниже оба примера используют действующую замену; они показывают, что делает автозагрузчик, прежде чем переходить к Composer.
<?php
declare(strict_types=1);
$loader = static function (string $name): void {
if ($name === 'Delivery') {
require __DIR__ . '/Delivery.php';
}
};
spl_autoload_register($loader);
try {
$delivery = new Delivery;
echo $delivery->label(), "\n";
} finally {
spl_autoload_unregister($loader);
}
Ожидаемый результат
Курьер
Callback сохранён в $loader, register добавляет его в очередь. Он не создаёт Delivery: исходное new продолжает работу после загрузки. __DIR__ означает каталог данного файла. unregister в finally убирает только наш callback после опыта.
<?php
declare(strict_types=1);
$first = static function (string $name): void {
if ($name === 'Shop\\Delivery') {
require __DIR__ . '/Delivery.php';
}
};
$second = static function (string $name): void {
if ($name === 'Reports\\Sales') {
require __DIR__ . '/Sales.php';
}
};
spl_autoload_register($first);
spl_autoload_register($second);
try {
echo get_class(new Shop\Delivery), "\n";
echo get_class(new Reports\Sales), "\n";
} finally {
spl_autoload_unregister($second);
spl_autoload_unregister($first);
}
Ожидаемый результат
Shop\Delivery
Reports\Sales
Первый callback игнорирует чужое имя, поэтому второй получает шанс загрузить Reports\Sales. Для неизвестного собственного класса не требуется выдавать произвольный успешный результат. Не строите путь require напрямую из HTTP: здесь карта двух точных имён.
В реальном Composer-проекте обычно достаточно require __DIR__ . "/vendor/autoload.php"; он регистрирует загрузчик, а не немедленно загружает все классы. Точное соответствие пространства имён и файлов: PSR-4 и первый запуск. При миграции удалите/переименуйте старое определение, сохраните его ограниченную логику в callback, проверьте порядок загрузки и обработку неизвестных имён. Автозагрузчик не обновляет токены и не делает объект живущим между HTTP-запросами.
Рядом: class_exists, interface_exists, get_declared_classes. Как выбрать проверку.
Источники и обсуждения
- PHP: book.classobj
- PHP: classobj.examples
- PHP: ref.classobj
- PHP: function.autoload
- PHP: function.class-alias
- PHP: function.class-exists
- PHP: function.enum-exists
- PHP: function.get-called-class
- PHP: function.get-class
- PHP: function.get-class-methods
- PHP: function.get-class-vars
- PHP: function.get-declared-classes
- PHP: function.get-declared-interfaces
- PHP: function.get-declared-traits
- PHP: function.get-mangled-object-vars
- PHP: function.get-object-vars
- PHP: function.get-parent-class
- PHP: function.interface-exists
- PHP: function.is-a
- PHP: function.is-subclass-of
- PHP: function.method-exists
- PHP: function.property-exists
- PHP: function.trait-exists
- PHP: language.oop5.property-hooks
- PHP: language.oop5.lazy-objects
- PHP: language.types.declarations
- PHP: migration81.deprecated
- PHP: function.spl-autoload-register
- Обсуждение задачи: Существование свойства и null — разные вопросы — обсуждение проблемы
- Обсуждение задачи: Импорт use работает, а строка имени класса — нет — обсуждение проблемы
- Обсуждение задачи: Найденный метод не обязательно доступен для вызова — обсуждение проблемы
- Обсуждение задачи: После Composer не видны все классы — обсуждение проблемы
- Обсуждение задачи: Настройки класса и текущий объект перепутаны — обсуждение проблемы
- Обсуждение задачи: В старом коде get_class_vars читали как текущие static — обсуждение проблемы
- Обсуждение задачи: Проверить подходящий тип до создания объекта — обсуждение проблемы
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


