Обновление старшей версии (например, с 6.4.0 до 7.0.0)

Дата обновления перевода 2025-02-18

Обновление старшей версии (например, с 6.4.0 до 7.0.0)

Каждые два года Symfony выпускает новую старшую версию (меняется первая цифра). Эти релизы самые сложные в обновлении, так как им разрешено нарушать обратную совместимость. Однако, Symfony делает так, чтобы процесс обновления прошёл как можно более гладко.

Это означает, что вы можете обновить большую часть вашего кода до того, как полноценная версия на самом деле будет выпущена. Это называется делать ваш код совместимым с будущим.

В обновлении до старшей версии существует несколько шагов:

  1. Избавить ваш код от устареваний ;
  2. Обновить до новой старшей версии через Composer ;
  3. Обновить ваш код, чтобы он работал с новой версией .

1) Избавить ваш код от устареваний

Во время жизненного цикла релиза старшей версии, добавляются новые функции, а подписи методов и использование публичных API изменяются. Однако, младшие версии не должны содержать никаких изменений обратной совместимости. Чтобы добиться этого, "старый" код (например, функции, классы и т.д.) всё ещё будет работать, но будет помечен как осуждённый, обозначая, что он будет удалён или изменён в будущем, и что вам стоит перестать его использовать.

Когда выпускается старшая версия (например, 7.0.0), все устаревшие функции и особенности удаляются. Так что, если вы обновили ваш код так, чтобы он перестал использовать такие устаревшие функции в последней версии перед старшей (например, в 6.4.*), у вас не должно возникнуть проблем с обновлением. Это означает, что вы сначала должны обновиться до последней младшей версии (например, 5.4), чтобы вы могли увидеть все устаревания.

Чтобы помочь вам найти устаревания, уведомления вызываются каждый раз, когда вы используете устаревшую функцю. Когда вы посещаете ваше приложение в окружении разработки вашего браузера, эти уведомления отображаются в панели инструментов веб-разработки:

На странице логов Symfony Profiler отображаются уведомления об устаревании.

В конце-концов, вы захотите перестать использовать устаревшую функциональность. Иногда предупреждение может сказать вам о том, что именно вам нужно изменить.

Но в других ситуациях предупреждение может быть туманным: установка где-то может вызвать более глубокий класс вызвать предупреждение. В этом случае Symfony старается как можно чётче сформулировать сообщение, но возможно вы захотите глубже исследовать такое предупреждение.

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

Tip

Rector - это сторонний проект, который автоматизирует обновление и рефакторинг проектов PHP. Rector включает в себя некоторые правила для исправления определенных устареваний Symfony автоматически.

Как только исчезнут все предупреждения о возражениях, вы можете обновляться с наибольшей уверенностью.

Устаревания в PHPUnit

Когда вы выполняете ваши тесты, используя PHPUnit, сообщения об устареваниях не отображаются. Чтобы помочь вам в этом, Symfony предоставляет мост PHPUnit. Этот мост покажет вам удобное резюме всех сообщений о возражениях в конце тестовго отчёта.

Всё, что вам нужно - это установить мост PHPUnit:

1
$ composer require --dev symfony/phpunit-bridge

Теперь вы можете начать исправлять уведомления:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# эта команда доступна после запуска "composer require --dev symfony/phpunit-bridge"
$ ./bin/phpunit
...

OK (10 тестов, 20 утверждений)

Оставшиеся сообщения об устареваниях (6)

Сервис "запроса" ("request") вызывает возражение и будет удалён в версии 3.0.
Добавьте типизирование для Symfony\Component\HttpFoundation\Request в параметры
вашего контроллера, чтобы вместо этого вернуть запрос: 6x
    3x in PageAdminTest::testPageShow from Symfony\Cmf\SimpleCmsBundle\Tests\WebTest\Admin
    2x in PageAdminTest::testPageList from Symfony\Cmf\SimpleCmsBundle\Tests\WebTest\Admin
    1x in PageAdminTest::testPageEdit from Symfony\Cmf\SimpleCmsBundle\Tests\WebTest\Admin

