If you work long enough with a language and figure out most its quirks, it's a breeze. It's nice that they are adding all these new features, but they are hardly what makes it or break it for me.
Here is the one features that is taken for granted in "modern stacks":
Edit file -> Alt+tab ctrl+R. Oops, Alt+tab fix -> Alt+tab ctrl+R.
When debugging I can do that 50 times a minute. With my react app, I can do it maybe 5 times a minute. With my golang app I'm lucky if I can do it twice a minute.
As for react, I work with a medium sized code base in the hundreds of thousands of lines and all I have to do is alt tab since it hot reloads for me. Don’t see how PHP is any better since it isn’t even hot reloading. Also with react I can update css and it doesn’t lose the state which is nice for debugging style changes.
Not denying your point though. There is some real awful stuff out there that could make a grown man cry.
This to me feels really underrated nowadays - at best, you shouldn't always have to reason about your code inside of your head and try to figure out how it'll work in detail, or read API docs for all of the obscure frameworks that you're using.
Test things in real time at first and in the cases where they don't, continue doing so, but with a debugger and stepping through everything bit by bit, or read the docs, or whatever the non-trivial cases will demand.
In my eyes, that's the exact same thing as autocomplete in IDEs - instant feedback, to free you from having to think about yet another mundane level of abstraction or API details, instead letting you solve the actual problems that you're faced with.
The human in the loop is a good thing. All things being equal, the type system is also a good thing, but what usually happens is that you end up checking your page once a minute or once every 10 minutes, not 50 times in a minute. That difference can make or break a project.
I'm working on a project that has a legacy PHP code base and a new JVM code base. What kind of naturally happened is that we end up doing most of our front end work in PHP and all of our new backend work on the JVM.
User interfaces, data science, and security/reverse engineering work are three domains that really require tight feedback loops. The work I did on parsing shell  is basically a kind of blackbox reverse engineering, and was done with < 100 ms feedback loops.
Of course you will need some manual procedure, and e2e tests, but not “50 times a minute”. That is just frustrating.
I am not saying that a type system will find all bugs. It will stop you from running incorrect code “50 times a minute”. Then you should have tests. Lastly you must also do some manual procedure (or run slower e2e tests).
Doing all this yourself constantly is just frustrating.
The difference in time it saves the dev can be anywhere from a few seconds to minutes per mistake.
Multiplied by hundreds of mistakes, it makes a huge difference. And that's not even getting into the advantages of better autocomplete for external libraries.
As someone who has written many thousands of lines of PHP, JS, TS, C#, Java, and Python, I now find it baffling that someone would start a project in 2021 without a great type system as a safety net.
PHP has always been a powerful language where the burden of making it work properly 250% relies on the dev. Stuff like enums should significantly reduce that ratio, it’s a big deal I think.
On the debugging part, I found something like ruby’s pry to be the easiest and fastest option. I wish PHP had something similar.
It's probably part of the reason for the success of PHP and similar.
However, being able to have a "compile" step that does a lot of work to make things faster is also very useful. The key is being able to switch between them easily.
In PHP for example there is the code cache (added later but basically standard now), and assuming it's a web app you probably want to crunch the images and CSS in production.
One of the reasons I use golang where possible, I feel more productive in golang because any mistakes you are make are almost always logical issues with the code, rather than language error and usually works first time.
In interviewing, I've seen a few candidates re-run their application after making single statement changes. They'll rename a variable, re-run. Change a conditional, re-run. Introduce whitespace, re-run.
These people aren't even confident in renaming variables!
PHP enables this type of underestimation in your own abilities. You don't need to distrust yourself so much.
Don't think you have to do this.
That might be true, but sometimes it happens that you overestimated and introduced a breaking change 20 changes ago and now you have to rewind your steps back to find the exact place. If an iteration can be done in less than a second, it's probably cheaper (and less stressing) to just check every single change like this. This is what many coding editor integrations actually do for you.
I've even had IDE refactoring tools fail on me whilst doing this, in type checked Java codebases, with reflection in place and annotations, which predictably caused problems down the road. At this point, i'll take any and every method that can help me in development, especially in the face of meaningless cruft and unreasonable complexity.
I'm actually writing this in my 5 minute break after being stuck at work 1 hour past my official work hours, due to some stupid bug where one service ignores a client certificate from service A, but not from service B on the server in containers.
The opposite end of this spectrum (my current circumstances) is completely unreasonable IMO - a change in code needs an app recompilation and a push to the container registry before it's deployed on the server (cannot reproduce locally, possibly proxy configuration is to blame, but it's so simple it should not be possible), whereas configuration changes need the Ansible playbook to run to the end, which also takes time.
Thus, my feedback loop is ~10 minutes for seeing a new way in which the app will fail to do something supposedly simple. Even in normal circumstances, local app reboots still take at least a minute or so, since JRebel and code hotswapping just doesn't work a lot of the time with the frameworks we're using. I'd take being able to see the changes in my code every X seconds over every X minutes any day of the week.
Even if i trust myself, i still want that freedom and speed of development and checking why everything breaks.
>Edit file -> Alt+tab ctrl+R. Oops, Alt+tab fix -> Alt+tab ctrl+R.
Yeah, this is pretty much what the Common Lisp and Smalltalk people have been doing since mid 1980s. Except that they're not limited to web applications. And also python people to some extent, with ipython. And Haskell people with ghci.
The value of less friction cannot be overstated in coding work.
With PHP, you're not limited to web apps as well. The same rapid-fire style development can be applied when building CLI applications.
> When debugging I can do that 50 times a minute. With my react app, I can do it maybe 5 times a minute. With my golang app I'm lucky if I can do it twice a minute.
Hmm... when working on React stuff I don't even have to do the ctrl+R stuff. Hot reloading in the browser is a thing and works quite well. When working with Django it's very close to being the same as the PHP experience thanks to automatic server reloading. I worked with PHP extensively back in the day but I never miss the tight feedback loop (although maybe this experience is why I always make sure I have such a tight feedback loop in whatever I do, I guess you don't always get it by default).
The heart of PHP (not the standard library binding C libraries part) do have come a very long way. Even the things that look the same to you on surface have change under the hood and are way more performant thanks to it.
If you find Emacs in a container, it's probably me ;-)
I think I would need to run some sshd program on the binary and use a reverse SSH tunnel from my laptop, but that requires me to expose an SSH port on the pod which isn’t a big concern, but it’s just a grind to get it all working end to end.