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

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

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

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

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

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

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

1) Избавить ваш код от депрекаций

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

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

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

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

Но в других ситуациях предупреждение может быть туманным: установка где-то может вызвать более глубокий класс вызвать предупреждение. В этом случае 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 (успех) и вы закончили!

Caution

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

Иногда вам не удастся исправить все депрекации (например, что-то устарело в версии 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/ на новую старшую версию:

{

"...": "...",

"require": {

  • "symfony/cache": "5.4.*",
  • "symfony/cache": "6.0.*",
  • "symfony/config": "5.4.*",
  • "symfony/config": "6.0.*",
  • "symfony/console": "5.4.*",
  • "symfony/console": "6.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": "5.4.*"
+       "require": "6.0.*"
      }
  }

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

1
$ composer update "symfony/*"

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

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

1
$ composer update symfony/symfony --with-dependencies

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

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

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

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

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

1
$ composer update

Caution

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

3) Updating Recipes

Over time - and especially when you upgrade to a new version of a library - an updated version of the recipe may be available. These updates are usually minor - e.g. new comments in a configuration file - but it's a good idea to keep your files in sync with the recipes.

Symfony Flex provides several commands to help upgrade your recipes. Be sure to commit any unrelated changes you're working on before starting:

1.18

The recipes:update command was introduced in Symfony Flex 1.18.

1
2
3
4
5
6
7
8
9
10
11
# choose an outdated recipe to update
$ composer recipes:update

# update a specific recipe
$ composer recipes:update symfony/framework-bundle

# see a list of all installed recipes and which have updates available
$ composer recipes

# see detailed information about a specific recipes
$ composer recipes symfony/framework-bundle

The recipes:update command is smart: it looks at the difference between the recipe when you installed it and the latest version. It then creates a patch and applies it to your app. If there are any conflicts, you can resolve them like a normal git conflict and commit like normal.

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

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

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

5.4

Проверка типа возвращаемого значения и исправление функций были представлены в Symfony 5.4.

Symfony 6 будет поставляться с нативными типами возвращаемых значений 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.