Как только вы исправите всё, команда окончится 0 (успех) и вы закончили!

Warning

Вы скорее всего увидите много устареваний касательно несовместимости нативных типов возврата. См. Добавление нативных типов возвращаемых значений , чтобы получить руководство по исправлению таких устареваний.

Иногда вам не удастся исправить все устаревания (например, что-то устарело в версии 5.4, а вам всё еще нужна поддержка версии 5.3). В таких случаях, вы всё равно можете использовать мост для исправления как можно наибольшего количества устареваний, а потом позволить одной или более из них провести тестирование. Вы можете сделать это, используя переменную окружения SYMFONY_DEPRECATIONS_HELPER:

1
2
3
4
5
6
7
8
<!-- phpunit.xml.dist -->
<phpunit>
    <!-- ... -->

    <php>
        <env name="SYMFONY_DEPRECATIONS_HELPER" value="max[total]=999999"/>
    </php>
</phpunit>

Вы также можете выполнить такую команду:

1
$ SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 php ./bin/phpunit

2) Обновить до новой старшей версии через Composer

Когда ваш код будет избавлен от устареваний, вы можете обновить библиотеку Symfony через Composer, модифицировав ваш файл composer.json, и изменив все библиотеки, которые начинаются с symfony/ на новую старшую версию:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
      "...": "...",

      "require": {
-         "symfony/config": "6.4.*",
+         "symfony/config": "7.0.*",
-         "symfony/console": "6.4.*",
+         "symfony/console": "7.0.*",
          "...": "...",

          "...": "Несколько библиотек, начинающихся с symfony/,
                  следуют собственной схеме версионирования. Вам
                  не нужно обновлять эти версии: вы можете обновить
                  их независимо, когда захотите",
          "symfony/monolog-bundle": "^3.5",
      },
      "...": "...",
  }

Внизу вашего файла composer.json, в блоке extra, вы можете найти настройку данных для версии Symfony. Убедитесь в том, что обновили и ее. Например, ирзмените ее на 6.0.*, чтобы обновиться до версии Symfony 6.0:

1
2
3
4
5
6
7
"extra": {
      "symfony": {
          "allow-contrib": false,
-         "require": "6.4.*"
+         "require": "7.0.*"
      }
  }

Tip

Если доступна более новая младшая версия (например, 6.4), вы можете использовать ее и пропустить более старые версии (6.0, 6.1 и т.д.). Проверьте поддерживаемые версии Symfony.

Далее, используйте Composer, чтобы скачать новые версии библиотек:

1
$ composer update "symfony/*"

Лучшей практикой после обновления до новой старшей версии является очистка кеша. Вместо того чтобы выполнять команду cache:clear (которая не сработает, если приложение не загружается в консоли после обновления), лучше удалить все содержимое каталога кеша:

