# PHP 7.1 to 8.2: The Real Bill for a Deferred Upgrade

> Moving a PHP app I maintain from 7.1 to 8.2 was proposed in 2023 and done in 2024. The most expensive line item on the bill wasn't where I expected.

- Published: 2026-10-18
- Category: Journal
- Tags: PHP, Refactoring
- Reading time: 5 min read
- Source: https://muhammetsafak.com/blog/php-7-1-to-8-2-the-real-bill-of-a-deferred-upgrade/
- Language: en-US
- Author: Muhammet Şafak

---
> **TL;DR:** In 2023 I proposed moving from PHP 7.1 to 8.2; the answer was that it works, so why bother. The move happened in 2024, dozens of breaking changes at once. The listed changes fit the budget; bugs that surfaced one case at a time, over months, did not.

The most expensive line item of the deferred upgrade wasn't the breaking changes. Those could be listed. What couldn't be listed were the bugs that showed up in a single case and stretched over months.

In 2023, on a PHP application I maintain, I proposed moving from PHP 7.1 to the stable 8.2. The answer was short and the move was put off; the upgrade happened in 2024. Looking from 2026, I can write the bill out line by line. The order below is not the order in which the items appeared to me, but the order I understood them in looking back.

## The proposal and the answer

The answer the day I proposed it was: "It works, so why bother?"

The answer wasn't wrong. The application was running, and I had nothing to show that it was broken that day. Still, I hadn't made the proposal for nothing. According to [PHP.net: Unsupported Branches](https://www.php.net/eol.php), support for PHP 7.1 had ended on December 1, 2019; the last release was 7.1.33. The 8.2 I proposed as the target had come out on December 8, 2022, and it was a stable choice for that day.

The most concrete thing I had was this: the move was a job of one or two days. Small jobs are the easiest to put off. "Let's finish the urgent thing first" finds room in every calendar, and this time it did too.

## The lock was set quietly

Meanwhile something happened that raised no alarm: packages began dropping support for old PHP. One package left 7.1 behind in its new release, and we stayed on the old version. Then the next package, then the one after that.

Each of them, on its own, was a detail that could be put off. Past a certain point there were no packages left to update and the application was locked to 7.1. I wrote about this mechanism, the dependency lock and why deferral is "the sum of reasonable decisions", separately on sade.dev, in [The Cost of Deferring an Upgrade](https://sade.dev/en/journal/the-cost-of-deferring-an-upgrade/). I won't repeat it here; I'm only telling the application side of this case.

In those days another item had been added next to the one or two days of work: a few hours per package update. Both looked small. Looking small was exactly what made deferring easy.

## 2024: The list, paid in one go

We made the move in 2024. We could no longer go step by step; we had to jump from 7.1 to 8.2 in one go, without passing through the versions in between.

Dozens of breaking changes and deprecated items came up in front of me. All of them had to be solved at the same time. A job that could have been split into pieces in 2023 had turned into a single job that couldn't be split in 2024.

Still, this line item had one good side: it was visible. The error message showed which line leaned on old syntax, and the deprecation notices said what was being removed. A list was drawn up, items were closed one by one, and it was over. I can say it was a long list, but it contained nothing unknown. You can roughly estimate its size and place it in the calendar.

I didn't measure the total time, so I can't give you a number of days or weeks. The only comparison I have is the one or two days in 2023 against "dozens of changes in one go" in 2024.

## The item that wasn't on the list

The real bill came after the move.

Some of the bugs showed up only in a single case: a path that isn't triggered often, a particular piece of data, a particular order. For a bug like that you first have to notice it, then reproduce it, then find the cause. Each one is a separate investigation. One would close, and another would appear in another case. Fixing them stretched over months.

I couldn't write this into the budget. The breaking changes could be estimated; the bugs couldn't. If you build the budget around the first, the second lives outside the budget and inside the calendar.

There was one more thing, and I noticed it late: carrying dozens of changes together made every bug's source one of dozens of candidates. Telling which change a bug came from became a job of its own. This is not a measurement, it is my observation.

The counter-intuitive part is this: when we talk about deferring, we always calculate the breaking change list. The cost wasn't there; it turned up in the long tail.

> **Tan:** What stays with me in this case is how writing nothing into the budget for the unknown passes for a neutral choice. Leaving that allowance at zero is an estimate too, and the most optimistic one on the table.

## Looking back

If I did this job again today, I would do three things differently.

First, I would write the 2023 proposal not as "necessary" but as "one or two days now, dozens of changes in one go later." Answering "it works" with "we gain nothing" isn't enough; you have to show the direction of the comparison.

Second, I would note down somewhere the day each package update couldn't be installed. That day was the earliest sign that the lock had been set.

Third, I would set aside a separate allowance in the bug queue for the first months after the move. How much? I don't know; I didn't measure it and I don't want to guess. But I now know it isn't zero.

This case has an ironic ending too. According to [PHP.net: Supported Versions](https://www.php.net/supported-versions.php), security support for 8.2, the target I proposed, ends on December 31, 2026. So even the case's target has entered its own calendar. What I take from this case is simple: write down the date of the next round in advance.

Not upgrading can also be a legitimate decision; I cover when that is so in the series on sade.dev. My objection isn't to deferring, it's to deferral not being written down as a decision.

The one thing you can do today: look at the end-of-support dates of the runtime and framework versions in your own system, and write them down somewhere. Two lines are enough: what is running, and when its support ends.

## Sources

- [PHP.net: Supported Versions](https://www.php.net/supported-versions.php)
- [PHP.net: Unsupported Branches](https://www.php.net/eol.php)
