I still remember the week we moved an agency client to PHP 7.2 and every each() call in a crusty CMS module started leaving notices. Somewhere in that wall of repetition sat a genuinely broken payment webhook, and it took us two days to spot it because the error channel had turned into wallpaper. That week taught me the position I want to defend today: a deprecation notice that shows up in production logs is not a PHP problem, it is a routing problem. The message was addressed to a developer, and your process delivered it to whoever happened to be on call.
The occasion for dragging out that old story: internals has wrapped up the vote on the big cleanup round for PHP 8.6, roughly 35 individual deprecation RFCs, and the large majority got approved. To be clear about what that means in practice: nothing stops executing in 8.6 itself. The flagged calls still return their values, they just leave a note behind, and actual removal is a job for a future major. This is the language behaving exactly the way we always say we want platforms to behave, with years of advance notice instead of a surprise.
So why does a well-mannered warning still hurt teams? Because of where we choose to read it. An E_DEPRECATED is a message from the PHP maintainers to the one person who can open the file and change the line. When you let it flow through Monolog into your log aggregation, you deliver that message in bulk, at three in the morning, to an operator who cannot act on it. You pay twice: once in storage and ingestion for information that is completely deterministic and reproducible on any laptop, and once in attention, because the single warning that actually matters that night is buried under ten thousand identical ones.
My conclusion is blunt: deprecations from code I own should never survive long enough to reach a server. I run the test suite on the new PHP version and configure it so that any deprecation triggered from my own namespaces fails the run. From there it is ordinary red-to-green work, and a lot of it is mechanical. Rector will rewrite most of these patterns for you automatically, with the obvious limit that it only operates on code you own, not on anything under vendor/.
Now the honest concession, because the hard-line version of my own policy has a real weakness. If your pipeline goes red on any deprecation from anywhere, then the day a package you depend on lags behind 8.6, your builds fail for as long as that maintainer needs, which might be months and is entirely out of your hands. Teams under delivery pressure will not tolerate a permanently red pipeline. Someone will switch the gate off, and then you have less protection than before you started. Critics of strict deprecation gates are right about exactly this failure mode, and pretending otherwise would be dishonest.
Which is why I land on a baseline instead of a ban, the same trick PHPStan made respectable. When you first run against 8.6, snapshot every deprecation that originates in vendor code and accept that list as known debt. The gate then fails only on growth: a new deprecation, or one that starts firing from a new place. Every composer update is a chance to shrink the file, and shrinking it feels good in a way that staring at log dashboards never does. Meanwhile, production stops logging E_DEPRECATED at all. You lose nothing by silencing it there, because unlike a timeout or a race, a deprecation carries zero runtime context worth observing.
None of this says you must move this quarter. PHP 8.5 will be maintained for years, and a deprecation has no deadline until the removal actually ships. But I would still spin up a throwaway branch against 8.6 soon, simply because the inventory costs an afternoon now and an incident review later. The one question I have not fully settled for myself is the stubborn tail: a vendor deprecation where upstream is unresponsive and no alternative release exists. Do you baseline it indefinitely, carry a composer patch, or take that as your cue to swap the package out? I would honestly like to hear where your team draws that line.
Comments
No comments yet — be the first.
Open the discussion
No account or password needed — just enter your e-mail and we’ll send you a one-time sign-in link. First time here? You’re set up automatically.
Your rating will be applied automatically after you sign in.
Check your inbox
We’ve sent a sign-in link to …. Open it on this device — this tab will sign you in automatically.
Nothing arrived? Check your spam folder — and mark the mail as "Not spam" so it lands in your inbox next time.