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

Class Alias Loader Laravel Package

typo3/class-alias-loader

Composer plugin that adds backwards-compatible class aliases for renamed PHP classes. Packages declare alias map files in composer.json; the loader rewrites vendor/autoload.php and transparently calls class_alias() when old names are requested. No-op when no maps exist.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal setup in a Laravel app:

  1. Install the Composer plugin at the root of the application (or require it from a compatibility package you publish):
composer require typo3/class-alias-loader
  1. Allow the Composer plugin. Composer 2.2+ blocks plugins until explicitly allowed:
{
    "config": {
        "allow-plugins": {
            "typo3/class-alias-loader": true
        }
    }
}
  1. Create an alias map file. Use ::class for the new target and plain strings for the old name:
<?php
// app/Compatibility/ClassAliasMap.php
return [
    'App\\Legacy\\Services\\Mailer' => \App\Mail\Mailer::class,
    'App\\Legacy\\Models\\Customer' => \App\Models\Customer::class,
    'OldVendor\\Package\\Client' => \NewVendor\\Package\\Client::class,
];
  1. Register the map in the root composer.json:
{
    "extra": {
        "typo3/class-alias-loader": {
            "class-alias-maps": [
                "app/Compatibility/ClassAliasMap.php"
            ],
            "always-add-alias-loader": true
        }
    }
}
  1. Regenerate Composer autoload files:
composer dump-autoload
  1. Verify the alias works:
php artisan tinker
>>> class_exists('App\\Legacy\\Services\\Mailer');
=> true
>>> get_class(new App\Legacy\Services\Mailer());
=> "App\Mail\Mailer"

Where to look first

  • The README section on extra.typo3/class-alias-loader.class-alias-maps.
  • TYPO3\ClassAliasLoader\ClassAliasMap::getClassNameForAlias() for resolving string class names.
  • vendor/autoload.php after composer dump-autoload to confirm the loader was injected.
  • The map file itself: it is plain PHP returning old => new.

First use case

Renaming application classes or namespaces while old references still exist:

// Before: App\Services\LegacyMailer
// After:  App\Mail\Mailer

return [
    'App\\Services\\LegacyMailer' => \App\Mail\Mailer::class,
];

Existing type hints, container bindings, and serialized payloads that reference the old class can continue to autoload while the new class is used internally.

Implementation Patterns

Use a compatibility package for library authors

If you maintain a Laravel package or shared PHP library, ship the alias map in the package itself:

{
    "require": {
        "typo3/class-alias-loader": "^2.0"
    },
    "extra": {
        "typo3/class-alias-loader": {
            "class-alias-maps": [
                "Migrations/ClassAliasMap.php"
            ]
        }
    }
}

Consumers then get backwards-compatible class names without application code changes. The plugin only activates when a map is found, so consumers that install a newer version without the map pay no runtime cost.

Keep one map per migration boundary

Prefer separate map files by concern:

"class-alias-maps": [
    "app/Compatibility/LaravelUpgradeMap.php",
    "app/Compatibility/DomainRenameMap.php",
    "app/Compatibility/VendorMap.php"
]

This makes it easy to remove a compatibility layer after the deprecation window without touching unrelated aliases.

Resolve string class names explicitly

Aliases fix autoloading and type resolution, but they do not rewrite arbitrary strings in configuration, database columns, queue payloads, or morph maps. Use the public API where your code manipulates class names as strings:

use TYPO3\ClassAliasLoader\ClassAliasMap;

$class = ClassAliasMap::getClassNameForAlias(
    config('legacy.mailer_class')
);

$mailer = app($class);

This returns the new class name when an alias exists and the original string otherwise.

Use it alongside Laravel’s facade aliasing, not as a replacement

Laravel’s config/app.php aliases and AliasLoader handle facade-style aliases during framework bootstrap. This package handles Composer-level class aliases. Use this package for renamed application/library classes and interfaces. Use Laravel’s aliasing for facade shortcuts. Avoid registering the same alias in both systems; duplicate class_alias() attempts can create confusing behavior or warnings.

Keep container bindings stable

If an old interface or implementation class was renamed, alias the class and keep bindings using the old name only during the transition:

$this->app->bind(
    \App\Legacy\Contracts\PaymentGateway::class,
    \App\Payments\StripeGateway::class
);

The alias allows the old contract name to resolve while the implementation moves forward. Prefer migrating bindings to the new name as soon as possible.

Handle polymorphic relations and queued jobs deliberately

For Eloquent morph maps, do not rely on class aliases alone. Use stable morph aliases or resolve class names through ClassAliasMap::getClassNameForAlias():

Relation::morphMap([
    'customer' => \App\Models\Customer::class,
]);

