CLI tool
Ocramius/PackageVersions avatar
Ocramius/PackageVersions

PackageVersions: the version string is a commit hash, the optimized autoloader is required, and the mutation badge points at the wrong language

:package: Composer addon to efficiently get installed packages' version numbers

3,165 stars72 forksPHPMIT

At a glance

What is it?
Ocramius/PackageVersions is a Composer addon that reads installed package versions without touching the filesystem at runtime. Everything it reports is compiled during composer install, which is why the readme tells you to optimize the autoloader rather than merely suggesting it. The rest of the repository is small and mostly correct, apart from a badge aimed at a JavaScript tool and a branch that stopped at 2.0.x.
Who is it for?
Use it if your build step needs a dependency's version at runtime without a filesystem read, which is exactly the case it was written for, and turn the optimized autoloader on in the same change, since the no-IO guarantee depends on it. Do not expect a maintained feature pipeline from it: the default branch is 2.13.x, the newest release is 2.12.0, and the readme's own example still prints a 1.0.0 string.
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 1 day 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 November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • Ocramius/PackageVersions3,165 ★ · -4
Star history
Repository2026-09-242026-11-14
Ocramius/PackageVersions3.2k3.2k

-4 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The version string is a commit hash attached to a version number

One static method is the entire public API.

php
$version = \PackageVersions\Versions::getVersion('ocramius/package-versions');

var_dump($version); // 1.0.0@0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33

The output format is the interesting part, and the comment above is where it is documented. The string is a version, an at sign, and a full commit hash. That means the value is reproducible against the lock file rather than against a version range, which is what you want when the number is going into a generated artefact and someone has to trace it back to a tree.

The example is also old. It prints 1.0.0 while the project sits on the 2.x line, with 2.12.0 released on 2026-05-21, 2.11.0 on 2025-11-27, and 2.10.0 on 2025-02-05. Anyone copying the sample is copying a shape, not a version.

What the call does not do is read anything, which is the subject of the next section rather than this one.

Everything is compiled during composer install, so nothing is read at runtime

The use-case section states the design decision plainly: this repository implements PackageVersions\Versions::getVersion() in such a way that no IO happens when calling it, because the list of package versions is compiled during composer installation.

The data source is named in the purpose section: the composer.lock file, which is regenerated during composer install or composer update. So the values are read from the lock file at install time and written into generated code, and the runtime call is a lookup into that generated map.

The motivation given is cost. When you want to generate assets, code, or artefacts computed from the current version of a dependency, checking the installed version of a package at runtime would be too expensive, and this package mitigates that.

That framing explains the whole shape of the package. It is not a general Composer API client, and it does not expose the lock file at runtime. It is a generated lookup table with one accessor, which is also why it has two source directories and no runtime dependencies of its own to speak of.

The optimized autoloader is presented as a suggestion and behaves as a requirement

The installation step is one command:

sh
composer require ocramius/package-versions

After it comes a recommendation that carries a second instruction. It is suggested that you use an optimized Composer autoloader, to prevent autoload I/O when accessing the PackageVersions\Versions API, by adding a config block to composer.json:

json
...
    "config": {
        "optimize-autoloader": true
    },
...

If you generate the autoloader yourself from the CLI, the equivalent is a flag:

sh
composer dump-autoload --optimize

The reason to flag this is that the package's central claim and this setting are the same claim. A compiled version table still has to be loaded, and an unoptimized autoloader looks for class and map files on disk while doing it. So a project that installs this package to avoid runtime IO and then leaves the autoloader unoptimized has moved the IO rather than removed it. The readme says suggested; the mechanism makes it closer to required.

The mutation testing badge points at a JavaScript tool and a branch that stopped at 2.0.x

The badge row is where the documentation stops matching the repository.

The first badge is a link to a Stryker mutator dashboard, and its URL ends in the branch name 2.0.x. The default branch of this repository is 2.13.x. So the mutation testing report being advertised is one scoped to a branch that stopped two major lines ago.

The language is also wrong for the package. Stryker is a JavaScript mutation testing tool, while this is a PHP library, and the repository configures its own mutation testing through infection.json.dist.

Two other badges repeat. The Packagist link appears twice in the same position, and there are separate links for a Shepherd dashboard and for a Tidelift subscription.

None of this affects the code. It does mean the four signals a reader gets about project health, being mutation coverage, continuous integration status, Packagist, and a commercial support offering, include one that reports on something that is not this package's current code.

Support for private projects is routed to a paid subscription

The last section of the README is an enterprise pitch, and it ends with a condition worth reading.

The package is available as part of the Tidelift Subscription. The text describes the maintainer of ocramius/package-versions and thousands of other packages working with Tidelift to deliver commercial support and maintenance for open source dependencies, with the pitch being to save time, reduce risk, and improve code health while paying the maintainers of the exact dependencies you use.

The final line is the significant one: you can also contact the maintainer at [email protected] for looking into issues related to this package in your private projects.

