Re: [VOTE] True Async RFC 1.6

From: Date: Fri, 21 Nov 2025 13:45:28 +0000
Subject: Re: [VOTE] True Async RFC 1.6
References: 1 2 3 4 5 6 7 8 9 10 11  Groups: php.internals 
Request: Send a blank email to internals+get-129366@lists.php.net to get a copy of this message
Hello. To use AMPHP you don’t need to run its server. But let’s simplify the situation. You have Fiber. With Fiber you can build an EventLoop + Scheduler, create two coroutines, and then run code inside them that, for example, renders a template. It will require a fair amount of code, but it’s possible. At the same time, ob_start/ob_end will immediately break, because they don’t support Fiber switching. This is a known bug. And if you pass global state into closures, and that state changes unpredictably, the application logic will essentially break. **What’s different with TrueAsync** 1. You don’t need to write a lot of code. Yes, just spawn(); 2. ob_start and ob_end will work correctly. 3. If closures share a variable that multiple coroutines write to unpredictably, the application will still break. In other words, no matter how asynchrony is implemented in PHP (and other langs), it will always require correct handling of shared memory. And I want to clarify a bit. This is not about a global variable. It’s about shared memory. These are not the same things. A local variable can be passed into a closure by reference. But if you don’t call WP() inside a coroutine, nothing prevents you from using asynchrony. In TrueAsync there is a Dockerfile for FPM, you can install it locally and try running WordPress. I’m sure something will break, but not everything at once :) > My understanding of AMPHP is that things only become async if you explicitly run AMPHP as your > web server. It either has no effect > if your application is running Apache + mod_php OR your application 100% breaks with nothing > getting executed at all. Is this not true? You can use it without a server. The only difference is that the coroutines won’t live longer than the HTTP request. The same applies to TrueAsync when running under FPM. > When I try to open my website locally it will either have everything broken or it will just > work regularly and nothing will be running async. There is no other option. It won’t break on its own. It will only break if that “something” shares a variable or resource with your code. If you write code according to SOLID principles, the chance of breakage is very low. If someone writes coroutine code and completely ignores memory handling, it’s the same as writing an infinite loop. Can they do that? Yes. Can you download that code? Yes. Can it break everything? It can. What’s the conclusion? > I do composer update one day and test my home page and it > works. But deeply nested somewhere there is a feature that will use Package A which > then spawns a coroutine and leads to my global state code behaving weirdly. It's not a > fatal error. It's not very clear at all to me that something changed, > but now my array indexes are triggering DB updates out of order. The exact same thing will happen in code without coroutines if, for example, you have a class, you pass an array to it by reference, and that class silently corrupts your values. You don’t need asynchrony for that to happen. ```php <?php class Storage { private array &$data; // holds a reference to the external array public function __construct(array &$data) { // store the reference $this->data = &$data; } public function loadUser() { // looks like a harmless read return $this->data['user'] ?? null; } public function updateInternally() { // silently mutates the external array $this->data['user'] = 'hacked'; $this->data['counter'] = ($this->data['counter'] ?? 0) + 1; } } // --------------------- $shared = [ 'user' => 'admin', 'counter' => 0, ]; // create the class, passing the array by reference $storage = new Storage($shared); echo $storage->loadUser() . PHP_EOL; // admin // somewhere else this method is called, modifying the shared array $storage->updateInternally(); print_r($shared); // the array is now corrupted unexpectedly ``` There is no asynchrony in the example above. It’s just normal code. It breaks application logic because the class secretly holds the array and modifies it without permission. And a coroutine is just a regular object. If you pass a referenced array into a coroutine and then say something “accidentally” broke, it wasn’t accidental. Did the array get there by accident? No. Did some developer write the code by accident? No. It’s a bit different from synchronous code, but the meaning is exactly the same. I have a mental habit: when I write asynchronous code, I always assume that any object shared between coroutines can change at any moment. Similarly, if you hand off memory ownership to another class or share memory, you have to keep in mind that there is a chance some developer might accidentally do something wrong. The only difference between synchronous and asynchronous code is that you don’t have a precise moment in time when the change happens. And yes, that makes debugging harder. It makes finding bugs harder. But it’s not something fundamentally new. Yes, making the same mistakes with AMPHP is harder, because you need to install a whole package and so on. But that’s not a guarantee :)

« previous php.internals (#129366) next »