Ocramius/PackageVersions: reading Composer dependency versions without runtime IO
:package: Composer addon to efficiently get installed packages' version numbers
At a glance
- What is it?
- PackageVersions compiles installed Composer package versions into the generated autoloader so that Versions::getVersion() returns a version string without touching composer.lock at runtime. It is a small PHP utility for code that needs a dependency's exact version while it runs.
- Who is it for?
- Adopt it if your PHP code needs a dependency's exact installed version at runtime and you already run an optimized Composer autoloader, since the README states the version list is compiled during composer installation and no IO happens on the call. Skip it if you only need versions in build scripts or CI, where composer.lock is readable directly, or if you cannot set optimize-autoloader.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What PackageVersions solves for PHP code that needs a dependency version at runtime
A PHP application often needs to know which version of a dependency is installed. The obvious approach is to read composer.lock at runtime, but that means parsing a file on every request or every time the value is needed. PackageVersions takes a different route: it derives version information from composer.lock, which is regenerated during composer install or composer update, and exposes it through a static call. The README states the purpose plainly: quick and easy access to version information of Composer dependencies, derived from the lock file.
The audience is narrow and specific. This is for library and application code that has to branch on a dependency version, or that has to embed a version into a generated asset, a cache key, or a diagnostic string. The README names the use case: generating assets, code or artifacts computed from the current version of a dependency, where checking the installed version at runtime would be too expensive. If your code never needs a dependency's version while it runs, this package adds a dependency for nothing.
How the version list gets compiled into the autoloader
The mechanism is the interesting part, and it is a build-time trick rather than a runtime lookup. The README says the repository implements Versions::getVersion() in such a way that no IO happens when calling it, because the list of package versions is compiled during composer installation. That means the cost is paid once, when Composer writes the autoloader, and the call itself reads a value that is already in memory.
The README gives this example of the API and its return value:
$version = \PackageVersions\Versions::getVersion('ocramius/package-versions');
var_dump($version); // 1.0.0@0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33The returned string is not a bare version number. It is the version followed by an @ sign and a commit hash, as the comment in the example shows. Any code that compares this value to a plain version string, or that stores it in a column sized for a version number, will need to account for that format. The README does not document a second method for getting the version without the hash, so the hash is part of the contract.
Because the list is compiled into the autoloader, the data flow is: composer install or composer update writes composer.lock, the package reads that lock file during installation, and the generated autoloader carries the result. Nothing in the call path reads composer.lock afterwards. That is the whole design, and it explains why the optimized autoloader matters.
Installing PackageVersions and making a first call
Install it with Composer. The README gives a single command:
composer require ocramius/package-versionsAfter that, the README suggests using an optimized Composer autoloader to prevent autoload IO when accessing the PackageVersions\Versions API. In composer.json that is a config entry:
{
"config": {
"optimize-autoloader": true
}
}If you generate the autoloader from the command line instead, the README gives the flag form:
composer dump-autoload --optimizeWith the package installed, the first real use is the call shown earlier. Ask for a package you actually depend on, not the package itself, and dump the result:
$version = \PackageVersions\Versions::getVersion('ocramius/package-versions');
var_dump($version);What you should see is a string in the form of a version, an @ sign, and a hash, matching the shape in the README example. If the autoloader was not optimized, the README's guidance implies you may pay autoload IO for the call, which defeats the point of the package. The README does not show a failure case for a package that is not installed, so treat an unknown package name as undocumented behaviour and test it yourself before relying on it.
The format of the returned value is the sharp edge
The version string includes a commit hash after the @ sign. The README example makes this explicit, but it is easy to skim past. Code that does a strict comparison against a version constant, or that writes the value into a database column or a log field with a fixed width, will behave differently than expected. This is not a bug; it is the documented output. The practical consequence is that callers need to split on @ if they want the version alone, and the README does not document a helper for that.
The second limitation is the dependency on the optimized autoloader. The README suggests it rather than requiring it, but the performance argument for the package rests on it. If your project cannot enable optimize-autoloader, for example because of a build pipeline that generates the autoloader differently, you lose the property that made the package worth adding. The README does not document what happens to the API when the autoloader is not optimized beyond the general note about autoload IO.
A third boundary: this is a read-only view of what is installed. It does not resolve versions, check constraints, or tell you what is available. It answers one question, what version of this package is installed here, and nothing else. The README does not document rollback, so if an install goes wrong the package offers no recovery path of its own.
Where PackageVersions is the wrong tool
If you need version information in a build script, a CI step, or a deployment job, you do not need this package. Those contexts can read composer.lock directly or run composer show, and they run once rather than per request. Adding a runtime dependency to solve a build-time problem inverts the cost.
If you need to know whether a version satisfies a constraint, this package is also the wrong tool. It reports the installed version; it does not evaluate semver ranges. Composer itself does that during resolution, and the lock file records the outcome. PackageVersions only surfaces the outcome.
Finally, if your application does not use Composer at all, or vendors dependencies by hand, the package has nothing to read. Its data source is composer.lock, and the README is explicit that the information is derived from that file.
How it compares to reading composer.lock directly
The direct alternative is to parse composer.lock yourself, or to shell out to Composer at runtime. The difference is where the work happens. Reading the lock file at runtime means file IO and JSON parsing on the call path, and the README frames that as too expensive for the use case it targets. PackageVersions moves that work to install time and leaves a static call behind.
The trade-off is freshness and coupling. A direct read always reflects the current lock file, while the compiled list reflects the lock file as it was when the autoloader was generated. In a normal Composer workflow those are the same, because install and update regenerate both. But if someone edits composer.lock without regenerating the autoloader, the two diverge, and the package will report the older value. The README does not discuss this scenario, so it is worth knowing before you depend on the value for anything that must be exact.
A second alternative is a build step that writes a version constant into your own generated file. That gives you full control over the format, including dropping the hash, at the cost of writing and maintaining the generator. PackageVersions is the off-the-shelf version of that idea, with the format fixed by the library.
Maintenance, licence and upgrade cost
The repository is not archived, and the last push was on 2026-09-22. Recent releases listed are 2.12.0 on 2026-05-21, 2.11.0 on 2025-11-27 and 2.10.0 on 2025-02-05, so releases have arrived roughly every six to nine months. The default branch is 2.13.x, which suggests the next line is already in progress. The README also points to a Tidelift subscription for commercial support and to the maintainer's email for private project issues, which is where enterprise users are directed for support terms.
The licence is MIT, which permits commercial use and modification with the usual requirement to keep the licence notice. That is a permissive arrangement, but it is not legal advice and your organisation should read the LICENSE file itself.
Upgrade cost is low by design. The public surface described in the README is one static method, so a major version bump is unlikely to require broad code changes unless the return format changes. The format, version plus @ plus hash, is the part to watch across upgrades, since callers that parse it will feel any change first.
Editorial conclusion
Adopt it if your PHP code needs a dependency's exact installed version at runtime and you already run an optimized Composer autoloader, since the README states the version list is compiled during composer installation and no IO happens on the call. Skip it if you only need versions in build scripts or CI, where composer.lock is readable directly, or if you cannot set optimize-autoloader. Verify first that your project's composer.json has config.optimize-autoloader set to true, that the version string format (version plus @ plus hash) is what your consumer expects, and that the package is still the right choice for your PHP version, because the README does not document rollback or a supported PHP version range.
Frequently asked questions
Does PackageVersions read composer.lock at runtime?
No. The README states that the implementation avoids IO when calling Versions::getVersion() because the list of package versions is compiled during composer installation. The lock file is the source, but it is read at install time, not on the call path.
Why does PackageVersions suggest an optimized Composer autoloader?
The README suggests it to prevent autoload IO when accessing the PackageVersions\Versions API. You can set optimize-autoloader to true in composer.json, or run composer dump-autoload --optimize if you generate the autoloader from the CLI.
What format does PackageVersions return for a version?
The README example shows a version followed by an @ sign and a commit hash, such as 1.0.0@0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33. The README does not document a method that returns the version without the hash.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ocramius-packageversions)