1
2
3
4
5
# запустите эту команду в Linux и macOS
$ rm -rf var/cache/*

# запустите эту команду в Windows
C:\> rmdir /s /q var\cache\*

Дата обновления перевода 2025-02-24

Ошибки зависимостей

Если вы получаете ошибку зависимости, это может означать, что вам также необходимо обновить другие библиотеки, которые являются зависимостями библиотек Symfony. Чтобы разрешить это, передайте флажок --with-all-dependencies:

1
$ composer update "symfony/*" --with-all-dependencies

Это обновляет symfony/* и все пакеты, от которых зависят эти пакеты. Используя жесткие ограничения версий в файле composer.json, вы можете контролировать,
до каких версий обновляется каждая библиотека.

Если и это не сработает, ваш файл composer.json может указывать версию для билиотеки, котора не совместима с более новыми версиями Symfony. В таком случае, обновление библиотеки до более новой версии в composer.json может решить проблему.

Или, у вас могут быть более глубокие проблемы, когда разные библиотеки зависят от конфликтующих версий других библиотек. Проверьте ваши сообщения ошибок для отладки.

Другая проблема, которая может возникнуть, заключается в том, что зависимости проекта могут
быть установлены на вашем локальном компьютере, но не на удаленном сервере. Обычно это происходит,
когда версии PHP на каждой машине разные. Решением является добавление опции конфигурации platform в файл `composer.json`, чтобы определить наивысшую версию PHP, допустимую для зависимостей (установите ее равной версии PHP на сервере).

Дата обновления перевода 2025-02-18

Обновление других пакетов

Вы можете также захотеть обновить и остальные ваши библиотеки. Если вы хорошо справились с вашими version constraints в composer.json, вы можете без опаски сделать это, выполнив:

1
$ composer update

Warning

Будьте осторожны, если у вас есь какие-то общие ограничения версий в вашем composer.json (например, dev-master), это может обновить некоторые библиотеки не из Symfony до более новых версий, которые содержат существенные изменения обратной совместимости.

Дата обновления перевода 2025-02-24

3) Обновление рецептов

Со временем - и особенно при обновлении до новой версии библиотеки - может появиться обновленная
версия рецепта . Эти обновления обычно незначительны - например, новые комментарии в файле конфигурации - но желательно синхронизировать ваши файлы с рецептами.

Symfony Flex предоставляет несколько команд, которые помогут обновить ваши рецепты. Убедитесь, что вы зафиксировали все несвязанные изменения, над которыми вы работаете, перед началом работы:

1.18

Команда recipes:update была представлена в Symfony Flex 1.18.

1
2
3
4
5
6
7
8
9
10
11
# выбрать устаревший рецепт для обновления
$ composer recipes:update

# обновить конкретный рецепт
$ composer recipes:update symfony/framework-bundle

# увидеть список всех установленных рецептов и какие обновления доступны
$ composer recipes

# увидеть детализированную информацию про конкретные рецепты
$ composer recipes symfony/framework-bundle

Команда recipes:update умная: она смотрит на разницу между рецептом, когда вы его установили, и его последней версией. Затем она создает патч и применяет его к вашему приложению. Если возникнут какие-либо конфликты, вы можете разрешить их как обычный конфликт git и зафиксировать как обычно.

3) Обновить ваш код, чтобы он работал с новой версией

В некоторых редких ситуациях, следующая старшая версия может содержать нарушения обратной совместимости. Не забудьте прочитать UPGRADE-X.0.md (где X - это новая старшая версия), включенный в хранилище Symfony, чтобы узнать о любых нарушениях обратной совместимости, на которые вам стоит обратить внимание.

Обновление до Symfony 6: Добавление нативных типов возвращаемых значений

Symfony 6 и Symfony 7 поставляются с нативными типами возвращаемых значений PHP (почти) ко всем методам.

В PHP, если родитель имеет декларацию типа возвращаемого значения, любой класс, реализующий или переопределяющий метод, должен также иметь тип возвращаемого значения. Однако, вы можете добавить тип возвращаемого значения до того, как его добавит родитель. Это означает, что важно добавлять нативные типы возвращаемых значений PHP к вашим классам до обновления на Symfony 6.0. Иначе, вы получите ошибки несовместимых деклараций.

Когда включен режим отладки (обычно в окружениях разработки и тестирования), Symfony будет выдавать устаревания для каждой несовместимой декларации методов. Например, метод UserInterface::getRoles() в Symfony 6 будет иметь тип возвращаемого значения array. В Symfony 5.4, вы получите сообщение об устаревании, и должны будете добавить декларацию типа возвращаемого значения к вашему методу getRoles().

Чтобы помочь с этим, Symfony предоставляет скрипт, который может добавлять эти типы возвращаемых значений за вас автоматически. Убедитесь в том, что вы установили компонент symfony/error-handler. После этого, сгенерируйте полное отображение классов, используя Composer, и выполните скрипт, чтобы выполнить перебор и исправить все несовместимые методы:

1
2
3
4
5
6
7
# Убедитесь, что "exclude-from-classmap" не заполнен в вашем "composer.json". Затем сбросьте автозагрузчик:

# "-o" - это важно! Это заставляет Composer найти все классы
$ composer dump-autoload -o

# исправьте все декларации несовместимых методов
$ ./vendor/bin/patch-type-declarations

Tip

Эта функция не ограничивается пакетами Symfony. Она также поможет вам добавлять типы и готовиться к другим зависимостям в вашем проекте.

Поведения этого скрипта можно изменить, используя переменную окружения SYMFONY_PATCH_TYPE_DECLARATIONS. Значение этой переменной окружения url-зашифровано (например, param1=value2&param2=value2), и доступны следующие параметры:

force

Включает исправление типов возвращаемых значений, значение должно быть:

  • 2, чтобы добавить все возможные типы возвращаемых значений (по умолчанию рекомендовано для приложений);
  • 1, чтобы добавить типы возвращаемых значений только к тестам, финальным, внутренним или приватным методам;
  • phpdoc, чтобы добавить только аннотации docblock @return к несовместимым методам, или #[\ReturnTypeWillChange], если оно вызвано PHP-движком.
php
Целевая версия PHP - например, 7.1 не генерирует типы "object" (которые были представлены в 7.2). По умолчанию это приравнивается к PHP-версии, используемой при выполнении скрипта.
deprecations
Установите 0, чтобы отключить устаревания. Иначе, возникнет уведомление устаревания, когда дочернему классу не будет хватать типа возвращаемого значения, в то время как родительский класс будет объявлять аннотацию @return (по умолчанию - 1).

Если есть какие-то конкретные файлы, которые нужно игнорировать, вы можете установить переменную окружения SYMFONY_PATCH_TYPE_EXCLUDE как регулярное выражение. Это регулярное выражение будет сопоставлено с полным путем к классу, и каждый совпадающий путь будет проигнорирован (например, SYMFONY_PATCH_TYPE_EXCLUDE="/tests\/Fixtures\//"). Классы в каталоге vendor/ всегда будут игнорироваться.

Tip

Скрипту неважен стиль кода. Запустите свой исправитель стиля кода, или PHP CS Fixer с правилами phpdoc_trim_consecutive_blank_line_separation, no_superfluous_phpdoc_tags и ordered_imports, после исправления типов.

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

  1. Во-первых, создайте младший релиз (т.е. без нарушений обратной совместимости), где вы добавите типы, которые могут быть представлены безопасно, и добавите PHPDoc @return ко всем другим методам:

    1
    2
    3
    4
    5
    6
    # Добавить декларации типов ко всем внутренним, финальным, тестовым и приватным методам.
    # Обновить параметр "php", чтобы он соответствовал вашей минимально требуемой версии PHP
    $ SYMFONY_DEPRECATIONS_HELPER="force=1&php=7.4" ./vendor/bin/patch-type-declarations
    
    # Добавить PHPDoc к оставшимся публичным и защищенным методам
    $ SYMFONY_DEPRECATIONS_HELPER="force=phpdoc&php=7.4" ./vendor/bin/patch-type-declarations

    После выполнения скриптов, проверьте свои классы и добавьте PHPDoc @return там, где его не хватает. Устаревания и скрипт исправлений работают исключительно основываясь на информации PHPDoc. Пользователи этого релиза получат уведомления об устаревании, которые сообщат им о том, что стоит добавить недостающие типы возвращаемых значений из вашего пакета в их код.

    Если вам не нужен был PHPDoc, и все ваши декларации методов уже совместимы с Symfony, вы можете спокойно разрешить ^6.0 для зависимостей Symfony. В других случаях, вам нужно будет перейти к следующему шагу (2).

  2. Создайте новый старший релиз (т.е. с нарушениями обратной совместимости), где вы добавите типы ко всем методам:

    1
    2
    # Обновить параметр "php", чтобы он соответствовал вашей минимально требуемой версии PHP
    $ SYMFONY_DEPRECATIONS_HELPER="force=2&php=7.4" ./vendor/bin/patch-type-declarations

    Теперь, вы можете безопасно разрешить ^6.0 для зависимостей Symfony.