# Why We Migrated from Zend Framework 1 to Symfony 8

Published 2025-12-01. Updated 2026-09-17.
Canonical URL https://log.delaa.dev/blog/2025-12-01-why-migrate-zf1-to-symfony8

> Zend Framework 1 has been end-of-life since 2016. PHP 5.6 receives no security patches. But the application still worked, so why take the risk? The decision process behind migrating a production HR platform from ZF1 to Symfony 8.

---

<Image
  src="/images/why-migrate-zf1-to-symfony8/hero.png"
  alt="A balance scale weighing a cracked gray scaffold marked with a warning shield against a solid blue scaffold"
  width={2000}
  height={1125}
  className="rounded-lg"
/>

This is the first article in a series documenting the migration of a
production HR and Payroll application from Zend Framework 1 (PHP 5.6,
MySQL) to Symfony 8 (PHP 8.4, PostgreSQL). This article covers the
context and the decision process: why migrate, why Symfony, and why
not a rewrite.

## The starting point

The application had been in production for years. It handled
payroll for hundreds of employees across multiple countries. Salary
calculations, tax deductions, leave management, recruitment pipelines,
document signing. It was a working piece of software that the business
depended on.

But the technical foundation was crumbling:

- **Zend Framework 1**, last stable release December 2012, officially
  end-of-life since September 2016
- **PHP 5.6**, end-of-life since December 2018, receiving no security
  patches
- **MySQL**, the version in use had gone the same route. No security
  updates for years, with no path back onto a supported release without
  touching the rest of the stack
- No automated deployment, no CI pipeline, no tests
- The sole infrastructure knowledge lived with one person

## The risks of staying

We evaluated what staying on ZF1 meant in concrete terms.

**Security.** ZF1 hasn't shipped a security fix since 2016. PHP 5.6
hasn't shipped one since it reached end-of-life in December 2018. And
the two were locked together. ZF1 leans on dynamic object properties
throughout (`Zend_Db_Table_Row` exposes columns as undeclared
properties, `Zend_Config` does the same for config keys), a pattern PHP
itself started deprecating from 8.2 onward. Upgrading PHP without
upgrading the framework wasn't an option; upgrading the framework meant
leaving ZF1 behind. Staying meant betting nothing new would ever be
found in either, a bet with no upside and an open-ended downside.

**Maintenance.** PHP 5.6 cannot run on modern infrastructure. Docker
images for 5.6 are becoming harder to find, and many PHP extensions no
longer compile. Adding a new feature meant fighting the framework.
ZF1 has no autowiring, no attribute-based routing, no modern ORM.

**Talent.** Finding a developer who knows ZF1 these days is difficult.
The framework was popular in the late 2000s, but most developers
experienced with it have moved on. The bus-factor risk was real.

## Why not a big-bang rewrite

A rewrite was the obvious alternative. Build the new Symfony application
from scratch, deploy it, and turn off the old one. We rejected this for
three reasons.

**No feature freeze.** The business could not stop adding features for
six months. Payroll compliance changes, new country requirements, legal
adjustments. These came in regularly throughout the migration. A
rewrite requires a frozen scope.

**Unknown unknowns.** A legacy codebase contains business rules
that nobody remembers. Payroll tax calculations, rounding rules,
specific client configurations. Rewriting meant rediscovering these one
bug report at a time.

**No parallel runs.** With a rewrite, you deploy the new system and hope
it works. If something is wrong, rolling back means downtime. The
Strangler Fig pattern let us run both systems in parallel and switch
routes gradually.

## Why Symfony 8 over Laravel or a modern framework

We did evaluate alternatives.

**Laravel.** The most popular PHP framework right now. Excellent ecosystem,
huge community. But the application was structured as a traditional MVC
with Doctrine-like patterns (Zend_Db_Table). Symfony's bundle system and
Doctrine integration aligned better with the existing mental model.
Laravel's Eloquent ORM would have required a different database mapping
philosophy.

**API Platform.** The application needed REST APIs for its multi-tenant
SaaS future. Symfony + API Platform v4 provided this natively. Laravel
can do APIs, but API Platform's resource-driven design matched our
domain model closely.

**No framework.** Keeping ZF1 with modern PHP shims was considered but
rejected. The framework environment was the problem, not just the PHP
version. We would still have no autowiring, no attributes, no modern
tooling.

Symfony 8 was chosen because it provided the clearest migration path
from ZF1's architecture. Bundles mirror modules, Doctrine maps to
Zend_Db_Table, and the event dispatcher could bridge the two systems.

---

The decision to migrate was not about rewriting for the sake of
freshness. ZF1 was a genuine production risk. The decision to use
Symfony and the Strangler Fig pattern was about managing that risk
incrementally rather than compounding it with a rewrite.

The next article in this series explains how the Strangler Fig bridge
was built. The catch-all route that let ZF1 and Symfony coexist
in the same process.

---

— Delaa
