Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Package Versions Laravel Package

samsonasik/package-versions

PHP 5.6 backport of ocramius/package-versions offering fast, no-IO access to Composer dependency versions from composer.lock. Call Versions::getVersion(), getShortVersion(), or getMajorVersion() to retrieve installed package versions at runtime.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a PHP 5.6-compatible backport of ocramius/package-versions. It ships a Composer plugin that bakes installed package versions into a generated PackageVersions\Versions class at install/update time, so lookups are a static array read — no composer.lock parsing, no filesystem IO at runtime. Treat it as a legacy-era tool: it is only worth reaching for on Laravel 5.x codebases pinned to PHP 5.6/7.0, not on modern Laravel where Composer\InstalledVersions (Composer 2) already covers this.

Install and first verification

composer require samsonasik/package-versions
composer dump-autoload   # regenerates the baked-in version map

The plugin installs itself, hooks Composer's install/update lifecycle, and rewrites the Versions class in vendor/. If Versions::getVersion() throws right after composer require, a dump-autoload usually fixes it.

Where to look first

  1. The generated class in vendor/samsonasik/package-versions/src/ — candidates should inspect the hardcoded map to understand what is (and isn't) included.
  2. composer.json / composer.lock — confirm the plugin is actually installed and which packages are in scope (dev requirements behave differently with --no-dev).
  3. The README's three-method surface: getVersion() returns 1.0.0@<sha1>, getShortVersion() returns 1.0.0, getMajorVersion() returns 1.

First use case

The natural day-one use is a build/version surface — a /health or /about endpoint, a log context entry, or a footer tag that reports the app and a couple of framework packages:

Route::get('/health', function () {
    return response()->json([
        'laravel' => \PackageVersions\Versions::getShortVersion('laravel/framework'),
        'app_env' => app()->environment(),
        'commit'  => strstr(\PackageVersions\Versions::getVersion('laravel/framework'), '@', false),
    ]);
});

An assessment candidate should get from composer require to a working endpoint in minutes — the interesting signal is whether they notice the @hash suffix and choose getShortVersion() for display and getVersion() for cache keys.

Implementation Patterns

Wrap the static class behind a service. Versions is a static utility with no interface, which makes it untestable and unswappable in isolation. The pattern to look for:

// app/Support/PackageVersionResolver.php
namespace App\Support;

class PackageVersionResolver
{
    public function short(string $package, string $fallback = 'unknown'): string
    {
        try {
            return \PackageVersions\Versions::getShortVersion($package);
        } catch (\Exception $e) {
            return $fallback;
        }
    }

    public function major(string $package, $fallback = null)
    {
        try {
            return \PackageVersions\Versions::getMajorVersion($package);
        } catch (\Exception $e) {
            return $fallback;
        }
    }
}

Bind it in a service provider, inject it where needed, and tests can mock the resolver instead of the static class. This also centralises the "package missing" fallback so a --no-dev deploy doesn't blow up an endpoint.

Config-driven package list. Rather than hardcoding package names across Blade views and controllers:

// config/versions.php
return [
    'reported' => [
        'laravel/framework',
        'samsonasik/package-versions',
    ],
];

Then a Blade directive or view composer iterates the list. This is the difference between a one-off hack and something that survives a dependency bump.

Cache-busting and asset versioning. getVersion() returning version@reference is purpose-built for cache keys — the reference changes whenever the lock file changes:

$key = 'pkg:' . \PackageVersions\Versions::getVersion('vendor/library') . ':report';
Cache::remember($key, 3600, fn () => $this->buildReport());

Good candidates distinguish this from getShortVersion(): a tagged release 1.4.2 will not bust a cache when you redeploy a dev-master build, but the full 1.4.2@abc123 will.

Feature/compatibility branching. getMajorVersion() is the intended hook for "this dependency changed its API" logic:

if ($this->versions->major('spatie/laravel-permission') >= 5) {
    return $this->newPermissionPath();
}

This is the anti-pattern to flag as well: branching on installed dependency versions at runtime is a code smell in application code. It is acceptable in a package's own compatibility shim or a migration window, not as a permanent strategy.

Artisan command for on-call. A php artisan app:versions (or enriching the existing about output) that dumps the reported packages plus PHP and Laravel versions is the highest-value daily use: one command an operator can paste into a ticket.

Log context. Push the app's own version plus a couple of key dependencies into a Monolog processor so every log line carries the deployed shape. This is the pattern most likely to appear in day-to-day work.

Gotchas and Tips

It is a Composer plugin, not just a library. On Composer 2 the plugin must be explicitly allowed (allow-plugins in composer.json), or installs fail with a prompt/error. Candidates on a 2016-era stack may not hit this, but anyone testing the package today will.

The data is baked at install time — it does not track reality. Editing vendor/ by hand, or a deploy that copies a prebuilt vendor directory, leaves the map stale. If the reported version looks wrong, composer dump-autoload is the first thing to try. The upside is the point of the package: zero runtime IO, so no lock-file read on every request.

Unknown packages throw. getVersion() raises an exception (an OutOfBoundsException subtype / PackageNotFoundException depending on version) for packages it doesn't know about. The root project itself is generally not in the map either — for the app's own version, read composer.json or a build-stamped constant, not this package. Always wrap with a fallback in anything user-facing.

getVersion() is not a clean version string. 1.0.0@0beec7... is the contract; the part after @ is the source reference, and for dev installs the whole string may look like dev-master@abc123. Anyone echoing it into a UI without getShortVersion() will ship an ugly footer.

No dev packages in production. composer install --no-dev produces a map without require-dev entries, so an endpoint reporting a dev dependency will 500 in production but pass locally. The resolver's fallback parameter exists precisely for this asymmetry.

Class collision with ocramius/package-versions. The backport deliberately occupies the same PackageVersions\Versions namespace and class name. Both cannot be installed in one project — if a transitive dependency pulls the original, you get an autoload conflict or silently the wrong implementation. composer why ocramius/package-versions is the diagnostic.

Static means untestable. Versions::getVersion() cannot be mocked in a PHPUnit test without the resolver wrapper shown above. If a candidate's code calls it directly in a controller and then writes tests that "pass locally," ask how those tests behave on a machine with a different composer.lock.

CI and environment drift. Two CI boxes with different lock references will report different getVersion() values. Never assert on the full hash in tests; assert on getShortVersion() or that the value is non-empty.

Version pinning in assertions. Treat reported versions as observability data, not configuration. If application behaviour depends on them, you have moved dependency resolution from composer.json into runtime code — the classic thing to catch in review.

Migration path. On PHP 7.1+/Composer 2, prefer Composer\InstalledVersions::getPrettyVersion() / getVersionRanges(), or ocramius/package-versions v2 (later composer/package-versions-deprecated). The backport has not been maintained since 2016, so any new Laravel work should plan the exit rather than deepen the integration.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels