1. Deprecations are helpful
It’s a common complaint: “why do my PHP scripts break with minor version updates??”. And quite right: PHP has a tendency to add deprecation notices in minor releases, which tend to be audibly present when upgrading a project.
Return type should either be compatible with
IteratorAggregate::getIterator(): Traversable,
or the #[ReturnTypeWillChange] attribute should be used
to temporarily suppress the notice
It’s important to understand what deprecations are about: they aren’t errors, they are notices. They are a way of notifying PHP developers about a breaking change in the future. They want to warn you upfront, to give you plenty of time to deal with that upcoming breaking change.
Of course, one could ask: are these breaking changes and fancy features essential? Do we really need to change internal return types like IteratorAggregate::getIterator(): Traversable
, do we really need to disallow dynamic properties?
In my opinion — and it’s shared by the majority of PHP internal developers — yes. We need to keep improving PHP, it needs to grow up further. And that sometimes means introducing a breaking change, like for example when internals adds return types to built-in class methods: if you’re extending IteratorAggregate
in userland code, you will need to make some changes. The language needs to evolve.
Overall I’d say that, despite some of the annoyances that come with such an evolving language, it’s for the better.
And luckily we have a mechanic like deprecation notices: they tell us that something will break in the future, but that we can still use it today. We can incrementally make changes and updates around our codebase.
2. Deprecations can be silenced
Second, PHP internals goes to great lengths to help userland developers in dealing with deprecations. Thanks to the addition of attributes in PHP 8.0, we now have a much better and standardized way of communication between our code and PHP’s interpreter.
For example you can tag userland code with the ReturnTypeWillChange
the attribute in order to prevent deprecation notices being shown.
final class MyIterator implements \IteratorAggregate
{
#[\ReturnTypeWillChange]
public function getIterator()
{
// …
}
}
Of course, this code will break in PHP 9.0, so while silencing deprecation notices is a short-term solution; you will need to fix them if you ever want to upgrade to the next major version:
final class MyIterator implements \IteratorAggregate
{
public function getIterator(): \Traversable
{
}
}
One more example maybe? With dynamic properties being deprecated in PHP 8.2, you can mark classes with the AllowDynamicProperties
attribute, making it so that they allow dynamic properties again and suppress the deprecation notice:
#[\AllowDynamicProperties]
class Post
{
}
// …
$post->title = 'Name';
3. They are notices, not fatal errors
PHP code will keep working just fine, even when parts of it trigger deprecation notices. Of course, you know by now that it’s in your best interest to fix them if you ever want to upgrade to the next major version, but you don’t need to do it right now. It’s perfectly ok to upgrade your production projects and deal with deprecation notices over time.
I’d even recommend disabling deprecation notices on production altogether, or at least not showing them to your end users:
error_reporting(E_ALL ^ E_DEPRECATED);
Maybe you can keep track of them using an external error tracker for the first months, to get a clear image of the places you’ll need to fix those deprecations. But above all: deprecation notices shouldn’t be blockers when upgrading to the latest minor PHP version.
4. Automation
Lastly, keep in mind that you don’t need to do boring tasks by hand. Usually, it’s a matter of running a script that takes a couple of minutes at most to scan and fix your codebase. That’s work you might need days for if you do it by hand.
It’s not difficult or time-consuming anymore to deal with PHP upgrades. In fact, deprecations help tremendously to create a smoother upgrade path and prepare your codebase for the future.