Перейти к основному содержимому

PHP Reflection и SPL

Reflection API​

PHP Reflection API позволяет анализировать классы, интерфейсы, функции, методы и расширения. По сути, это «обратная разработка» кода изнутри PHP. Широко используется в контейнерах внедрения зависимостей, ORM (например, Doctrine) и тестовых фреймворках для изучения классов и их свойств без ручной конфигурации.

Основные классы Reflection​

  • ReflectionClass: информация о классе.
  • ReflectionMethod: информация о методе класса.
  • ReflectionProperty: информация о свойстве класса.
  • ReflectionFunction: информация о функции.
  • ReflectionParameter: информация о параметре функции/метода.

Пример: получение приватных свойств​

class User {
private string $name = "John Doe";
}

$reflector = new ReflectionClass('User');
$property = $reflector->getProperty('name');
$property->setAccessible(true); // Начиная с PHP 8.1, свойства автоматически доступны через Reflection

$user = new User();
echo $property->getValue($user); // John Doe

Стандартная библиотека PHP (SPL)​

SPL — это набор интерфейсов и классов, предназначенных для решения распространённых задач. Она предоставляет стандартный способ реализации типовых паттернов: итераторов, структур данных и наблюдателей.

Основные компоненты SPL​

  1. Итераторы: классы для итерации по объектам, директориям, файлам и сложным структурам.
    • ArrayIterator, DirectoryIterator, FilterIterator, RecursiveIteratorIterator.
  2. Структуры данных: оптимизированные классы для специфического хранения данных.
    • SplStack, SplQueue, SplHeap, SplPriorityQueue, SplFixedArray (быстрее обычных массивов для больших наборов данных), SplObjectStorage (маппинг для объектов).
  3. Исключения: стандартные классы исключений — LogicException, RuntimeException, InvalidArgumentException.
  4. Интерфейсы: Countable (позволяет использовать count()), Serializable, SplObserver, SplSubject.

Различие между SplFixedArray и Array​

Стандартный PHP array на самом деле является упорядоченной картой (хеш-таблицей). SplFixedArray — это настоящий C-подобный массив с фиксированным размером и целочисленными индексами, что делает его быстрее и эффективнее по памяти для больших наборов данных с числовыми индексами.


PHP как демон (Swoole, RoadRunner)​

Современный PHP больше не ограничен жизненным циклом «запрос-ответ» (когда скрипт создаётся и уничтожается при каждом запросе). С помощью таких инструментов, как Swoole, RoadRunner или Workerman, PHP может работать как долгоживущий процесс (демон).

Преимущества​

  • Производительность: инициализация (загрузка фреймворка, конфигурации, DIC) происходит один раз при запуске, а не при каждом запросе.
  • Сохранение состояния: подключения к БД, кэши и объекты могут оставаться в памяти между запросами.
  • Асинхронные задачи: встроенная поддержка неблокирующего ввода-вывода, таймеров и фоновых задач.

Риски и сложности​

  1. Утечки памяти: поскольку процесс не завершается, любая некорректно очищенная память (например, статические переменные, глобальные массивы) будет накапливаться, что в конечном итоге приведёт к падению процесса.
  2. Глобальное состояние: глобальные переменные или статические свойства переносятся между запросами, что может привести к «загрязнению состояния» (данные пользователя A отображаются пользователю B).
  3. Зависшие ресурсы: открытые файловые дескрипторы или подключения к БД могут оставаться открытыми слишком долго или зависать, если управление ими организовано некорректно.
  4. Обработка ошибок: фатальная ошибка может уронить весь серверный воркер, а не только один запрос.
  5. Обновление кода: изменения в коде требуют полного перезапуска демона для вступления в силу (по умолчанию «горячая перезагрузка» отсутствует).

Постоянные подключения к базе данных​

PHP предоставляет механизм постоянных подключений к БД (например, PDO::ATTR_PERSISTENT => true).

Плюсы​

  • Снижает накладные расходы на установку нового TCP-соединения и рукопожатие при каждом запросе.
  • Повышает производительность в условиях высокой конкурентности.

Минусы​

  • Исчерпание соединений: поскольку соединения не закрываются по завершении скрипта, они остаются в пуле. При некорректном управлении можно превысить лимит max_connections базы данных.
  • Устаревшее состояние: временные таблицы, сессионные переменные или состояния транзакций могут перейти к следующему запросу, использующему то же соединение.
  • Deadlock'и: длительные транзакции на постоянных соединениях могут вызвать проблемы, если не закрыть их корректно.