pretty-package-versions: one call for a dependency's version, on Composer 1 or 2
A small, independent wrapper to get pretty versions strings
At a glance
- What is it?
- This small PHP package answers a narrow question, that is what version of a dependency is actually installed, and answers it identically on Composer 1 and Composer 2. It started as a wrapper around another package and now mostly exists to keep working across the Composer 2 transition.
- Who is it for?
- pretty-package-versions fits a library that has to report the version of one of its dependencies at runtime and still supports users on Composer 1, since that is the case the compatibility chart is built for.
- 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 123 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 October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One static call, one value object
The entire API of the package is a single class with a single method, and it is used like this:
use Jean85\PrettyVersions;
$version = PrettyVersions::getVersion('phpunit/phpunit');
$version->getPrettyVersion(); // '6.0.0'
$version->getShortVersion(); // '6.0.0'
$version->getVersionWithShortReference(); // '6.0.0@fa5711'
$version = PrettyVersions::getVersion('roave/security-advisories');
$version->getPrettyVersion(); // 'dev-master@7cd88c8'
$version->getShortVersion(); // 'dev-master'
$version->getVersionWithShortReference(); // 'dev-master@7cd88c8'`PrettyVersions::getVersion()` takes a package name and returns a `Jean85\Version` object for the requested package. The two examples show why the object has more than one accessor: a package installed from a tag reports `6.0.0`, while a package installed from a branch reports `dev-master`, and the pretty version for the second case is the same as the version with the short reference, because there is no release version to show.
The `Version` class also implements `__toString()`, so the object can be cast to a string, and the result is the same as calling `getPrettyVersion()`. That is a small convenience with a real effect in practice, because the usual place for a version string is inside a `User-Agent` header, a support page or a CLI banner, where interpolating the object is much more convenient than remembering which accessor to call.
The package is MIT licensed, the primary language is PHP, the default branch is `2.x`, and the last push was on 2026-06-22. The recent releases are 2.1.1 from 2025-03-19, 2.1.0 from 2024-11-18 and 2.0.6 from 2024-03-08.
Eight accessors, and a rename in 2.0
The `Version` class exposes a small set of public methods, and reading them together explains what the package is really reporting.
`getPrettyVersion()` returns just the short version if the requested package is a tagged version, and otherwise the same result as `getVersionWithShortReference()`. `getShortVersion()` returns just the version of the package, in whatever form it has, such as `6.0.0`, `v.1.7.0` or `99999-dev`. `getReference()` returns the reference of the installed package, generally the full Git commit hash, and `getShortReference()` returns the shortened version of it, such as `fa5711`. `getVersionWithShortReference()` combines the two, such as `6.0.0@fa5711`. `getPackageName()` returns the original package name. `getFullVersion()` returns the same value as `PackageVersions\Versions::getVersion()`, and `__toString()` returns the same as `getPrettyVersion()`.
Two methods were added in 1.5. `PrettyVersions::getRootPackageName` returns the package name of the current root project, which is the `name` property in your `composer.json`, and it exists as a compatibility layer for `PackageVersions\Versions::ROOT_PACKAGE_NAME`, which would otherwise be a transient dependency that is not guaranteed to be present. `PrettyVersions::getRootPackageVersion` is a shortcut to `getVersion()` of that name.
The rename in 2.0 is about vocabulary. The methods with `reference` in the name were introduced in the 2.0 release, to better reflect the meaning of the data retrieved from the Composer 2 API, and the old methods are still present but deprecated:
| New method | Old, deprecated method | |---|---| | `Version::getReference()` | `Version::getCommitHash()` | | `Version::getShortReference()` | `Version::getShortCommitHash()` | | `Version::getVersionWithShortReference()` | `Version::getVersionWithShortCommit()` |
The behaviour is the same in both sets, so an application can migrate by renaming, which is the kind of change that belongs in a major version and is the reason 2.0 exists.
The compatibility chart is the real documentation
The package was born as a thin wrapper for `ocramius/package-versions`. With the advent of Composer 2, that wrapper is no longer needed, since `Composer\InstalledVersions` can be used directly. That history produced the compatibility chart, which is the most useful table in the README.
| `pretty-package-versions` | Composer | Dependency used | |---|---|---| | Up to 1.2 | 1.x only | `ocramius/package-versions` | | 1.3 | Both 1.x and 2.x | `composer/package-versions-deprecated`, fork of `ocramius/package-versions` | | 1.4 | 2.x only | None | | 1.5+ | Both 1.x and 2.x | `composer/package-versions-deprecated`, fork of `ocramius/package-versions` | | 2.0 | 2.x only | None |
The point of the chart is that with this package you can obtain pretty versions without tying your user to any specific Composer version, with a smooth upgrade path.
The row for 1.4 is unusual. The README explains that the release of 1.4 was reverted due to some discussion in issue 21 and related issues, which is a reminder that a package that exists to be unobtrusive can still have a contentious release history. The chart lists 1.4 as a row anyway, so a reader can see what was attempted and what it was reverted to.
The dependency column is the part to read before installing. Versions 1.3 and 1.5 use `composer/package-versions-deprecated`, a fork of the original package, and versions 1.4 and 2.0 use nothing at all. So the version that has no dependencies of its own is also the version that only works on Composer 2, and that is the trade the whole package exists to make.
Installation and the constraint that matters
The package is installed with Composer, in the usual two ways.
From the command line:
composer require 'jean85/pretty-package-versions:^1.5 || ^2.0'Or directly in the `composer.json` file:
{
"require": {
"jean85/pretty-package-versions": "^1.5 || ^2.0"
}
}The constraint is the interesting part, and the README gives the reason. If you use this package in a library, you are encouraged to require it with a constraint of `^1.5 || ^2.0`, to obtain all the functionalities without constraining your end users to upgrade immediately to Composer 2.
That is a rule about who is affected by a dependency constraint. A library that requires `^2.0` forces every application that installs it onto Composer 2, whether or not that application needs anything from version 2. A library that requires `^1.5 || ^2.0` lets the resolver pick the version that matches the Composer in use, so a user on Composer 1 gets the branch that works with Composer 1 and a user on Composer 2 gets the branch that has no dependencies.
The package supports PHP `^7.1|^8.0`, and the badge in the README reflects the same range. Both version lines support PHP `^7.1|^8.0`, which is what makes the pair of constraints in the install instruction coherent.
The releases on Packagist are tagged without a prefix, 2.1.1, 2.1.0, 2.0.6, and the default branch is `2.x`, so the version line a project is on is visible in the constraint it writes.
Four static analysers and a formatter in the Makefile
The repository is small, and the tooling is the clearest sign of how it is maintained.
pre-commit-check: composer cs phpstan psalm test
cs:
vendor/bin/php-cs-fixer fix --verbose
phpstan:
vendor/bin/phpstan analyze
psalm:
vendor/bin/psalm
test:
vendor/bin/phpunitThe `pre-commit-check` target chains the whole chain: install the dependencies, apply the code style, run PHPStan, run Psalm, run the test suite. The individual targets are what a contributor runs while working, and there is a `cs-dry-run` variant that applies the formatter in check mode rather than writing changes, which is what the continuous integration would use.
Running two static analysers is unusual, and it is worth reading as a signal rather than as a detail. PHPStan and Psalm overlap heavily in what they catch, so the redundancy is deliberate belt and braces, or a transition from one to the other, and either way it says the package is checked before it ships.
The rest of the root directory matches that picture. There is a `.php-cs-fixer.dist.php` for the style rules, a `phpstan.neon` and a `psalm.xml` for the analysers, a `phpunit.xml.dist` for the test configuration, a `rector.php` for automated refactoring, a `codecov.yml` and a codecov badge for coverage reporting, a `CHANGELOG.md` and a `LICENSE` file, and the `src/` and `tests/` directories.
The build badge points at a `tests.yaml` workflow on the `2.x` branch, which is the branch the current work happens on.
Where pretty-package-versions is the wrong tool
The limits are small, which is to be expected from a package with one class.
The first is that it answers a question about the environment, not about your code. Every method describes a package that is installed, so the version of a package you merely require in your `composer.json` but that is not present in a given installation is not available. That is usually the desired behaviour for a diagnostic screen, and it is a limitation for anything that wants to display a compatibility matrix of versions the project supports rather than versions it has.
The second is that on Composer 2 the package is a thin layer over something that already exists. The README says it plainly: with the advent of Composer 2 this is no longer needed, since `Composer\InstalledVersions` can be used directly. A new application that requires Composer 2 can call that class itself, and the only thing the wrapper adds is a stable set of method names and a `__toString()`. That is a real convenience, and it is also a dependency to keep up to date for a capability the platform now provides.
The third is the fork in the middle. The versions that support Composer 1 depend on `composer/package-versions-deprecated`, which is a fork of a package that was deprecated in the first place. Depending on a deprecated package, even a maintained fork of it, is a cost that the chart documents honestly and that a project with a modern Composer never has to pay.
The alternative for a Composer 2 only application is to call `Composer\InstalledVersions` directly and format the version yourself, which is a handful of lines and no dependency. The difference in approach is that this package exists to make one answer identical on two Composer generations, and the alternative accepts that the two generations have different answers so that a project can support one of them. For a library with users on both, that is a fair trade, and for an application that does not need to support Composer 1, it is an extra dependency for a marginal gain in ergonomics.
Editorial conclusion
pretty-package-versions fits a library that has to report the version of one of its dependencies at runtime and still supports users on Composer 1, since that is the case the compatibility chart is built for. It is the wrong choice for a new Composer 2 only application, where `Composer\InstalledVersions` is already there and needs no wrapper, and it is the wrong choice for a package that wants to report the version of a dependency it does not require, because the answer is only available for packages that are actually installed. Before adding it, check the compatibility chart row for the version you would install, since 1.3 and 1.5 pull in the deprecated `composer/package-versions-deprecated` fork while 1.4 and 2.0 need nothing at all, and remember that the 2.0 release renamed the reference methods and deprecated the old commit-hash ones.
Frequently asked questions
How do I install pretty-package-versions?
From the command line with `composer require 'jean85/pretty-package-versions:^1.5 || ^2.0'`, or by adding the same constraint to the require section of your composer.json. The README recommends that constraint for libraries, because it gets the functionality without forcing end users to upgrade to Composer 2 immediately.
How do I get the installed version of a dependency?
Call `PrettyVersions::getVersion('phpunit/phpunit')`, which returns a `Jean85\Version` object. `getPrettyVersion()` returns '6.0.0' for a tagged package and the version with the short reference for a branch build, while `getShortVersion()` returns only the version and `getVersionWithShortReference()` returns '6.0.0@fa5711'.
What changed in pretty-package-versions 2.0?
The methods with reference in the name were introduced, `getReference()`, `getShortReference()` and `getVersionWithShortReference()`, to better reflect the data retrieved from the Composer 2 API. The previous commit-hash methods are still present but deprecated, and the behaviour is identical.
Does pretty-package-versions still depend on ocramius/package-versions?
Only in some versions. The compatibility chart shows that 1.4 and 2.0 need no dependency at all, because Composer 2 exposes `Composer\InstalledVersions`, while 1.3 and 1.5 use `composer/package-versions-deprecated`, a fork of ocramius/package-versions.
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/jean85-pretty-package-versions)Was this useful?