
Однажды вы присоединяетесь к проекту на Laravel.
Клонируете репозиторий, запускаете:
composer install
Всё работает идеально.
Через несколько дней к тому же проекту присоединяется другой разработчик.
Он запускает ту же команду.
Но внезапно…
«Почему у меня установилась другая версия пакета?»
Вы проверяете проект и замечаете два важных файла:
composer.json composer.lock
На первый взгляд они выглядят похоже.
Оба относятся к зависимостям Composer.
Так в чём же реальная разница?
Давайте разберемся на простой истории.
Знакомьтесь, composer.json
Относитесь к composer.json как к списку покупок для вашего проекта.
Вы говорите Composer:
«Вот эти пакеты нужны моему проекту».
Например:
{
"require": {
"php": "^8.2",
"laravel/framework": "^12.0",
"laravel/sanctum": "^4.0"
}
}Это не обязательно указывает Composer точную версию, которую он должен установить.
Например:
laravel/framework: ^12.0
означает:
«Дай мне совместимую версию Laravel 12.x в соответствии с этим ограничением».
Таким образом, у Composer есть определенная гибкость при разрешении (resolve) зависимостей.
Кто же тогда определяет точную версию?
Здесь вступает в игру наш второй файл:
composer.lock
Представьте composer.lock как итоговый кассовый чек.
Он фиксирует точные версии пакетов, которые разрешил Composer.
Что-то вроде:
laravel/framework → 12.35.1 laravel/sanctum → 4.2.0 symfony/console → 7.3.2
То есть связь следующая:
composer.json
↓
"Какие пакеты мне нужны?"
↓
Разрешение зависимостей в Composer
↓
composer.lock
↓
"Были отобраны именно эти версии."Пример из реальной жизни
Представьте, что вы создаете приложение на Laravel сегодня.
В вашем composer.json указано:
"laravel/framework": "^12.0"
Сегодня Composer может разрешить:
Laravel 12.30.0
Месяц спустя Laravel выпускает:
Laravel 12.35.1
Теперь другой разработчик клонирует проект.
Без composer.lock
Composer может разрешить более новую совместимую версию:
12.35.1
На вашей машине:
12.30.0
У другого разработчика:
12.35.1
И теперь вы получаете классическое:
«Но на моей машине всё работает!»
И начинается отладка.
Что происходит при наличии composer.lock?
Предположим, в проекте уже есть:
laravel/framework → 12.30.0
зафиксированная в composer.lock.
Другой разработчик клонирует проект и запускает:
composer install
Composer использует lock-файл и устанавливает зафиксированные в нём версии.
Итог:
Developer 1 → 12.30.0 Developer 2 → 12.30.0 Developer 3 → 12.30.0 Production → 12.30.0
Гораздо более предсказуемо.
Самое главное отличие
Вот самый простой способ это запомнить:
ФайлНазначениеcomposer.jsonОпределяет требования к зависимостямcomposer.lockСохраняет точные разрешенные версии
Или еще проще:
composer.json = What I want composer.lock = What I got
Что происходит при запуске composer install?
Именно здесь многие разработчики путаются.
Когда composer.lock существует:
composer install
Composer устанавливает версии, зафиксированные в lock-файле.
Поэтому эту команду обычно используют при развертывании существующего проекта.
Например:
git clone project cd project composer install
После этого ваша среда получает именно те версии зависимостей, которые ожидает проект.
Что происходит при запуске composer update?
Здесь всё иначе.
Когда вы запускаете:
composer update
Composer смотрит в:
composer.json
и заново разрешает зависимости.
Он может найти более новые версии, удовлетворяющие вашим ограничениям версий.
Затем Composer обновляет:
composer.lock
Например:
Before Laravel → 12.30.0 composer update After Laravel → 12.35.1The lock file changes because the dependency resolution changed.
Типичный сценарий в Laravel
Представьте, что ваш проект содержит:
"require": {
"laravel/framework": "^12.0",
"spatie/laravel-permission": "^6.0"
}Ваш lock-файл может содержать:
laravel/framework → 12.30.0 spatie/laravel-permission → 6.20.0
Теперь Spatie выпускает:
6.21.0
Ваш composer.json не обязательно должен меняться, потому что:
^6.0
уже разрешает совместимые версии 6.x.
Запуск:
composer update
может обновить пакет в composer.lock.
Но запуск:
composer install
обычно сохранит версии, уже зафиксированные в lock-файле.
Нужно ли коммитить composer.lock в Git?
Для большинства приложений — да.
Например, репозиторий приложения на Laravel обычно содержит:
app/ bootstrap/ config/ database/ resources/ routes/ composer.json composer.lock
Коммитьте оба:
git add composer.json composer.lock git commit -m "Update dependencies"
Почему?
Потому что вашей команде нужны предсказуемые версии зависимостей во всех окружениях:
Local ↓ Development ↓ Staging ↓ Production
В идеале все должны использовать одинаковый набор зависимостей.
А как насчет PHP-пакетов?
Существует важное различие между проектом/приложением и переиспользуемым пакетом/библиотекой.
Для приложения на Laravel:
composer.lock
обычно закоммичен.
Для переиспользуемого PHP-пакета lock-файл обычно не коммитится как часть публикуемого контракта зависимостей, поскольку потребителям пакета нужно, чтобы Composer разрешал зависимости в контексте их собственных проектов.
Это различие важно при работе с пакетами, публикуемыми на платформах вроде Packagist.
Создается ли composer.lock автоматически?
Обычно он генерируется, когда Composer разрешает и устанавливает зависимости для проекта.
Например:
composer install
или:
composer update
могут создать или обновить lock-файл в зависимости от состояния проекта и команды.
Типичный проект может начинаться с:
composer.json
Затем после разрешения зависимостей появится:
composer.json composer.lock vendor/
Что находится внутри composer.lock?
Lock-файл содержит гораздо больше деталей, чем просто названия пакетов.
Он фиксирует такую информацию, как:
Package name Version Source Distribution Dependencies PHP requirements Hashes / metadata
Упрощенный пример:
{
"name": "laravel/framework",
"version": "v12.30.0",
"require": {
"php": "^8.2"
}
}Реальный lock-файл намного больше, так как сам Laravel зависит от множества других пакетов.
У Laravel больше зависимостей, чем вы думаете
Вы можете написать:
"laravel/framework": "^12.0"
Но Laravel зависит от множества других пакетов Symfony и экосистемы PHP.
Поэтому Composer создает дерево зависимостей:
Your Laravel App
|
└── Laravel Framework
|
├── Symfony Console
├── Symfony HTTP Foundation
├── Symfony Routing
├── Symfony Process
└── ...composer.lock фиксирует итоговый граф зависимостей.
Это одна из причин, почему этот файл может быть достаточно большим.
Ошибка, которую часто допускают разработчики
Представьте, что вы подтягиваете свежий код:
git pull
и кто-то изменил:
composer.json composer.lock
Затем вы запускаете:
composer update
просто потому что хотите установить новый пакет.
Это может обновить и множество других зависимостей.
Вы можете неожиданно обновить пакеты, которые до этого работали корректно.
Для существующего проекта обычно безопаснее использовать:
composer install
когда lock-файл уже содержит нужный набор зависимостей.
Когда следует использовать composer update?
Используйте его, когда вы намеренно хотите заново разрешить или обновить зависимости.
Например:
composer update
или для точечного обновления, например:
composer update laravel/framework
После проверки и тестирования изменений закоммитьте обновленный lock-файл.
Золотое правило
Запомните эти две команды:
composer install
↓
Используйте зафиксированные версии зависимостей.
↓
composer update
↓
Повторно разрешить зависимости
↓
Update composer.lockИ эти два файла:
composer.json
↓
Dependency rules / requirements
↓
composer.lock
↓
Exact resolved dependency versionsИтоговая мысль
Самая простая аналогия такова:
composer.json — это ваш рецепт.
Он говорит:
«Мне нужны Laravel, Sanctum, Spatie Permission и PHP 8.2+».
composer.lock — это точный список выбранных ингредиентов.
Он говорит:
«Вот точные версии каждого ингредиента, с которыми приложение заработало вместе».
Вот почему оба файла важны, но они служат совершенно разным целям.
Когда вы работаете в команде над проектом на Laravel, понимание этой разницы может спасти вас от одной из самых частых проблем с зависимостями:
«На моей машине всё работает, а на твоей — нет».
Так что в следующий раз, когда увидите:
composer.json composer.lock
помните:
JSON определяет правила.
LOCK фиксирует результат.
Удачного кодинга! 🚀
Комментарии (0)
Пока нет комментариев — будьте первым.