Queued jobs and serialized models can benefit from aliases because PHP autoloads class names during unserialization, but test this explicitly for your job payloads. If a job references an old class name, make sure the alias is active before the queue worker unserializes it.

Add a CI smoke test

A simple test prevents silent breakage after map edits:

public function test_legacy_class_aliases_resolve(): void
{
    $this->assertTrue(class_exists('App\\Legacy\\Services\\Mailer'));
    $this->assertSame(
        \App\Mail\Mailer::class,
        \TYPO3\ClassAliasLoader\ClassAliasMap::getClassNameForAlias(
            'App\\Legacy\\Services\\Mailer'
        )
    );
}

Run this in CI after composer dump-autoload so broken aliases fail the build rather than production.

Deployment workflow

In Docker or CI where vendor/ is built once:

composer install --no-dev --optimize-autoloader
php artisan optimize:clear

The plugin must run during the Composer step. The generated vendor/autoload.php already contains the alias loader; runtime does not need to modify files. Avoid composer install --no-plugins for production builds if aliases are required.

Deprecation lifecycle

A practical pattern is:

  1. Rename the class.
  2. Add the old name to the alias map.
  3. Keep the alias for one major release cycle.
  4. Add instrumentation or logs around getClassNameForAlias() usage where string resolution is under your control.
  5. Remove the map entry and old references after the deprecation window.

Gotchas and Tips

The Composer plugin must be allowed

If aliases are not being generated, first check:

composer config allow-plugins.typo3/class-alias-loader

Without allow-plugins, Composer may install the package but not execute it.

You must run composer dump-autoload after changing maps

The loader is injected when Composer dumps autoload information. Editing a map file is not enough. In CI, a stale Composer cache can produce a vendor/autoload.php without the loader.

always-add-alias-loader belongs in the root composer.json

Use it when your application adds alias maps at runtime or wants the loader initialized even when no static map is present:

"extra": {
    "typo3/class-alias-loader": {
        "always-add-alias-loader": true
    }
}

Do not expect package-level configuration to control the root application’s loader behavior.

Only classes can be aliased

This package uses class_alias(). It does not replace removed helper functions such as str_limit() or e(). If you removed global helpers, provide your own function polyfills or update call sites. Do not put function names in the alias map.

Case-insensitive class loading is gone in v2

v2.0.0 removed case-insensitive class loading. If you have legacy code relying on differently cased class names, either normalize the names or stay on the older 1.x line for legacy support. For modern Laravel applications, always use case-sensitive PSR-4 names.

Be careful with v2.0.0

The v2.0.1 release notes describe a critical bugfix related to refactoring. If your lock file resolves to 2.0.0, upgrade or pin to at least 2.0.1.

Aliases do not rewrite database or config strings

A row containing App\Legacy\Services\Mailer will not automatically become App\Mail\Mailer. The same applies to cached configuration, API payloads, and third-party records. Resolve those through ClassAliasMap::getClassNameForAlias() or a migration.

Watch for duplicate or conflicting aliases

If two maps define the same old class name with different targets, behavior becomes order-dependent and hard to debug. Keep old class names unique across all installed packages and application maps.

The target class must exist

If a map points to a class that is not autoloadable, the failure appears when the old name is first used, not necessarily during composer dump-autoload. Add a smoke test that calls class_exists() on each old name.

IDE and static analysis will not see aliases

PhpStorm, PHPStan, Psalm, and similar tools usually analyze the real class names. Expect missing-class warnings when legacy code references old names. Options include:

  • Add @deprecated stubs for old classes.
  • Exclude legacy paths from strict static analysis.
  • Add a PHPStan baseline or stub file that declares the aliases.
  • Prefer resolving strings through the API so analysis sees the new class.

Do not edit vendor/autoload.php manually

The plugin owns that file’s generated changes. Manual edits are overwritten by the next Composer run.

Immutable vendor directories are supported, but only at build time

The plugin runs during composer install or composer dump-autoload. In a read-only production container, run Composer during image build. Do not attempt to regenerate autoload files at runtime.

--no-plugins and some CI settings disable the loader

If your deployment uses composer install --no-plugins, aliases will not be registered. Similarly, scripts or custom Composer wrappers that skip plugin execution need to be adjusted.

Use the API for debugging

When an old class name behaves unexpectedly, inspect the resolved target:

dump(\TYPO3\ClassAliasLoader\ClassAliasMap::getClassNameForAlias($oldName));

Also confirm the alias map file is actually included in the generated autoload data by checking vendor/autoload.php after a dump.

Keep compatibility maps temporary

Class aliases are a bridge, not a permanent architecture. Treat every entry in the map as technical debt with an owner and a removal date. Remove aliases after downstream packages and internal code have migrated; otherwise the compatibility layer becomes an untested permanent dependency.

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.
htinlynn/genius-helper
maco-studios/hephaestus
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