Наше обещание обратной совместимости

Дата обновления перевода 2024-07-17

Наше обещание обратной совместимости

Гарантирование плавного обновления ваших проектов является нашим главным приоритетом. Поэтому мы обещаем вам обратную совместимость (ОС) для всех небольших релизов Symfony. Вы скорее всего знаете эту стратегию, как Семантическое версионирование. Кратко говоря, Семантическое версионирование означает, что только крупные релизы (вроде 5.0, 6.0 и т.д.) могут нарушать обратную совместимость. Небольшие релизы (вроде 5.1, 5.2 и т.д.) могут представлять новые функции, но должны делать это не нарушая существующий API этой ветки релиза (в предыдущем примере - 5.x).

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

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

Также, не каждая ОС имеет одинаковое влияние на код приложения. В то время, как некоторые поломки ОС требуют существенных изменений в ваших классах или архитектуре, другие исправляются простым изменением имени метода.

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

Второй раздел, "Работа над кодом Symfony", направлена на вкладчиков Symfony. Этот раздел печисляет подробные правила, которым дожен следовать каждый вкладчик, чтобы гарантировать плавные обновления для наших пользователей.

Caution

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

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

Использование кода Symfony

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

Использование наших интерфейсов

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

Caution

Исключением из этого правила являются интерфейсы, тегированные @internal. Такие интерфейсы не должны быть использованы или реализованы.

Если вы реализуете интерфейс, мы обещаем, что никогда не сломаем ваш код.

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

?????? ????????????? ???????? ?????????????
???? ??... ?? ?? ??????????? ??...
??????????? ????????? ? ?????????? ??
????????? ????? ?? [10]
???? ?? ?????????? ????????? ?... ?? ?? ??????????? ??...
?????????? ????? ??
?????????? ???????? ? ????????????? ????? ??
?????????? ???????? ?? ????????? ? ???????? ??
?????????? ?????????? ??? ? ???????????? ????? ??

Использование наших классов

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

Caution

Классы, свойства и методы, которые хранят тег @internal, а также классы, расположенные в различных пространствах имён *\Tests\ являются исключением из этого правила. Они предназначены только для внутреннего использования и не должны быть доступны из вашего собственного кода.

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

?????? ????????????? ???????? ?????????????
???? ??... ?? ?? ?????????? ??...
??????????? ????????? ? ?????? ??
???????? ????? ????????? ??
?????????? ????? ??
????????? ?????? ? ?????????? ???????? ??
????????? ????????? ????? ?? [10]
???? ?? ?????????? ????? ?... ?? ?? ?????????? ??...
????????? ?????? ? ??????????? ???????? ??
????????? ?????????? ????? ?? [10]
??????????????? ????????? ???????? ??
??????????????? ?????????? ???????? ??
??????????????? ????????? ????? ??
??????????????? ?????????? ????? ??
?????????? ????? ???????? ???
?????????? ????? ????? ???
?????????? ??????? ? ????????????????? ?????? ??
?????????? ? ????????? ???????? ?? ????????? ??
????????? ????????? ????? (????? Reflection) ???
????????? ?????? ? ???????? ???????? (????? Reflection) ???

Использование наших черт

Все черты, предоставленные Symfony могут быть использованы в ваших классах.

Caution

The exception to this rule are traits tagged with @internal. Such traits should not be used.

To be on the safe side, check the following table to know which use cases are covered by our backward compatibility promise:

?????? ????????????? ???????? ?????????????
???? ??... ?? ?? ?????????? ??...
??????????? ????? ??
???? ?? ??????????? ????? ?... ?? ?? ?????????? ??...
??????????? ?? ??? ?????????? ?????????? ??
??????????? ?? ??? ?????????? ???????????? ?????? ??
??????????? ?? ??? ?????????? ????????????? ?????? ??
??????????? ?? ??? ??????????? ???????????? ?????? ??
??????????? ?????????, ?????????? ??? ????????? ???????? ??
??????????? ?????????, ?????????? ??? ????????? ????? ??

Работа над кодом Symfony

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

Изменение интерфейсов

Эта таблица сообщает вам, какие изменения вам можно делать при работе с интерфейсами Symfony:

