Learn (Almost) Anything
КаталогСкачать курс

Современный PHP

Справка по migration guides, deprecations, backward incompatible changes, поддержке расширений, проверке зависимостей и стратегии обновления 8.x. Связана с [Версии PHP и режимы выполнения](course://article/Версии PHP и режимы выполнения) и [composer.lock, install/update и audit](course://article/composer.lock, install/update и audit).

ruЭнциклопедия52 урока8 модулей10
Справочник PHPPHPСовременный PHPЯдро языкаДанные и стандартная библиотекаОбъектная модельВеб-слой и HTTPHTTPБазы данных и безопасностьЭкосистема и качество кода

Миграции между версиями PHP

Справка по migration guides, deprecations, backward incompatible changes, поддержке расширений, проверке зависимостей и стратегии обновления 8.x. Связана с [Версии PHP и режимы выполнения](course://article/Версии PHP и режимы выполнения) и [composer.lock, install/update и audit](course://article/composer.lock, install/update и audit).

Что значит «мигрировать PHP»

Миграция между версиями PHP — это не просто поменять php:8.2-fpm на php:8.4-fpm в Dockerfile. В проекте одновременно меняются язык, стандартная библиотека, расширения, Composer-зависимости, настройки рантайма и иногда поведение фреймворка. Поэтому обновление PHP ближе к controlled rollout, чем к обычному апдейту пакета.

На 15 июня 2026 года поддерживаемые ветки PHP — 8.2, 8.3, 8.4 и 8.5. При этом 8.2 уже находится в security support, 8.4 ещё в active support, а 8.5 — самая новая стабильная ветка. Это важно для выбора цели: обновляться «на ближайшую возможную» версию иногда разумно, но для нового production-плана лучше смотреть на ветку с нормальным горизонтом поддержки. Жизненный цикл версий подробно связан с Версии PHP и режимы выполнения, а техническая часть почти всегда упирается в composer.lock, install/update и audit.

flowchart TD A[Выбрать целевую версию PHP] --> B[Прочитать migration guide] B --> C[Проверить composer.json и composer.lock] C --> D[Обновить dev-инструменты] D --> E[Запустить CI matrix] E --> F[Разобрать deprecations и несовместимости] F --> G[Проверить расширения и SAPI] G --> H[Staging smoke tests] H --> I[Production rollout] I --> J[Логи, healthchecks, rollback-план]
flowchart TD
    A[Выбрать целевую версию PHP] --> B[Прочитать migration guide]
    B --> C[Проверить composer.json и composer.lock]
    C --> D[Обновить dev-инструменты]
    D --> E[Запустить CI matrix]
    E --> F[Разобрать deprecations и несовместимости]
    F --> G[Проверить расширения и SAPI]
    G --> H[Staging smoke tests]
    H --> I[Production rollout]
    I --> J[Логи, healthchecks, rollback-план]
Практический маршрут миграции PHP: сначала совместимость кода и зависимостей, затем смена runtime и проверка production-поведения.
Быстрое повторение #rc-1

Почему миграцию PHP нельзя сводить к замене Docker image вроде php:8.2-fpm на php:8.4-fpm?

Показать ответ

Потому что меняются не только версия языка, но и стандартная библиотека, расширения, Composer-зависимости, настройки рантайма и иногда поведение фреймворка. Поэтому миграция больше похожа на controlled rollout, чем на обычный апдейт пакета.

Что читать в migration guide

Официальные migration guides PHP обычно делят изменения на несколько групп: new features, new functions/classes/constants, backward incompatible changes, deprecated features, removed extensions и other changes. Для обновления production-кода самые важные разделы — не новые фичи, а несовместимости и deprecations.

Backward incompatible change — это изменение, из-за которого старый код может начать вести себя иначе или падать. Например, в PHP 8.4 часть ошибок стала выбрасываться как ValueError или TypeError, некоторые resource-значения были переведены в objects, а exit() стал вести себя ближе к функции и учитывать strict_types. Такой код не всегда ломается на этапе composer install; он может проявиться только в тестах или в редком runtime-сценарии. Поэтому статья Ошибки, исключения и Throwable здесь не теоретическая: при миграции надо понимать, где раньше был warning или fatal error, а теперь прилетает исключение.

Deprecation — предупреждение о будущем удалении или изменении поведения. Хороший пример из PHP 8.2 — динамические свойства объектов: создание $object->newProperty без объявления свойства стало deprecated, если класс явно не разрешил такое поведение. В легаси-коде это часто всплывает в DTO, ORM-моделях, старых hydration-слоях и тестовых double-объектах. Правильный фикс обычно не «заглушить warning», а объявить свойство, заменить структуру данных или осознанно использовать #[\AllowDynamicProperties]. Это напрямую касается Классы, объекты и видимость и Атрибуты и Reflection.

Быстрое повторение #rc-2

В migration guide PHP какие разделы важнее всего читать для production-обновления, если цель — не новые фичи, а снижение риска?

Показать ответ

В первую очередь backward incompatible changes и deprecated features. Именно там описаны изменения, из-за которых старый код может вести себя иначе сейчас или сломаться в следующей версии.

Composer как первый фильтр

Перед запуском приложения на новой версии PHP надо спросить Composer, вообще возможна ли такая платформа. Минимум — проверить constraints в composer.json:

{
  "require": {
    "php": "^8.2 || ^8.3 || ^8.4",
    "ext-json": "*",
    "ext-mbstring": "*"
  }
}

Если проект хочет перейти на PHP 8.5, а constraint разрешает только 8.4.* или >=8.4 <8.5, Composer честно заблокирует установку или обновление. Это не баг Composer, а защита от непроверенного рантайма. При этом ^8.4 сам по себе PHP 8.5 не блокирует: для Composer это диапазон >=8.4 <9.0. Иногда команда временно использует --ignore-platform-req=php+, чтобы проверить совместимость зависимостей с верхней границей, но это диагностический ход, а не production-практика.

Полезные команды:

composer validate --strict
composer outdated --direct
composer prohibits php 8.5
composer update --dry-run
composer check-platform-reqs

composer prohibits php 8.5 показывает, какие пакеты не дают перейти на целевую версию. composer check-platform-reqs проверяет реальную установленную версию PHP и расширения, причём не полагается на config.platform. Это важно после deploy: lock-файл мог собираться в CI под одной платформой, а production-FPM может жить с другим набором ext-*.

Быстрое повторение #rc-3

Что показывает команда composer prohibits php 8.5 при подготовке миграции?

Показать ответ

Она показывает пакеты, constraints которых не дают перейти на целевую версию PHP. Это первый способ найти dependency blockers до запуска приложения на новом рантайме.

Lock-файл и стратегия зависимостей

Миграция PHP почти никогда не должна начинаться с хаотичного composer update всего проекта. Без плана вы одновременно меняете PHP, framework, десятки библиотек и dev-инструменты. Когда после этого падают тесты, непонятно, кто виноват.

Более управляемая схема:

1. Зафиксировать текущий composer.lock и убедиться, что composer install воспроизводим.

2. Обновить dev-инструменты, которые должны понимать новую версию PHP: PHPUnit, PHPStan или Psalm, PHP-CS-Fixer/PHP_CodeSniffer.

3. Найти blockers через composer prohibits php <version>.

4. Обновить только необходимые runtime-зависимости.

5. Запустить полный pipeline из CI, линтеры и автоматические проверки.

6. Прогнать приложение на новой версии PHP в staging или отдельном окружении.

Если пакет больше не поддерживается, Composer может показать это через audit/outdated-процессы, но решение всё равно архитектурное: заменить пакет, поднять major-версию с миграцией API или оставить проект на старой ветке PHP до рефакторинга.

ИнтерактивПорядок миграции PHP#int-1
Шаг 1 из 61. Зафиксировать baseline
Убедитесь, что текущая ветка зелёная на старой версии PHP: `composer install`, `composer check`, тесты и static analysis проходят без новых ошибок.
Короткий walkthrough по безопасному обновлению версии PHP в проекте с Composer и CI.

Что ломается чаще всего

Первый класс проблем — типы. Новые версии PHP постепенно делают стандартные функции строже: там, где раньше был warning, может появиться ValueError; там, где значение молча приводилось, теперь важен TypeError. Код с точными сигнатурами, strict_types, PHPDoc и статическим анализом обычно переносится легче. Поэтому Типы и strict_types и PHPDoc, generics и статический анализ — практическая база для миграций, а не «красота типов ради типов».

Второй класс — расширения. Проект может быть совместим с PHP 8.4 на уровне языка, но не иметь готового ext-imagick, ext-redis, ext-swoole или драйвера БД для нужного образа. Особенно это видно в Docker и CI: PHP обновили, а PECL-расширение не собрано или требует другой системной библиотеки. Проверять надо не только php -v, но и php -m, composer check-platform-reqs, smoke tests и реальные entrypoints: CLI, FPM, queue workers, cron.

Третий класс — долгоживущие процессы. Классический request-response под PHP-FPM часто прощает больше: процесс обработал запрос и умер или вернулся в пул. В RoadRunner, Swoole, очередях и воркерах состояние живёт дольше, поэтому миграция может вскрыть проблемы с singletons, кешами, статическими переменными и обработкой исключений. Это смыкается с PHP-FPM, RoadRunner и долгоживущие воркеры и Очереди, фоновые задачи и воркеры.

Как ловить deprecations до production

На staging и в CI полезно включать максимально шумный error reporting, но не показывать ошибки пользователю:

error_reporting = E_ALL
display_errors = Off
log_errors = On

В тестах deprecations часто превращают в отдельный quality gate. Например, Symfony/PHPUnit-экосистемы умеют считать deprecation notices; в другом проекте можно начать проще: логировать E_DEPRECATED, выгружать их из CI artifacts и заводить issue на самые частые места. Главное — не ждать момента, когда deprecation станет fatal behavior change в следующей версии.

Пример типичного фикса PHP 8.2:

// Было: свойство создаётся на лету и даёт deprecation.
final class UserView
{
}

$user = new UserView();
$user->name = 'Ada';

// Лучше: состояние явно описано в классе.
final class UserView
{
    public function __construct(
        public string $name,
    ) {}
}

$user = new UserView('Ada');

Такой фикс улучшает не только совместимость. Он помогает автодополнению, статическому анализу, сериализации и тестам. Хорошая миграция часто оставляет код понятнее, чем он был до неё.

Production-план

Безопасный rollout обычно идёт в две фазы. Сначала проект становится совместимым со старой и новой версиями PHP: зависимости обновлены, deprecations разобраны, CI гоняется на matrix, например 8.3 и 8.4. Потом меняется runtime: Docker image, серверный пакет PHP, FPM pool, CLI для cron и worker-сервисов.

Пример matrix в GitHub Actions:

strategy:
  matrix:
    php-version: ['8.3', '8.4']

steps:
  - uses: actions/checkout@v4
  - uses: shivammathur/setup-php@v2
    with:
      php-version: ${{ matrix.php-version }}
      coverage: none
  - run: composer install --no-interaction --prefer-dist
  - run: composer check

После переключения версии PHP надо проверять не только web-запрос. Нужны php -v, composer check-platform-reqs --no-dev, healthcheck, авторизация, запись в БД, загрузка файлов, queue worker, cron и команды CLI. Разные SAPI могут смотреть на разные php.ini, поэтому CLI «зелёный» не доказывает, что FPM настроен так же. Это связано с SAPI и суперглобалы и CLI и встроенный сервер.

См. также

Источники

  1. PHP: Supported Versions
  2. PHP Manual: Migrating from PHP 8.4.x to PHP 8.5.x
  3. PHP Manual: Migrating from PHP 8.3.x to PHP 8.4.x
  4. Composer CLI: check-platform-reqs
  5. PHP Manual: Deprecated Features in PHP 8.2
  6. PHP Manual: Backward Incompatible Changes in PHP 8.4