Why I Don’t Enjoy Writing PHP Anymore

Michael Bodnarchuk @davert
4 min readOct 4, 2022

--

This post was started from my Twitter thread, please follow me to join the discussion.

I enjoyed writing PHP in the past. It was my first web-development language and the first programming language I was paid for. It had its evolution path and even though we can’t say that PHP is stuck in the past, its current development strategy is problematic, and here is why.

I am the creator and one of the maintainers of Codeception Testing Framework and Robo Task Runner. And I know some shit about maintaining PHP libraries.

PHP development nowadays is bumping versions, updating types, and tests, and getting out of cross-dependencies conflicts.

Let’s imagine this situation:

I have my own library MyLib that is expected to support PHP 7.4 and PHP 8+ at the same time.

Meanwhile the coollib package I depend on releases its v2 where it changes the interface of the same function to an incompatible one:

dependencies of MyLib and clients of MyLib

🤓 Client #2 already migrated PHP 8.1 and wants to install coollib 2.0 while

🤠 Client #1 is using PHP 7.4 and can’t move to coollib 2.0

As MyLib author I can either drop 🤠 Client #1 and make a major release not because I introduced some breaking changes but because I bumped dependency of coollib.

Now imagine what happens if coollib has also dependencies… And so on…

But still, I don’t understand why

doStuff(mixed $val)

and

doStuff($val)

are conflicting with each other as they are basically the same function! However, PHP engine treats them differently.

So here are two fundamental problems we have in modern PHP:

🎃 Problem #1: All PHP classes and functions are loaded globally.

🎃 Problem #2: New PHP types are not backward compatible.

If either of these won’t be a problem, we would not get into dependency hell.

Problem #1 was solved in In #NodeJS.

If you require a module it will stay only in the current context and won’t affect the whole application.

So in NodeJS context, different versions of the same library with different signatures of methods can live together.

Problem #2 could be solved on PHP engine level

However, it was not predicted from the start. Using types in the ecosystem and getting into dependency conflict was not an expected outcome of introducing more and more incompatible types into the engine.

Libraries tend to add more and more type changes with breaking compatibility in interfaces every year. Could a community solve this? Yes! Banning types could be an option and staying with PHP 7.0 features only. But that doesn’t sound cool when you know that PHP 7 is not supported anymore and you don’t actually enjoy writing legacy code. Anyway, we can’t force maintainers to keep on old interfaces, right?

So let’s sum up:

While PHP still keeps ugly array_* str* functions from 90s, it breaks compatibility in the ecosystem with every new release.

So it’s neither a modern language nor a stable one.

(sorry, #PHP, you know I love you but I must have said this)

While you can think that everyone can do upgrades every year, it can be automated via Rector and so on… But you can’t run Rector on all your dependencies and bump new versions without the maintainer’s permission.

So you get stuck with the lowest PHP version of any of your dependencies.

That’s how some big projects are still on PHP 7.2..7.4 and can’t get to PHP 8.1.

Upgrading has its cost.

While making a mid-sized framework-based project can be fine to upgrade, large enterprise codebases with custom core and a dozen of dependencies are painfully hard to upgrade

So let’s get back to me, a library author who has a library that just works.

🤓 Client #2 (mid-size) upgraded their app and wants me to upgrade my code as well.

🤠 Client #1 (enterprise size) could not get an upgrade yet and wants to use MyLib.

Should I drop the enterprise client? I don’t want to. Actually, that enterprise client may be supporting MyLib with donations or paying me for consultancy.

As an author of a general-purpose library, I will need to maintain a library with versions for all currently used PHPs. You see, that sucks!

But let’s say, I decided to drop support for all old PHPs.

I say: my lib is PHP 8.1+ compatible!

Client says: ok, we are not going to use your lib, as we won’t upgrade just to use it

I can probably say: how about upgrading to PHP 8.1, as old ones are not maintained and don’t even get security patches!

But the client will reply: we have a team of 100 PHP developers, they are not so stupid as you might think, they also want to upgrade. But we can’t pay them for a month just to make your shitty MyLib be installed on our application.

And that’s the dead end. Upgrading in PHP is very expensive. And it happens for no good reasons. It happens because the PHP engine does not keep the compatibility of interfaces between releases, because PHP libraries upgrade to the most modern features, and because we share the global namespace of loaded classes. As a library maintainer, I need to balance upgrades, create bridges between different libraries and always test for compatibility with other dependencies.

But I’m tired. And I think the majority of maintainers in PHP ecosystem are tired of needless upgrades as well:

--

--

Michael Bodnarchuk @davert

Web developer from Kyiv, Ukraine. Lead developer of Codeception testing framework. Tech consultant and trainer at http://sdclabs.com