??? ????????? ????????? ????????? ??????????
??????? ????????? ???  
???????? ??? ??? ???????????? ???? ???  
???????? ???????????? ????????? ?? [2]
??????? ???????????? ????????? ???  
??????    
???????? ????? ???  
??????? ????? ???  
???????? ??? ???  
??????????? ???????????? ????????? ??  
???????? ???????? ??? ???????? ?? ????????? ???  
???????? ???????? ?? ????????? ?? ????????? ???  
??????? ???????? ??? [3]
???????? ???????? ?? ????????? ? ????????? ???  
??????? ???????? ?? ????????? ?? ????????? ???  
???????? ????????? ? ????????? ???  
??????? ????????? ????????? ???  
???????? ??? ????????? ???  
???????? ??? ???????? ???  
??????? ??? ???????? ??? [9]
???????? ??? ???????? ???  
??????????? ??????    
????????????? ?? ??????????? ? ??????????? ???  
????????????? ??????????? ? ?? ??????????? ???  
?????????    
???????? ????????? ??  
??????? ????????? ???  
???????? ???????? ????????? ?? [1] [5]

Изменение классов

Эта таблица расскажет вамо том, какие изменения разрешены при работе с классами Symfony:

Изменение черт

Эта таблица сообщает вам, какие изменения разрешены при работе с чертами Symfony:

Примечания

[1] Стоит избегать. Если же изменение сделано, оно должно быть задокументировано в файле UPGRADE.

[2] Добавленный родительский интерфейс не должен представлять никаких новых методов, не существующих в интерфейсе ранее.

[3] Только последний(ие) арумент(ы) метода могут быть удалены, так как PHP не волнуют дополнительные аргументы, которые вы передаёте методу.

[4] При изменении родительского класса, исходные родительский класс должен оставаться предшественником класса.

[5] Значение константы может быть изменено только когда константы не используют в конфигурации (например, файлах Yaml и XML), так как они не поддерживают константы и должны жёстко кодировать значение. Например, константы имён событий не могут изменять значение без поломки ОС. Кроме того, если константа будет скорее всего использована в сериализованных объектах, значение константы не должно быть изменено.

[6] Позволено использование аннотации @final.

[7] Разрешено, если класс финальный. Классы, получившие аннотацию @final после своего первого релиза, считаются финмальными в следующей полноценной версии. Изменение типа аргумента возможно только с родительским типом. Изменение типа возврата возможно только с дочерним типом.

[8] Разрешено, если метод финальный. Метод, получивший @final после своего первого релиза, считается финмальным в следующей полноценной версии. Изменение типа аргумента возможно только с родительским типом. Изменение типа возврата возможно только с дочерним типом.

[9] Разрешено для возврата типа void.

[10] Имена параметров охватываются обещанием об обратной совместимости только для конструкторов классов Атрибута. Использование PHP-именованых аргументов может сломать ваш код при обновлении на более новые версии Symfony.

Внесение изменений в код способом, обеспечивающим обратную совместимость

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

Добавление аргумента к публичному методу

Добавление нового аргумента к публичному методу возможно только в том случае, если это последний аргумент метода.

Если это так, то вот как правильно это сделать в младшей версии:

  1. Добавьте аргумент в качестве комментария в подписи:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // новый аргумент может быть опциональным
    public function say(string $text, /* bool $stripWithespace = true */): void
    {
    }
    
    // или обязательным
    public function say(string $text, /* bool $stripWithespace */): void
    {
    }
  2. Задокументируйте новый аргумент в PHPDoc:

    1
    2
    3
    /**
     * @param bool $stripWithespace
     */
  3. Используйте func_num_args и func_get_arg для получения аргумента в методе:

    1
    2
    3
    $stripWithespace = 2 <= \func_num_args() ? func_get_arg(1) : false;
    
    Обратите внимание, что значение по умолчанию - ``false``, чтобы сохранить текущее поведение.
  4. Если аргумент имеет значение по умолчанию, это изменит текущее поведение, предупредите пользователя:

    1
    trigger_deprecation('symfony/COMPONENT', 'X.Y', 'Not passing the "bool $stripWithespace" argument explicitly is deprecated, its default value will change to X in Z.0.');
  5. Если аргумент не имеет значения по умолчанию, предупредите пользователя, что это будет необходимо в следующей старшей версии:

    1
    2
    3
    4
    5
    6
    7
    if (\func_num_args() < 2) {
        trigger_deprecation('symfony/COMPONENT', 'X.Y', 'The "%s()" method will have a new "bool $stripWithespace" argument in version Z.0, not defining it is deprecated.', __METHOD__);
    
        $stripWithespace = false;
    } else {
        $stripWithespace = func_get_arg(1);
    }
  6. В следующей старшей версии (X.0) раскомментируйте аргумент, удалите PHPDoc, если нет необходимости в описании, и удалите код func_get_arg и предупреждение, если они есть.