Composer is dependency management for PHP, and it consists of two main files:
- composer.json where you specify your dependencies
- composer.lock where composer itself records exactly which precise version of every library and every dependency of every library it picked, so all installs will be identical
Crucially, the composer.lock also includes a hash of the current composer.json when it updates, so you can always tell if you've added a requirement to the composer.json file and forgotten to install it.
In that case, you'll see an error message like:
Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.
You now have three options: upgrade everything, figure it out, or do nothing.
Option one: upgrade all of the things
composer update
This will upgrade ALL packages to their newest possible allowed version, and bring every package in composer.json into sync with composer.lock. This definitely will make the error message go away but it may introduce other unexpected changes since you're now running with new versions of all your packages. As long as you understand that you need to do all of the testing again at this point, you can take this approach. I could argue that it is good to refresh packages (especially if they have security updates) and that semantic versioning will protect us from breakages. In practice, this approach works but is a little bit risky.
Option two: try to work out which composer.json change caused this
Remember that composer.lock contains a hash, so any slight whitespace change as a result of a source control merge or something will cause the hash to be out of date. A safer approach than option one is to ask Composer what it would do if it were allowed to upgrade everything:
composer update --dry-run
In this output you should see lots of upgrades, so if the change in composer.json is a version change, it will be hard to spot. However if a new dependency has been added to composer.json and we just somehow forgot to install it, you'll see it showing up as a new install (and similarly if something was removed, that shows as an uninstall). Often this is all you need to know - you can then just update that individual package to get things back in sync.
composer update [package]
This approach only updates the package whose required version changed without needing to update all the dependencies in a project. I would also use this command when adding a new package or wanting to upgrade a specific package.
Option three: do nothing, safely
If you think that your files are correct and the hash of the file is just wrong for some reason, you can cause Composer to update the hash of composer.json stored in composer.lock by simply doing:
composer update nothing
Sometimes this is the right answer so it's a handy trick to know!. I seem to see these kinds of issues in people's projects quite often (I'm a consultant, I see a lot of projects) so I thought I'd share my usual tactics for getting things sorted - if you have any tricks of your own to share, I'd love to hear them :)