But at least the python folks provided some tooling to bridge the gap between v2 and v3 such as backporting features from python 3. Also minor version updates generally don't break whole codebases.
Apropos Java backwards compatibility, Microsoft has been pretty good at ensuring strong backwards compatibility with .NET code. I've seen .NET 1.0 source compile and run just fine on .NET 4. Hell I've even witnessed .NET 1.0 binaries run just fine without recompilation in newer .NET environments.
Sure there's breaking differences between .NET Standard and .NET Core but they're two different products and that was made pretty apparent from the get-go.
That was one of the lowest effort upgrades I ever did for my company (backend services, no front end websites).
One of the other reasons Java is popular in big companies is the low effort it requires to find people who can work with it.
If your application does a lot of ASCII/unicode/raw string and byte manipulation, the transition from Python 2 to 3 can be very cumbersome.
I mean, I agree with you. But Java benefits from well thought-out design constraints, ground-up IDE support, and an amazingly flexible bytecode interpreter. Normal people in the early 90s didn't have the resources to produce a language like Java.
It's not just PHP. But Python 2x / 3x as well.
Just to point something out: this is one reason why Java is so well liked for large enterprise code bases. They have been religious about backward compatibility in new versions.
A 2nd principle I would advocate is that if there must be a breaking change, it should be caught at compile time, not at run time. The project should fail to build, and the errors point you to exactly where the source code problems are.
Other language systems would do well to embrace backward compatibility and build time errors over run time errors. IMO.