The Thing About PHP
asko.dev
asko.dev
- You don't need to explicitly install your replacement code and start that server (java -jar .... / node server.js )
- You don't need a systemd unit to keep your server running ( you can deploy as many PHP files as you like and they'll all be "running" )
- You don't have to worry about keeping your server up (the php file).
- You don't need to use Docker because PHP is pretty stable target.
- You're not forced to deploy Kubernetes or Docker swarm to deploy code infront of users.
- You could use Ansible to deploy your PHP but you can probably just use git.
- You can spin up multiple servers and deploy the same file to them all and nginx and php-fpm shall handle concurrency and parallelism for you since each PHP session is independent and stateless.
This is a double-edged sword though. Let's say I have a PHP file that "include"s another one and a request arrives in the middle of such a deployment where the first PHP file has been replaced but the second has yet to be - you now have undefined behavior.
Filesystem-based URL routing is one of the "features" I hate the most in PHP as it leads to countless security issues - simply uploading a file in the wrong place (or sometimes merely with a wrong extension) immediately turns into an RCE.
PHP itself doesn't follow filesystem-based routing, your webserver config does. PHP just executes what th webserver tells it to. Most PHP applications written in the last 10 years use a single entry point and are no longer prone to the attacks you are describing.
It's indeed possible (and quite pleasant) to do proper PHP with a good framework, sane web server config & modern development practices. The problem is that a sizeable chunk of the PHP ecosystem (and very popular projects such as Wordpress) are not doing that.
Not sure I agree with this. Upgrading PHP versions or managing extensions can be _sometimes_ a PITA, using Docker makes it easier. but for simpler apps, sure, apt install php and a few extensions, and you are good to go.
OTOH - a bit off though - I still haven't figured out how to properly build a php stack with Docker. Do I add an nginx instance to each app image? Or should the app container expose only the FPM? If I'd have to do it nowadays, I'd probably go with the second.
You do, actually. You need a systemd unit to keep your apache / nginx + fpm / whatever server that is actually handling and processing your requests.
Edit:
> You could use Ansible to deploy your PHP but you can probably just use git.
You can use Ansible to deploy your [Python | Ruby | Perl | JS | Java | literally every other language on earth]. I can't see your point.
You don't need a systemd unit file for your php files whereas you do for your Java app unless you're using a Java container such as Tomcat.
I have typically used system packages to install PHP and nginx and fpm which includes those systemd units
My overreaching point was the ease of using PHP. As a low tech solution.
In the previous era you just FTP your files to the server but you can use git instead which is probably easier than using Ansible. (That's my comparison of FTP vs Git vs Ansible and which is easiest)
Doing zero downtime deployments with PHP is easier than Java (rolling deploys in Kubernetes)
If you just copy your code without explicitly flushing opcache, or having traffic on that server that you are copying your code to, that can lead some interesting issues where your old and new code pieces running simultaniuosly
> You don't need a systemd unit to keep your server running
Actually a systemd unit keeps your PHP-FPM processes running on most of the Linux distributions. But writing a systemd unit config file is like 10 lines
> You don't have to worry about keeping your server up
This is redundant with the point above.
> You don't need to use Docker because PHP is pretty stable target.
First, you don’t need Docker for other languages. Actually a static linked binary (for example Go) is much more portable than a PHP application. Secondly, good luck for keeping your OS up to date.
> You're not forced to deploy Kubernetes or Docker swarm to deploy code infront of users.
You are not forced to do this with any other languages. I was running Java, Node.js, Python, Ruby, Go applications without any of these (in large scale).
> You could use Ansible to deploy your PHP but you can probably just use git.
You can do this with any other language.
> You can spin up multiple servers and deploy the same file to them all and nginx and php-fpm shall handle concurrency and parallelism for you since each PHP session is independent and stateless.
Haha, thats a good joke. Once we ran into a PHP-FPM issue where separate FPM pools were running each others (separate) codebase randomly. And there are sessions, local files and opcache that are all stateful. PHP won’t help you writing safely scalable code at all. That’s up to the developers, regardless of the programming language. Oh, and PHP-FPM has nothing to do with handling concurrency.
You also don't need docker, application servers were docker before docker was an idea.
You certainly do need to keep Apache or ngix up.
I like that Erlang programs are robust and even if a program crashes, the BEAM runtime won't take the BEAM process out.
PHP programs don't tend to cause the nginx or php-fpm to crash but just the particular interpretation PHP instance which is replaced with a replacement restarted automatically.
Sure, 10-20 years ago the language was more hacky than anything, but nowadays its a solid choice for backend stuff, with lots of activity, new innovations, good, proven frameworks (Symfony, Laravel) and also lots of people who have experience in it.
I have a few projects running a PHP API with a JS frontend (Vue in my case) and it works pretty nicely. Best of both worlds!
Examples off the top of my head:
* Lists and dictionaries being the same data type ("array"). This makes it impossible to distinguish between an empty list and an empty dictionary, good luck encoding that JSON.
* Arrays are pass-by-value
* '123' == '+123' evaluates to true
* '0' == '0.000' evaluates to true
* `$a = true; $b = false; $c = $a and $b;`, $c evaluates to `true`
* Closures requiring you to explicitly list every variable from the parent scope you want to use
* References (&$var) have a lot of footguns
* array_key_exists and property_exists taking opposite parameter orders
* stdlib naming in general being pretty bad, with the stated justification being that strlen() was used as a hash function in early PHP versions, so functions were named to achieve an even distribution: http://news.php.net/php.internals/70691
* The null-coalescing operator is also an are these even valid identifiers-coalescing operator – here $result is 2:
$myvariable['x'] = 1;
$result = $myvvvvariiiiableee['x'] ?? 2;
* '0e123' == '0e456'All those bad things about PHP you've listed go well with Gary Bernhardt's WTF video about JS's inconsistency.
JavaScript is not well-designed however you squint at it, and claims that it's gotten better must come from people that have not used any other language before.
What's the difference between that and `pip install psycopg2` (which actually seems easier to me)?
Hell no. PHP is awful for background processing. I do DevOps for a bunch of different languages (Node.js, Elixir, PHP, Java) and PHP is always the problem child. Poor concurrency, memory leaks, general RAM bloat, etc.
And if you google for “php memory leak”, you’ll get a lot more than 0 results.
Since php scripts are meant to be run once per request memory leaks are not an issue - any build up gets “reset” once execution ends. There are however shit frameworks that have circular references to objects and do all kinds of crap that builds memory up - easily avoided by parallel queue consumers.
Threading and async are non issues given my statement above, hence me blaming on the dev’s skill and not understanding what the language does.
For instance, you dont normally start a background process with an event loop to handle stuff. You start queue consumers at set intervals that run in parallel, or scripts that process batches of code - thus mimicking parallelism in a classic multi threaded app. This way you reduce the blast radius, are guaranteed that at least some data will always be processed and avoid memory leaks alltogether. No need for “conscious” async since its async by nature.
However there is nuance in everything. Would you be able to provide a specific example of where you end up with such issues so i can better detail an example of how i would approach it?
Yes, and that’s exactly why I said that PHP is awful for background processing, because there the process ideally runs continuously, or at least as long as there’s data to process. With PHP, I have to continuously re-spawn the processes to keep the memory leaks in check.
If your application is so simple that it doesn’t need to process data outside of the request/response cycle, I’m sure PHP is fine.
And sure, you can compensate for PHPs lack of async processing by spawning more processes, but that makes the RAM bloat problem even worse.
We actually had a big argument about building them like this for exactly the reasons you mentioned though - the preference for me and some others was to run them as once off's from cron, specifically to avoid the possibility of memory issues.
Our tech lead wanted them to run as services (I think to improve responsiveness primarily). I didn't think it would work as well, but history has proven that it worked fine. I can't say it was better - it took a while to work out the kinks - but these things have been happily running for over a decade with basically zero issues relating to memory leaks, etc. They're not super complicated but not trivial either.
PHP isn't great for persistent background processing because that's not what it's designed for, any more than Python is good as a frontend DOM manipulation language.
But one common issue with php devs is that they are religious about the language. Probably because they dont actually understand programming as a whole - not even php itself. They should use the best tool for the task at hand and not be religious about php.
I remember when i was in that dark place i even considered php for gui apps lmao because php was hot hot hot.
I was involved in several large PHP projects which did a lot of background processing (not Google scale, but telco scale) and performance was more than adequate in all cases.
The advantages of running a single codebases far outweighed any potential benefit of a speed increase from switching to another language. (... I say that having been the jerk that actually did rewrite one small component in C and it turned out to be a huge waste of time and effort and just meant something additional the team has had to manage in the almost 20 years since I did it!)
But yes, the reluctance to use other languages and different codebases was also a common argument in all php teams i worked with. People need to understand that a language is a tool not a religion. If using php for the web layer, python for processing background tasks and nodejs for apis makes sense then do so by all means. PHP devs need to understand that.
The PHP apps i built were for large userbases processing billions of pounds and in one case dollars a year. The language if used right is superb.
It’s the type of dev using it that’s usually not, I am sorry to say that.
Heh, nah, the rest of the stack is still running. The first line of PHP code that I personally wrote was in 1999 and it's still there; the core CMS was written earlier than that.
It's not doing anywhere near the traffic it used to (it was a reasonably popular video gaming site back in the day; it gets almost zero maintenance & I'm continually impressed it's online and working just as well as it did (... arguably better because it has so much less load :)
> It’s the type of dev using it that’s usually not, I am sorry to say that.
I don't disagree but I also don't think that is a problem unique to PHP at all. Arguably some languages are better than others at keeping developers on the rails in some cases, but you're going to see garbage written in everything eventually.
Yes, there are often things besides pure request/response that an application needs—but in all the cases I have yet personally come across, those were easily served by simple cron jobs calling PHP scripts from the command line (either directly, or through a Symfony app's Command interface).
To be clear, I do not at all dispute that many types of application do need some kind of persistent background processes, and those would be much less suitable for building (entirely) in PHP. Indeed, I am happy to also stipulate that it may not always be easy to tell whether that will be the case when initially designing the spec and choosing one's tools.
But there are plenty of applications that work perfectly fine using nothing but request/response, and many others that only need to add simple triggered scripts to that.
I think op is having more of a problem with languages that are not fully typed than php per se.
It runs everywhere and it's cheap. It's essentially serverless without the expensive, no-cost-limit cloud providers.
I've made a ton of personal projects in php, and I will continue doing so. They're great, they just keep running even when I don't look at them for a long time. Which is exactly what I need.
The reason is pretty simple. Hack has a compilation step. PHP does not. Generics in an interpreted language means runtime errors, which are far less valuable and more troubling than compilation errors.
PHP’s loose typing + an offline static analyzer like phpstan will get you roughly the same result without the runtime errors.
function test(bool $param) {}
You will get an runtime error if you call it with wrong type: Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean
However generics are probably costly to typecheck runtime? I haven't studied the reason why there is not generics planned.There's a video about generics in PHP, posted 2 hours ago: https://youtu.be/JtmRG5lCENA
All composer adds is the ability to easily use other people's code in your app. And that's not a new thing: people did that in one of two ways pre-2010:
1. They used PEAR/PECL, upon which composer is a massive improvement
2. They copied it from experts exchange, some spammy site like hotscripts.com, or - most often - from the comments section on php.net. The latter was a surprisingly good source but none of this was ever sustainable.
Honestly, I wish more documentation out there had comments/discussion at the bottom.
For example, what if would be like to find myself reading about setting up OpenID Connect and having the first (most upvoted) comments on the first page explain things that might not be clear in the docs, analogies that make things easier to understand, or code/configuration snippets for a particular technology.
Somehow the comments in PHP docs were usually like: "after reading the docs, here's what you might want to really know", a bit like those tl;dr apps for manpages: https://tldr.sh/
But PHP developers, boy oh boy, are a different story.
My favourite is how they all still debate setter and getters and almost none know the language but only the framework they use and code usually turns into a huge pile of unmaintainable crap. But hey they use ORMs just in case they’ll swap database engines (happens so rarely not even worth mentioning).
Such a nice language bastardised by over engineering and reinventing the wheel. Sad.
That's not to say that it doesn't happen in other languages, but I've never seen PHP code written by a stranger that didn't make me squirm.
Last time, long time ago, when i touched a php symfony project i ended coding yml instead of actual php because _everything_ was in a config file - hundreds of packages and libraries just because the dev couldn't be bothered to issue calls to native php functions. Hilarious. However i did make a killing in training teams in design patterns and coding practices to help them maintain quality.
And almost always my advice was to write framework agnostic code (treat the framework as if it were just a dependency). Worked nice. Clean little specialised classes, no config maintenance madness, i also enforced running code linters and smell detectors on each commit and push. Gave up on the language when i noticed that _literarily_ all teams had the exact same issues, the exact same topics of debate and the exact same flamewars.
Therefore all in all i think, for me, php belongs to history, and without wanting to insult anyone, i try and avoid any debated with a pho developer - it simply gets stuck in a bike shedding endless loop.
As I gained more experience, I've become wary (and weary) of how a language or framework can mis-guide programmers into messy code that's difficult to grow and maintain. But then again, as long as the work gets done and money gets made, perhaps it doesn't matter much to some people. For myself, I want to take pride and pleasure in the work, and there are other languages with better design and developer experience.
Living with some of the hellish code that exists in the wild (and honestly terrible code that I've written myself) has been a great learning experience, making me a better programmer. It's important to be sensitive to code smell, noticing how it's going in the wrong direction and what can happen in the long term, understanding how it happens, what can be done to prevent it - and better yet, how a language (syntax, patterns, tooling, ecosystem) can be designed to guide oneself and others so that good code can be written "naturally" by following best practices that are built into it.
And PHP has wide built-in support for multiple database engines (check out PDO) so this is largely not a part of an ORM.
This leaves the ORM to focus on higher-level work, like how to abstract the differences away regardless of which engine you end up using and focussing on the representation of your data and the API you use to interact with it.
That's pretty powerful and has allowed tools like Laravel and Symfony to suit a super wide range of needs.
But yes, it does also mean that you're not switching your entire language or framework stack when some database technology providers baits-and-switches their licensing - which has been known to happen
Can you expand on this please? What exactly makes it easy to scale in which way?
How will you deal with the wall you hit when you outgrow your one central database?
As such errors would be contained within the context of that request, while memory leaks if any would be a non issue since gc is done when the process literarily ends. So that covers that aspect of scaling.
Then all of these external state maintenance dependencies each scale independently. For instance session data can be distributed against endless clusters of redis or nosql instance. Heck some people even used remote file systems for it. Databases would be clustered too - say a couple mysql percona write instances and endless read instances. If that’s not enough then use an intermediary localised storage and queue writes. Or use something like cassandra. Database connections can also be round robin’d since each script would be re executed and connection reopened anyway (can be reused if needed) so they can connect to any server in your cluster. You can also use a database load balancer and sharding, or nosql for fast writes than then get further processed into a relational database.
All in all php webapps can be scaled infinitely. Not as efficiently per instance but fairly straight forward by even average devs with the right guidance.
For some past clients i scaled apps to billions of unique monthly requests with a fairly low effort. Happy to answer any specific question.
And 100% right about the "over-engineered" part.
The "real" danger for PHP is to end up like Java (not the JVM, Java)