ocramius/package-versions
PackageVersions gives PHP applications fast, zero-I/O access to the installed versions of Composer dependencies. Version data is compiled from composer.lock at install time, so \PackageVersions\Versions::getVersion() returns a package's version and commit hash without any runtime disk reads—ideal fo...
Architecture fit
PackageVersions\Versions) exposing getVersion(string $package): string, returning 1.2.3@<commit-ref>. No service provider, no config file, no facade, no container bindings, no migrations — it sits alongside Laravel rather than inside it.composer install/update; 2.x delegates to Composer 2's own composer-runtime-api (Composer\InstalledVersions). That removes the install-time file mutation and the class of bugs that came with it (--no-scripts, --classmap-authoritative, vboxfs, composer remove, lock: false).Composer\InstalledVersions::getPrettyVersion() directly is the version@ref string format and an OutOfBoundsException on unknown packages. A TPM should treat this as a convenience wrapper, not infrastructure.Integration feasibility
composer require ocramius/package-versions and nothing else. Expected effort for the adoption itself: well under a day, including tests. The surrounding decisions (what consumes the version string, and whether to abstract it) dominate the cost.config.optimize-autoloader: true (or composer dump-autoload --optimize) to avoid autoload I/O on first access. Most Laravel production images already do this; verify rather than assume, because it is the only tuning knob that exists.Technical risk
InstalledVersions payload anyway.Dependents: 0 is inconsistent with 3.1k stars and heavy historical Packagist download volume; treat that field as unreliable for this package and do not use it in a build-vs-adopt argument.Versions::ROOT_PACKAGE_NAME constant in favour of rootPackageName(). Any tutorial, Stack Overflow snippet, or legacy snippet copied from 1.x-era content will break, which is a documentation and code-review risk more than a runtime one.Key questions
Composer\InstalledVersions directly."Composer\InstalledVersions and avoid the shim entirely.composer install at image build time with a lock file present, and does it reset OPcache / reload PHP-FPM after deploy? Both preconditions matter for correctness rather than for this package specifically.--no-dev used in production, and will any code path query a dev-only package name?Stack fit
app/Support/AppVersion.php or a ReleaseInfo value object — bound as a singleton, with PackageVersions\Versions (or Composer\InstalledVersions) called only inside it.PackageVersions\*. This keeps the exit cost of removing the dependency at roughly one file, which matters given the redundancy noted above./health or /version JSON response, an exception-reporter release field, a cache-key salt for asset/route caches, and a php artisan about-style diagnostic line.Migration path
composer require, add the wrapper, wire one consumer, add a feature/unit test asserting the wrapper returns a non-empty name@ref string for a known installed package and throws/returns null for an unknown one.PackageVersions\Versions calls (already-present transitive usage), invert the wrapper so it delegates to Composer\InstalledVersions::getPrettyVersion() plus getReference(), replicating the version@ref format. That is a mechanical change and eliminates the dependency outright.ROOT_PACKAGE_NAME constant and any assumption that a generated file exists in src/Packages/Versions.php (it does not in 2.x).Compatibility
composer-runtime-api); Composer 1 has been EOL since 2020, so this is a non-issue in practice but should be confirmed for any legacy CI image still on Composer 1.composer.json (e.g. "ocramius/package-versions": "^2.10") rather than allowing a floating ^2, otherwise a routine composer update on a PHP 8.2/8.3 app will fail resolution or force an unintended platform bump.--no-scripts, --classmap-authoritative, --no-dev, and read-only container filesystems, all of which were 1.x pain points. This is the single biggest compatibility improvement of 2.x and should be stated plainly in the ADR.Application::VERSION), Debugbar, Telescope, or Sentry SDKs; consumers are reading, not registering.Sequencing
composer.json require for the intended version. Gate everything else on this.version@ref vs version), and agree the unknown-package behaviour.Maintenance
InstalledVersions API or the PHP floor changes.Support
Composer\InstalledVersions is a one-file change with no data migration. This should be recorded as the explicit fallback in the ADR — it is the main reason the risk is acceptable at all.Scaling
optimize-autoloader enabled, access cost is a class-map hit.Failure modes
OutOfBoundsException when querying a package that is not installed in the current context — most commonly a dev-only dependency queried in a production image built with --no-dev. This is a configuration/consistency bug, not a package bug, but it will surface at runtime and must be handled in the wrapper (return null, log, never let it 500 a health endpoint).composer.lock at build time, or a composer install run outside the image build, yields wrong or absent version data. The version reflects the lock file, not the actual deployed code — if the image is built from a different commit than the lock file implies, the reported version is misleading.dev-<branch>@<ref> rather than a semver, so any consumer that parses or compares versions must handle that shape. Do not build logic that assumes semver.composer remove breakage, filesystem-specific install failures, global-vs-local plugin interference) are gone in 2.x but will reappear if anyone pins to a 1.x version for legacy reasons.Ramp-up
version@ref and may be a dev-* branch name; (b) the value is pinned at install time and requires OPcache reset on deploy; (c) the wrapper is the only sanctioned call site; (d) the removal path is Composer\InstalledVersions. Without (a)–(d) documented, the package will accumulate ad-hoc call sites and outlive its usefulness.How can I help you explore Laravel packages today?