We’re nearing the end of the year and when I look back at 2020, aside from all the turmoil in the world, more than anything I feel very, very tired.
It largely feels like I have been running from one open-source crisis to another since May/June. Crisises which were outside my control, but had to be tended to anyway.
No matter that a Composer plugin I’m a co-maintainer of was prepared for Composer 2.0 well in advance. When Composer 2.0 was released into the world this October and prevailing CI systems updated quickly, there were still lots and lots of projects which hadn’t updated to the new version we released in June, resulting in support requests and emergency update rounds for various projects.
Along the same lines, while the latest PHPUnit was prepared for Xdebug 3, a lot of real-world projects are not using the latest version of PHPUnit. Again, when the prevailing CI systems were updated to use Xdebug 3 quickly after the release, emergency fixes were needed to prevent projects from being completely blocked by CI code coverage runs failing.
And when Travis finally broke down, and even though they are still not owning up to it, stopped supporting open source, again, there was a scramble to move all CI builds for all open source projects to other CI platforms, which again took huge amounts of time, under pressure, as progress in projects was blocked while the CI wasn’t running.
And let’s not talk about PHP 8.0…
Or actually, maybe we should.
From an open-source maintainer point of view, PHP 8.0 is, not to put too fine a point to it, a nightmare. Don’t get me wrong; I love all the new features and I compliment and thank everyone who has contributed. I can’t wait to start using the nullsafe object operator or union types once projects I work on drop support for PHP < 8, but that will be another few years at the very least.
In the meantime, I had to prepare projects, or help prepare projects for the fall-out. And fall-out there is.
Combine the engine exception changes with union types, which now allowed for adding lots of new type declarations to PHP internal functions, and you get a release that throws fatal errors on code that worked perfectly fine without even a notice or a warning in previous PHP versions.
Top that up with changes in return types for some pretty commonly used functions and you get code that may end up doing the complete opposite of the originally intended behaviour, again without any warning or notice in previous PHP versions.
And while static analysis tools can guestimate where there may be problems in your code, as these changes are all related to the run-time value and type of variables, the only sure-fire way to detect these fatal errors and behavioural changes is to run the tests on PHP 8…
This brings its own problems as lots of open source projects which – for their own reasons – support a wider range of PHP versions than just the latest and greatest, were still using PHPUnit 5/6/7 to run their tests on PHP 7.4 due to the addition of the void
return type to fixture methods in PHPUnit 8.
So, instead of being able to focus on fixing their PHP 8 problems, these projects now first have to find a way to get their tests running on PHPUnit 4 to 9.3+ and have to pay the technical debt they had built up from not doing so earlier.
A small project like PHPUnit Polyfills, going from first public mention to over 50.000 downloads in just eight short weeks, testifies to the amount of projects which are scrambling to make their test suites PHPUnit cross-version compatible.
And that’s for the projects which have tests.
The unfortunate reality is that a significantly large number of projects do not have unit tests or when they do have tests, those only cover a small portion of their codebase.
So, again, instead of being able to focus on fixing their PHP 8 problems, these projects now first have to raise their code coverage by writing additional tests.
And let’s not forget the difference between testing the happy path versus the unhappy path. A significantly large number of tests in projects only test the happy path, while the problems created by PHP 8.0 lie mostly in the unhappy path.
So, again, instead of being able to focus on fixing their PHP 8 problems, projects now have to write even more tests to make sure the unhappy path in their code is sufficiently covered.
Are you feeling the pain yet?
And don’t even get me started on named parameters in function calls. A change that was voted in late July, suddenly makes parameter names in function declarations part of the public API.
This means that every single function declaration in the public API of an open-source project has to be reviewed for those parameter names being suitable for public use, as as soon as PHP 8 came out, changing any of them will now be a breaking change.
Now doing this for your own small, 5.000 lines of code, pet project may be a one-day job, but having to do this for a 500.000 line codebase in one of the most extended pieces of software in the PHP world, where nearly everything is public API, in just four months… well, you get my drift.
Of course, you may say: “but a project can indicate it is not compatible (yet) with PHP 8 in the version constraints in their composer.json
“. You are wrong. As that presumes that the software will be installed via Composer, which for projects with a large non-technical userbase is rarely the case.
Open source projects, which basically are expected to be cross-version compatible by the release date of a new PHP version, now have to break with the past and actively declare themselves incompatible or “alpha-compatible” with the latest version of PHP for the time being.
And that is presuming those projects even keep track of changes in PHP ahead of a release and don’t just look at the changelog or migration guide for the first time once the release has come out.
With all that going on, the barrier for updating legacy code to use a more modern PHP version has gone up exponentially and for some, may even have become insurmountable.
I believe PHP is doing itself a huge disservice by not making these changes opt-in. It feels like it’s lost touch with a significant part of its user-base and that the impact of these changes has been grossly underestimated.
Yes, these changes are all nice and dandy when you work in a closed-source environment, where everything is under your control, you only have to deal with one PHP version at a time and get paid to write tests for the code you write.
However, for the majority of unpaid, overworked open source maintainers, working on software that is extended in ways they never imagined when the project started, these changes are a huge additional burden to carry, especially with the added time-pressure of having to be ready in time for the release of PHP 8.
I have seen beautifully coded projects, which are largely unused and some of the ugliest code I’ve ever seen is in projects used by millions.
Historically PHP has always been a very forgiving language. Now, that “contract” with the dev users has been broken.
Why force a “one way” of coding upon everyone? Why, when things are a significant break with the past, not make things optional?
I’d be the first to take that option. But the whole thing about it being an option is that it puts the power in the hands of your users, which is where it belongs.
While I laud the progressiveness of the changes in PHP 8.0, the reality is that 40.0% of all PHP servers still run PHP 5, 53% of that PHP 5.6, which means 47% still run on PHP < 5.6. *
There is just a hell of a lot of legacy code out there.
It’s all nice and dandy to believe that everyone has always named parameters in a sensible and descriptive manner and that everyone uses strict type checking and strict_mode already. It’s a wonderful illusion to believe that everyone manages their dependencies with Composer using strict version constraints. The reality is very different and I live in that reality.
So I join Derick in asking: please, please have some more emphpathy.
Let’s try and be kinder to each other. Take a moment to gauge the workload a proposed change will cause for maintainers of open source projects. Not just for your own small pet-project, but for the big, huge projects which run the internet.
Consider whether it is realistic to expect them to push EVERYTHING ELSE to the side and get every contributor they can scramble together to focus 100% on fixing the fall-out caused by your change, knowing that even then, chances are they would still not be ready in time for the release of PHP 8.0. If that’s the case, then maybe, just maybe, your change should be an option and not be forced upon the world.
I wish you all time to reflect and hope that 2021 will bring some light to the world again.
Are you saying code that used to work now fails, or that if you start using union types it fails?
Or are you saying that exceptions are being thrown when they previously were not? (There is a wide-eyed excitement by many who decide the direction of PHP to cause practically everything to throw an exception rather than allow a function to return a value that indicates an error condition, thus forcing developers to add try{} catch{} even when they are fully aware of the errors that are likely to occur and are ready to handle them with simple if{} statements. #justsaying)
Heh. Yeah, that is a slow-motion train wreck I watched happen, and was powerless to do anything about it.
The thing is, the majority of those with an actual vote — those who can be found on the the PHP internals list — are often not concerned about what the impacts of the broader PHP community, they often only seem to care above their pet use-cases and they make statements to the effect of “real programmers won’t be bothered” and “it won’t be hard to fix and they should be fixing anyway.”
The fact that list was once infamously called a toxic kindergarten should give you some indication.
IMO, there is a need for a huge number of “userland” PHP developers to spend time on the PHP internals list to raise issue when those who drive PHP decide to make the kind of changes that make userland developers life a living hell.
Said another way, if these things bother you, get ye to the mailing list and make some noise!
What I’m saying is, that code which used to work without even a notice or a warning will now throw an exception, which, when uncaught, is effectively a fatal error.
While I agree (selectively) using
try - catch
for expected error conditions is a good thing™, these aren’t expected error conditions, but new ones and by the sheer amount of them, devs may be tempted to just wrap the whole application in atry-catch
which is counter-productive.By all accounts, things are nowhere near as bad now as they were when that article was written. And I concur, an influx of people representing open source and legacy code projects on the mailinglist may be needed to turn things around.
All the same, I value my mental health and feel my energy is better spend elsewhere.
I feel your pain, Juliette. We all need to rest, recharge and brace ourselves for 2021.
The changes in PHP may aim for making things faster and more consistent, but from early benchmarks, PHP 8 isn’t necessarily faster. Hopefully minor releases will address some of the issues you’ve raised after the market weighs in on the major release.