laminas-zendframework-bridge: an autoloader that renames your legacy ZF classes
Alias legacy ZF class names to Laminas Project equivalents.
At a glance
- What is it?
- The laminas-zendframework-bridge is a small PHP package that aliases legacy Zend Framework, Apigility and Expressive class names to their Laminas equivalents through a custom autoloader and a configuration post processor, so an existing application can be moved onto the renamed packages without rewriting its source. It is BSD-3-Clause licensed, feature-complete, and in security-only maintenance mode.
- Who is it for?
- Adopt the bridge if you are running a Zend Framework MVC, Apigility or Expressive application and you want to move to the renamed Laminas packages without touching every `use` statement, since it aliases the legacy class names at autoload time and rewrites the configuration for you. Do not adopt it for a new project, and do not treat it as a long term dependency, because the project is feature-complete and receives security fixes only.
- Can I use it commercially?
- Yes. BSD-3-Clause 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 3 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
A migration shim rather than a framework
The laminas-zendframework-bridge is a PHP library that provides a custom autoloader that aliases legacy Zend Framework, Apigility, and Expressive classes to their replacements under the Laminas Project.
That is the whole idea, and it is narrower than it first sounds. When Zend Framework was renamed to Laminas, every class in the framework changed its namespace, and an application with a hundred `use Zend\...` statements and a service manager configured with those class names had a migration problem that was tedious rather than difficult. The bridge makes the class names in your old code keep working by aliasing them at autoload time, so the old namespace resolves to the new class.
The intended user is an existing application in the middle of that migration. The project supports Zend Framework MVC projects, all v2 and v3 releases, Apigility projects, all stable versions, and Expressive versions, all stable versions. Those three are the ecosystems that were renamed into the Laminas Project, and the repository topics also name laminas-api-tools and Mezzio.
What this package is not is a compatibility layer for the long term. The README says plainly that this package should be installed only if you are also using the composer plugin that installs Laminas packages to replace ZF, Apigility and Expressive packages. That is a significant constraint and it is stated as a requirement rather than a recommendation, which tells you the bridge is designed for a single migration event, not for a permanent state.
The maintenance status makes the intent clearer still. The package is considered feature-complete and is in security-only maintenance mode, following a decision by the Technical Steering Committee, and the README links the minutes of the meeting where the future of the migration layer was decided.
The composer plugin pairing is not optional
The dependency on the composer plugin is the detail most likely to cause confusion, so it is worth being precise about what happens without it.
The composer plugin's job is to install the Laminas packages in place of the ZF, Apigility and Expressive ones. That is, the packages in your `vendor/` directory become the renamed versions, and the class files inside them carry the new namespaces. The bridge's job is the other half of the job: to make code that still refers to the old names resolve to those new classes.
Without the plugin, the vendor tree still contains the old packages under their old names, and there is nothing for the alias autoloader to point at. The README's instruction that this package should be installed only if you are also using the composer plugin is therefore a statement about how the two pieces interlock, not a preference about installation order.
The mechanism has two halves, and the second one is easy to overlook. The first half is the autoloader, which handles the class names in your source code. The second is a configuration post processor, which rewrites the class names that appear in your application configuration, and that is where the factory class names, the service names and the controller plugin names live.
That second half is the interesting one, because configuration in a Zend Framework application is an array of strings and class name references, and those references are not resolved by the autoloader at all. A factory named in configuration is instantiated by the service manager using the class name as a string, so a plain namespace alias would not help. The post processor is what makes the configuration work, and the rest of the README is largely about how to control it.
Configuration post processing and the replacements escape hatch
Since 1.6.0 you may provide additional replacements for the configuration post processor, and the README explains when that is useful: if your application uses third-party components that include class names the post processor otherwise rewrites, and which you want to never rewrite.
The configuration structure is a single key in your application config:
return [
'laminas-zendframework-bridge' => [
'replacements' => [
'to-replace' => 'replacement',
// ...
],
],
];The example that follows makes the failure mode concrete. If your configuration contains a dependency mapping like this:
return [
'controller_plugins' => [
'factories' => [
'customZendFormBinder' => \CustomZendFormBinder\Controller\Plugin\Factory\BinderPluginFactory::class,
],
],
];then the two strings containing the verbiage `ZendForm` would be rewritten by the post processor, because the rewrite is textual and does not know that this particular name is not a Laminas class that has a replacement. The fix is to tell the post processor to leave them alone:
return [
'laminas-zendframework-bridge' => [
'replacements' => [
// Never rewrite!
'customZendFormBinder' => 'customZendFormBinder',
'CustomZendFormBinder' => 'CustomZendFormBinder',
],
],
];A mapping whose key and value are identical is a no-op replacement, and that is the idiom the README teaches.
Two observations follow. The rewrite is a string operation over your configuration, which means it will catch anything that looks like a legacy class name, including your own application class names and not just the ones from the framework. And the escape hatch is per string, so a third party component that uses a `Zend` verbage in several places needs an entry for each of them.
This is also the part of the migration that is hard to test in advance, because a mis-rewritten factory name in configuration produces a class that cannot be found at runtime rather than a compile time error.
Installing it and the version history
Installation is one Composer command:
$ composer require laminas/laminas-zendframework-bridgeThere is no configuration step required to get the aliasing working, because the bridge is designed to be transparent once the plugin is in place. The `replacements` configuration is optional and only needed when the post processor catches something it should not.
The release history is what tells you how to pin it. The recent tags are 1.8.0 from 2023-11-24, 1.7.0 from 2022-12-12 and 1.6.1 from 2022-07-29, and the default branch is `1.9.x`, which is where further work would land. The last push to that branch was on 2026-10-12, and the repository is not archived.
The dates matter when you are planning the upgrade. The 1.6.0 release is the one that introduced the `replacements` option, so any version before it has no escape hatch for the third party class name problem, and 1.7.0 and 1.8.0 are the releases to look at if you need that. The project version follows the usual Laminas convention of a major, minor and patch number, and the branch naming, `1.9.x`, tells you the current line.
The licence is BSD-3-Clause, which is the standard permissive BSD variant with the no-endorsement clause. The repository carries a `LICENSE.md` and a `COPYRIGHT.md`, and the tree also shows the tooling you would expect from a maintained package: `phpcs.xml` for coding standards, `psalm.xml.dist` with a `psalm-baseline.xml` for static analysis, `phpunit.xml.dist` for the test suite, a `renovate.json` for dependency updates, and a `composer.json` with a committed `composer.lock`.
The support channels are the issue tracker and a Discourse forum, and for a security issue the README points to the Laminas security reporting guidelines rather than to a public issue.
Security-only mode and what it means for your application
The status of the package is the most important line in the README, and it deserves to be read as an instruction rather than as a status update.
The package is feature-complete and in security-only maintenance mode, following a Technical Steering Committee decision. In practice that means no new features, and fixes only for security issues. The README also invites maintainers, which is the standard signal that a package in this state is looking for someone to take it over, and that until someone does, the response to a bug report will be limited.
For a bridge in an application's authentication or request handling path, that status has a specific implication. A security fix in this package changes the class name resolution for your entire application, and applying it means re-running your test suite with new class mappings. A package that only ships security fixes is a package you will apply without much ceremony, and a security fix in a class aliasing layer is exactly the kind of change you want to be able to test.
There is a second, larger consequence, and it is the one to plan around. A bridge is a transitional dependency, and a transitional dependency that has reached the end of its feature life is a signal. The migration it exists to support was supposed to finish. If your application still depends on the bridge in 2026, the question is not why the bridge is old but why the migration did not complete, because a partly migrated codebase keeps two sets of class names alive and keeps the configuration rewriting in the request path, which is a cost that grows with the number of dependencies you add.
The repository's own structure supports the reading that this is close to done. The `src/` and `config/` directories are small, the package has no runtime dependencies of its own beyond the framework packages it aliases, and the fact that the README points at a specific TSC decision about the future of the migration layer suggests the organisation has already decided what the endgame is.
Where the bridge is the wrong answer
There are three situations where reaching for this package is a mistake, and one where it is exactly right.
The bridge is wrong for a new application. If you are starting a Laminas or Mezzio project today, there is nothing legacy to alias, and the dependency would be pure overhead.
It is wrong for an application that is already fully migrated but still has the package installed, which is a common state after a migration that nobody cleaned up. The fix there is to remove the package and the composer plugin and check that the autoloader and the configuration post processor are no longer in the request path.
It is also wrong if your application is not in the supported matrix. The README lists Zend Framework MVC v2 and v3, all stable Apigility and all stable Expressive, and anything outside that list is not covered by the aliases the bridge provides.
And it is wrong for the class of application where the configuration post processor cannot be trusted, which is a large codebase with a long history of third party components whose names contain legacy verbs. The `replacements` escape hatch exists, but it is per string, so a codebase with hundreds of such names is maintaining a growing list of exceptions, and that is a signal to fix the third party packages rather than to enumerate them.
Where the bridge is exactly right is the case it was written for: a working application that references the old namespaces in hundreds of places, a service manager configured with old class names, and a team that wants the new packages on the next deploy without a rewrite. The difference in approach between the bridge and a proper migration is the difference between renaming classes and renaming references, and for a single release cycle of a large codebase that is often the trade that makes sense.
The alternative for most teams is a codemod. A script that rewrites the `use` statements and the configuration strings, run once, followed by a normal dependency upgrade, produces a codebase with one set of class names and no transitional layer at all. The difference in approach is that the bridge keeps both worlds alive at runtime, while a codemod collapses them once and leaves nothing behind to maintain.
Editorial conclusion
Adopt the bridge if you are running a Zend Framework MVC, Apigility or Expressive application and you want to move to the renamed Laminas packages without touching every `use` statement, since it aliases the legacy class names at autoload time and rewrites the configuration for you. Do not adopt it for a new project, and do not treat it as a long term dependency, because the project is feature-complete and receives security fixes only. Verify three things first: that the composer plugin that replaces the ZF packages is installed alongside it, since the bridge is documented to work only in that combination, that the third party components in your dependency tree do not use class names the post processor will rewrite, which is what the `replacements` configuration exists for, and that your own service manager factories and controller plugin names survive the configuration rewrite.
Frequently asked questions
What does the laminas-zendframework-bridge package do?
It provides a custom autoloader that aliases legacy Zend Framework, Apigility and Expressive classes to their replacements under the Laminas Project, and it rewrites the class names in your application configuration through a configuration post processor. It supports Zend Framework MVC v2 and v3, all stable Apigility versions and all stable Expressive versions.
How do I install the laminas-zendframework-bridge?
With `composer require laminas/laminas-zendframework-bridge`. The README states that this package should be installed only if you are also using the composer plugin that installs Laminas packages to replace the ZF, Apigility and Expressive packages.
How do I stop the bridge from rewriting a class name I want to keep?
Since version 1.6.0 you can add a `replacements` mapping under the `laminas-zendframework-bridge` configuration key, where a key and value that are identical tells the post processor never to rewrite that string. The README's example uses `customZendFormBinder` and `CustomZendFormBinder` for a third party component whose names contain legacy verbiage.
Is the laminas-zendframework-bridge still maintained?
The package is considered feature-complete and is in security-only maintenance mode, following a Technical Steering Committee decision, so it receives security fixes only. The recent releases are 1.8.0 from 2023-11-24, 1.7.0 from 2022-12-12 and 1.6.1 from 2022-07-29, and the last push to the 1.9.x branch was on 2026-10-12.
What licence is the laminas-zendframework-bridge released under?
BSD-3-Clause, with the licence text in the LICENSE.md file at the repository root and the copyright notices in COPYRIGHT.md. The repository also carries coding standards, static analysis and test configuration alongside a Renovate configuration for dependency updates.
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/laminas-laminas-zendframework-bridge)Was this useful?