Ответ 1
Документация Composer дает два основных примера. Я постараюсь объяснить:
Перечисляет пакеты, которые заменены этим пакетом. Это позволяет вам разветвлять пакет, публиковать его под другим именем со своими собственными номерами версий, в то время как пакеты, требующие исходного пакета, продолжают работать с вашим ответвлением, поскольку он заменяет исходный пакет.
Предположим, что ваше программное обеспечение использует original/library
и other/package
, для которого также требуется original/library
.
Теперь вы думаете, что original/library
должны интегрировать функцию, но сопровождающие не допустят, чтобы ваше предложение появилось в их пакете. Вы решаете раскошелиться на эту библиотеку под именем better/library
и отметить новую версию.
Вернуться к вашему программному обеспечению. Конечно, он должен начать использовать better/library
, так что вместо этого вам нужно, но этот other/package
все еще требует original/library
- дублирование кода! Как вы можете заставить этот другой пакет использовать вашу better/library
вместо этого, не разветвляя ее и только изменяя composer.json (вы все еще совместимы с этим original/library
, поэтому он должен работать)?
Вы добавляете ключ замены в ваш composer.json
:
"replace": {
"original/library":"1.0.2"
}
Теперь Composer знает, что любой пакет из вашей better/library
одинаково хорош как original/library
когда дело доходит до разрешения зависимостей other/package
.
Это также полезно для пакетов, которые содержат подпакеты, например, основной пакет symfony/symfony содержит все компоненты Symfony, которые также доступны в виде отдельных пакетов. Если вам требуется основной пакет, он автоматически выполнит любое требование одного из отдельных компонентов, поскольку он заменяет их.
Те же правила, немного другой угол. Требование компонентов каркаса является хорошим подходом для любого другого компонента, который нуждается в некоторой функции. Но если вам требуется полная платформа в вашем программном обеспечении и другая библиотека, для которой впоследствии также требуется компонент этой платформы, объявление replace
платформы позволяет Composer не устанавливать дважды этот единственный компонент, поскольку он уже включен в полная структура.
Осторожно: заполнители в замененных версиях обычно плохие
В своем первоначальном ответе я предложил:
"replace": {
"original/library":"1.*"
}
Это имеет последствия: Composer теперь будет рассматривать вашу библиотеку версии 1.0.0 так же хорошо, как ЛЮБУЮ версию 1.x оригинальной библиотеки, даже если они исправят вещи или добавят функции и выпустят версию 1.2.34 когда-нибудь. Это также означает, что если ваш other/package
нибудь получит обновление и требует original/library:^1.1
, замена в ВАШЕЙ библиотеке все еще активна и заявляет, что она может заменить ЛЮБУЮ версию 1.*
, даже если вы ничего не обновляете внутри - что это невозможно, ваш старый код никогда не будет реализовывать новые функции исходной библиотеки, если вы не проделаете какую-то работу, но замена говорит именно об этом.
Итак, по сути: избегайте подстановочных версий в заменяющей версии! Если вы используете их, вы делаете выражение о будущем, которое вы не можете знать или предсказать (если вы не можете контролировать original/library
, но даже тогда будьте очень осторожны). Всегда используйте конкретную версию original/library
которую вы знаете и можете полностью реализовать заново.