So the repository defines two channels by audience. Open source users have the issue tracker, a security file, and a contributing guide. Private projects are directed to a paid arrangement or a direct email, and neither is described as a free support promise.

The license underneath all of this is MIT, with a LICENSE file at the root, and the repository is not archived.

The default branch is 2.13.x while the newest release is 2.12.0

The versioning position is one step ahead of the release list, which is worth knowing before you pin.

The default branch is named 2.13.x. The newest tag is 2.12.0, published on 2026-05-21, preceded by 2.11.0 in November 2025 and 2.10.0 in February 2025. The most recent commit is dated 2026-10-04.

So there is unreleased work on the default branch that no tag refers to, which is the normal arrangement for a maintained line and worth noting for anyone who compares a fork against master.

The branch naming is also the reason the readme's badges look odd, since a badge URL that hard-codes a branch name will silently report on the wrong tree as soon as the line moves, as this one did.

Nothing in the repository suggests a deprecation notice, an archive, or a successor package, and none of the search or installation material points at an alternative implementation.

The readme opens with a message addressed to Russian readers

The first substantive section of the README is not about the package.

It is headed as a message to Russian people, and it asks readers who currently live in Russia to read a separate document linked as ./ToRussianPeople.md. That file sits in the repository root alongside the composer.json and the source directory, so it is part of the source tree rather than something hosted elsewhere.

The positioning matters for anyone reading the repository top to bottom: the policy statement comes before the purpose statement, and the install instructions come third. That is a choice about what the project considers its first message.

It also means the repository carries a file with no technical content at all, which is unusual in a package whose entire footprint is a single accessor class, and it is one more thing to account for when mirroring or vendoring the tree.

What the document says is not visible here, so this section describes only its presence and its place in the file rather than its argument.

Five analysis configs, a committed lockfile, and two directories

The repository is small, and the root listing accounts for most of it.

There are two source directories, src/ and test/, and everything else in the root is configuration or governance. Quality tooling is extensive: phpcs.xml.dist for coding standards, psalm.xml for static analysis, phpunit.xml.dist for tests, infection.json.dist for mutation testing, and renovate.json for automated dependency updates. Continuous integration is configured through .laminas-ci.json.

Governance files sit alongside them. There is a CHANGELOG.md, a CONTRIBUTING.md, a SECURITY.md, and the ToRussianPeople.md described in the previous section.

One file stands out for a library of this size: composer.lock is committed to the repository. For an application that is normal, and for a library it means the dependency set used to build the library itself is pinned and auditable, at the cost of a lock file that has to be kept current.

There is also a packagist badge pointing at the lowercase package name, which is not the same string as the repository name.

Editorial conclusion

Use it if your build step needs a dependency's version at runtime without a filesystem read, which is exactly the case it was written for, and turn the optimized autoloader on in the same change, since the no-IO guarantee depends on it. Do not expect a maintained feature pipeline from it: the default branch is 2.13.x, the newest release is 2.12.0, and the readme's own example still prints a 1.0.0 string. And if you need support for a private project, note that the readme routes that to a paid subscription rather than to the issue tracker.

Frequently asked questions

What does a 0 major version mean?

This repository does not discuss major version zero. What it shows is its own output format, where a resolved version prints as a version followed by an at sign and a full commit hash, for example 1.0.0@0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33. The package itself is on the 2.x line, with the newest release 2.12.0 and the default branch named 2.13.x.

What are the available versions of NuGet?

Nothing here covers NuGet; this is a Composer addon for PHP projects. It reports versions taken from a composer.lock file, which is regenerated during composer install or composer update, and its own released versions are 2.12.0 from 2026-05-21, 2.11.0 from 2025-11-27 and 2.10.0 from 2025-02-05.

What are the best practices for versioning NuGet packages?

Nothing about NuGet appears in this repository. The one practice it documents is about Composer autoloading: enable an optimized autoloader, either by setting optimize-autoloader in the config block of composer.json or by passing --optimize to composer dump-autoload, because the version list is compiled at install time and the API reads it without touching the filesystem.

Does PackageVersions read composer.lock at runtime?

No. The stated design is that no IO happens when PackageVersions\Versions::getVersion() is called, because the list of package versions is compiled during composer installation. The readme gives the reason: checking the installed version of a package at runtime to compute generated artefacts would be too expensive.

How do I contact the maintainer of ocramius/package-versions?

The readme gives [email protected] for issues related to the package in private projects, and separately describes a paid route: the package is available as part of the Tidelift Subscription, where the maintainer delivers commercial support and maintenance. Open source issues go to the tracker. The license is MIT and the repository is not archived.

Official sources

  1. Issues
  2. License: MIT
  3. Ocramius/PackageVersions on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ocramius-packageversions.svg)](https://hysenlabs.com/projects/ocramius-packageversions)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/ocramius-packageversions.svg)](https://hysenlabs.com/projects/ocramius-packageversions)

Was this useful?