Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Where to begin indeed!

> - No proper connection pooling with circuit breakers.

PHP has had a "shared nothing" architecture since the very beginning, that includes DB connections. It helps it to scale (think micro-services being stateless in a modern context): nothing is shared between requests, again including connections, by design.

> - No proper multithreading (that works in web environment) or parallelism in general.

I once asked Rasmus about this face-to-face, during one of his presentations, specifically his thoughts about the pThread extension (https://www.php.net/manual/en/intro.pthreads.php), and he responded that it was not required in a web context, as web servers already have threads per request so its a mute point.

> - Almost everything blocks (even `new PDO('mysql:...')` can block for whatever the execution time limit is, if there is an issue with connection or MySQL server).

Well, it depends on your code of course, but pretty hard to proceed with some code that works with a DB when the connection can't be established, so proceed with what exactly other than error handling? Seems like a strange example. And as mentioned above, no (excluding optional pThreads) support for asynchronous threads in the language, so...?

> - Most libraries are implemented in C instead of in PHP, whereas with other languages people try to avoid native code as much as possible. This means that code is not memory safe, and understanding or contributing is close to impossible.

Ok now you have just thrown away one of the main benefits of PHP. Remember, Rasmus is a C programmer, not a PHP programmer, so he wanted to leverage that HUGE library of existing C-code from his new scripting language, from the very beginning, deliberately by design.

> The reason for this is because PHP doesn't support many things that are expected in any other language.

Yes it does, via the C-extensions, see above.

> PHP C API is hard to understand, hard to use, and documentation is subpar.

Yes programming in C is hard.

> - There is no way to easily share memory between processes. You have to rely on APCu (hack), because this cannot be implemented in PHP.

Deliberate design choice, "shared nothing architecture", stateless between requests, as above.

> - Did I mention that almost anything can block? ODBC? PDO? Some 3rd party library? Even set_time_limit cannot help you here. Handling this gracefully is close to impossible.

Yes because each request is a synchronous thread, as described above above. By design.



> Yes programming in C is hard.

I'm not anti-PHP, so I'm not supporting the grandparent post in general. But as someone who is working on a PHP extension right now, I agree that PHP's C API is under-documented.

The best semi-official documentation I have found is http://www.phpinternalsbook.com/, but it is incomplete. Some important chapters are just blank, eg http://www.phpinternalsbook.com/php7/internal_types/zvals/me.... A lot of questions I can only answer by grepping the source code of the extensions in the PHP distribution itself.

I don't think this is just a case of "programming in C is hard." Some C APIs are amazingly well-documented, especially Lua. If you open up Lua's reference manual (https://www.lua.org/manual/5.3/manual.html#4), it explains just about everything you need to know to write good C extensions. Every public function, macro, and constant is documented. Python's C API is pretty well-documented too.


> Well, it depends on your code of course, but pretty hard to proceed with some code that works with a DB when the connection can't be established, so proceed with what exactly other than error handling? Seems like a strange example. And as mentioned above, no (excluding optional pThreads) support for asynchronous threads in the language, so...?

What to proceed with? Well, any other code of course! Does all code in a current task depend on writing something to a database or reading from it? What if you need to get data from multiple sources? It would be stupid to wait for every single connection to be made sequentially, instead of proceeding with the next one.

This is just one example. This is actually what Node is often lauded for, making a lot of use of single cores, due to putting one "task" at rest and asynchronously proceeding with the next, not blocking.


  I once asked Rasmus about this face-to-face, during one of his presentations, specifically his thoughts about the pThread extension (https://www.php.net/manual/en/intro.pthreads.php), and he responded that it was not required in a web context, as web servers already have threads per request so its a mute point.
if each web server thread that serves a request ends up spawning a full PHP process then it's not a mute point.

  pretty hard to proceed with some code that works with a DB when the connection can't be established, so proceed with what exactly other than error handling? 
proceed with all the rest of the bootstrapping code in parallel instead of blocking and waiting for each.

  is a synchronous thread, as described above above. By design.
it's a synchronized full forked process. Because the runtime was written using memory unsafe C features from the start. By design doesn't excuse it being a bad design.


It's php-fpm persistent threads (seperate Daemon listening on port or socket), not web server threads, just to be specific. You have a lot of control of how many PHP threads you will allow per web node using php-fpm, very reliable tech. The days of mod_php are long gone.

So I meant one thread per request at the php-fpm level, not Nginx/HTTPD level.

* Edit for spelling


> PHP threads

Still, my understanding is that php-fpm spawns processes, not threads. What is "persistent" is the php-fpm daemon itself that's connected to nginx, but each request spawns a whole process which has to bootstrap your whole framework every time. That's the reason frameworks like symfony run almost mandatorily with something like opcache.


Oh I see, yes you are correct each request will bootstrap your PHP code stack framework each time (mitigate with opcache). Seems weird I know, but it goes back to that "shared nothing" principal: nothing is kept in memory between requests. On the plus side of that principal: nothing is kept in memory between requests that is not currently being used.

Coming from a Java background into PHP, this really confused me at first, until I started to think about PHP's approach as some kind of super-agressive garbage collection: everything gets released in that reqest thread once it's completed.

It's a fundemental design choice of the language that you have to embrace if you want to use PHP (I love it now, simplifies so much), or move on to another language.


> PHP has had a "shared nothing" architecture since the very beginning, that includes DB connections. It helps it to scale (think micro-services being stateless in a modern context): nothing is shared between requests, again including connections, by design.

A bit ironic that you compare it to microservices, because that exact property of PHP makes it massively unsuitable for microservices and scaling, because it requires another layer in between the microservice platform handling the scaling, and the actual application.

PHP has it's uses, but I wouldn't go beyond a classic monolith or "backend/frontend" style application with it, with very little, manual scaling. If you go beyond that, you could probably manage to do that with a proper architecture and doing wonky stuff, but would it be a good fit? Absolutely not.


I've been hearing that "PHP does not scale" arguement for many, many, years, in many, many, variations.

When you really have to scale, infrastructure, resources, and networks will rapidly overtake any concerns around your choice of language. You can develop crappy architectures in any language, and the inverse is true.


Not my experience. At scale, once you go down the 'cloud native' (kubernetes) path, the infrastructure part becomes relatively straight-forward, but PHP's weaknesses become very apparent.

Doesn't work very well with message queues. Sure, pushing messages is not a problem, but consuming? Something has to do it? But it won't be written in PHP. It doesn't work very well with SQL databases, and with that I mean not the querying etc, but connection pooling, so the database server doesn't suddenly gets flooded by thousands of connections because a service is autoscaled due to heavier load (and sadly, that's a real-world example that brought down a database cluster). Tracing is doable, but not ideal, metrics are hacky due to the need of weird extensions to support shared memory, or rely on an external database such as Redis, which kinda defeats the point of metrics being lightweight. And tuning the PHP runtime almost rivals the JRE...


> but pretty hard to proceed with some code that works with a DB when the connection can't be established

When you can't query your DB, you hit your resident memory cache. Redis, Memcached, etc. You probably have background threads that do cache invalidation, queue management, etc.

You frequently have to be more reliable than your database.

> he responded that it was not required in a web context, as web servers already have threads per request so its a mute point.

I use multiple threads in a single request flow frequently. Dispatching requests to other services or data stores, updating in-memory caches or queues (not Redis, but living within the app itself), etc. It's an important tool.

> Ok now you have just thrown away one of the main benefits of PHP. Remember, Rasmus is a C programmer, not a PHP programmer, so he wanted to leverage that HUGE library of existing C-code from his new scripting language, from the very beginning, deliberately by design.

Good for him. I don't see why that matters for anyone else. It's ugly and inconsistent, takes time to memorize, and leads to errors.

> Yes because each request is a synchronous thread, as described above above. By design.

This limits you to writing basic CRUD. And so many other languages offer this.


> When you can't query your DB, you hit your resident memory cache. Redis, Memcached, etc.

You would query those first surely, before loading the DB? Regardless, I've been using Redis and Memcache for years from PHP, so mute point.

> I use multiple threads in a single request flow frequently.

So how do you track those? And for how long do they live after the parent request has been processed, or do they block the parent? Gets complicated quickly.

> It's ugly and inconsistent, takes time to memorize, and leads to errors.

Rasmus will admit the same, but he will also admit he does not care (I've seen him say this during a talk). Nobody bought your product because it had beautiful, consistent code.

> This limits you to writing basic CRUD. And so many other languages offer this.

99.9% of web apps are CRUD.


> You would query those first surely, before loading the DB? Regardless, I've been using Redis and Memcache for years from PHP, so mute point.

You probably want to report a degraded status so any traffic that can be bled off into another cluster can do so.

> So how do you track those?

There's a thread pool.

> And for how long do they live after the parent request has been processed.

They might live on after the request flow if they're still doing work.

> or do they block the parent?

Depends on the job and the nature of the API.

> Gets complicated quickly.

That's engineering.

> Rasmus will admit the same, but he will also admit he does not care (I've seen him say this during a talk). Nobody bought your product because it had beautiful, consistent code.

That's why I buy a lot of things. It's also one of many reasons why I don't buy PHP.

> 99.9% of web apps are CRUD.

Now that platforms have taken over, I don't think this is the case. Large systems have sophisticated needs that don't always map to a traditional relational data store. PubSub, feeds, queues, concurrency, eventual consistency, vector clocks, etc.

Platforms are going to eat the long tail in the search for growth.


Just FYI since you've done it twice and might want to know, it's not mute point. It's moot point.


LOL thank you, English is hard (like engineering) ;-)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: