Re: PHP True Async RFC Stage 5

From: Date: Sat, 15 Nov 2025 16:20:41 +0000
Subject: Re: PHP True Async RFC Stage 5
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to internals+get-129234@lists.php.net to get a copy of this message
Hi Rob, Edmond, > On Nov 15, 2025, at 06:37, Rob Landers <rob@bottled.codes> wrote: > > I have concerns about the clarity of when suspension occurs in this RFC. > > The RFC states as a core goal: > > "Code that was originally written and intended to run outside of a Coroutine must work > EXACTLY THE SAME inside a Coroutine without modifications." > > And: > > "A PHP developer should not have to think about how Coroutine switch and should not need > to manage their switching—except in special cases where they consciously choose to intervene in > this logic." > > [...] > > With explicit async/await ("coloured functions"), developers know exactly where > suspension can occur. This RFC’s implicit model seems convenient, but without clear rules about > suspension points, I’m unclear how developers can write correct concurrent code or reason about > performance. > > Could the RFC clarify the rules for when automatic suspension occurs versus when manual > suspend() calls are required? Is this RFC following Go’s model where suspension timing is an > implementation detail developers shouldn’t rely on? If so, that should be stated explicitly. Keep > in mind that Go didn’t start that way and took nearly a decade to get there. Earlier versions of > Go explicitly stated where suspensions were. > > — Rob To provide an explicit example for this, code that fits this pattern is going to be problematic: function writeData() { $count = count($this->data); for($x = 0; $x < $count; $x++) { [$path, $content] = $this->data[$x]; file_put_contents($path, $content); } $this->data = []; } While there are better ways to write this function, in normal PHP code, there's no problem here. But if file_put_contents() can block and cause a different coroutine to run, $this->data can be changed out from under writeData(), which leads to unexpected behavior. (e.g. $this->data changes length, and now writeData() no longer covers all of it; or it runs past the end of the array and errors; or doesn't see there's a change and loses it when it clears the data). Now, yes, the programmer would have to do something to cause there to be two coroutines running in the first place. But if _this_ code was correct when "originally written and intended to run outside of a Coroutine", and with no changes is incorrect when run inside a coroutine, one can only say that it is working "exactly the same" with coroutines by ignoring that it is now wrong. Suspension points, whether explicit or hidden, allow for the entire rest of the world to change out from under the caller. The only way for non-async-aware code to operate safely is for suspension to be explicit (which, of course, means the code now must be async-aware). There is no way in general for code written without coroutines or async suspensions in mind to work correctly if it can be suspended. -John

« previous php.internals (#129234) next »