Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129252 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id B09C71A00BC for ; Sat, 15 Nov 2025 23:17:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1763248628; bh=AJ9iQw/HN8fLOYiD+9F3wxOztpO+Ol6FoxYcU3Vy7ww=; h=Subject:From:In-Reply-To:Date:Cc:References:To:From; b=blgy1tVUyWDPlPe/CdK96GtDv6UoHhFa2v//CX/JSWIqV+kae0HnhS2kr2JQlI/ZA na3Hj20GWE6kx4Cb4vHoXlGQ2RIce9xVP0ps+KoQ8yehOzghD3yJ+f+z5zZESbR8XI nvu7BnSEptevctLFERB1pFekBftOEpdN9Q7MqiGFrYExL0MPv8kMrjTWEVZYtY67VZ wR3IFu+joKC3R+lOYFMx/HQXdI9VEJyHxKnADRQIXkZt8lfW/mTl3uH76HWRvmiigz djFHFm73QT/ziAWqyB6ObXACbLwycPXi+63x1cCY6MxGtTOuIXwb/G8fBGycRuRTOF eSbEInnHGF53Q== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id C324018003E for ; Sat, 15 Nov 2025 23:17:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from nebula.zort.net (nebula.zort.net [96.241.205.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sat, 15 Nov 2025 23:17:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=zort.net; s=zort; t=1763248617; bh=AJ9iQw/HN8fLOYiD+9F3wxOztpO+Ol6FoxYcU3Vy7ww=; h=Subject:From:In-Reply-To:Date:Cc:References:To:From; b=n2XKNhpsz3ZIAMl5s5uwzfyTbNtKzC/GSWS+uwOoj7/8DxsxBtN15CZ/RSof2e8PF OsP7n7rzXoZjBOhoDtSL3Sx9TqmKEE0CEwyVEfjsfaWchAeXFJ3To5IFrB8DYFnhBB drH9BlhY0LS+qzQ6piqipaSvYAg6vuZobgg0NF3Y= Received: from smtpclient.apple (pulsar.zort.net [96.241.205.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by nebula.zort.net (Postfix) with ESMTPSA id 565FF1300460; Sat, 15 Nov 2025 18:16:57 -0500 (EST) Content-Type: text/plain; charset=utf-8 Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.700.81\)) Subject: Re: [PHP-DEV] PHP True Async RFC Stage 5 In-Reply-To: Date: Sat, 15 Nov 2025 18:16:47 -0500 Cc: Rob Landers , php internals , Jakub Zelenka , Larry Garfield Content-Transfer-Encoding: quoted-printable Message-ID: References: <6618a91c-5393-4f40-88b5-b5041ee09deb@app.fastmail.com> <3e0cf0a1-c1a3-4e05-97ba-0eeb7f559a53@app.fastmail.com> To: Edmond Dantes X-Mailer: Apple Mail (2.3826.700.81) From: jbafford@zort.net (John Bafford) On Nov 15, 2025, at 16:20, Edmond Dantes wrote: >=20 > Hello. >=20 >> An array_map() always blocks the thread but should never suspend. > This function is not related to this discussion or to the RFC. function writeData() { return array_map(function($elt) { [$path, $content] =3D $elt; return [$path, file_put_contents($path, $content)]; = //POSSIBLE SUSPENSION POINT }, $this->data); } Now this array_map function potentially suspends. As of course does this = writeData(). And whatever calls this writeData(). And so on up the = stack. _Any_ function that calls any other function might have a hidden = suspension point. And as Rob pointed out, any hook might also have a = hidden suspension point, so you can't even trust code that doesn't look = like it calls functions. And even if there are no hooks, __get(), = __set(), etc are also there to ruin your day. >> To provide an explicit example for this, code that fits this pattern = is going to be problematic >=20 > Why is this considered a problem if this behavior is part of the > language=E2=80=99s contract? Because this RFC *changes the contract* out from every line of php code = ever written. Code that used to be strictly synchronous now has async = suspension points it didn't ask for. >> $this->data can be changed out from under writeData(), which leads to = unexpected behavior. >=20 > So the developer must intentionally create two different coroutines. > Intentionally pass them the same object. > Intentionally write this code. > And the behavior is called =E2=80=9Cunexpected=E2=80=9D? :) Yes. To repeat, a core premise of this RFC is: > =E2=80=A2 =46rom a PHP developer's perspective, the main value of = this implementation is that they DO NOT NEED to change existing code (or = if changes are required, they should be minimal) to enable concurrency. = Unlike explicit async models, this approach lets developers reuse = existing synchronous code inside coroutines without modification. > =E2=80=A2 Code that was originally written and intended to run = outside of a Coroutine must work EXACTLY THE SAME inside a Coroutine = without modifications. With this, the RFC implies that I should be able to take my synchronous = PHP code and run it in a coroutine with other synchronous PHP code, and = it will all just work. But obviously that won't work. I understand that a different interpretation of this wording is, "well, = that code does exactly what it did before, just that with coroutines, = that happens to be broken". I could maybe squint and grunt = disapprovingly about it being "technically correct", except "has a = suspension point" is *definitely not* exactly how it worked before. > The changes described in the RFC refer to the algorithm for handling > I/O functions in blocking mode. And of course these words assume that > we haven=E2=80=99t lost our minds and understand that you cannot write > completely different message sequences to the same socket at the same > time. In practice, changes are of course sometimes necessary, but > throughout my entire experience working with coroutines, I should note > that I have never once run into the example you mentioned. Even when > adapting older projects. And do you know why? Because the first thing > we refactored in the old code was the places with shared variables. Well, but that's not what my example was doing. My example was taking a = set of (filename, content) pairs and writing them to individual files. = But it was doing it in an async-unsafe way (because that has never = before been a consideration), and so its data source can be corrupted = _while it is executing_. The async problems in my example might be glaringly obvious (for people = skilled in the art), but many other async issues are much more subtle, = such as Rob described in his follow-on email to mine. For people who = have never had the pleasure of working with async code before, "the = world changed out from under me" is not a scenario you're accustomed to = thinking about. > But in PHP, colored functions are inconvenient. Overloading I/O > functions does not lead to serious errors that make developers suffer; > on the contrary, it saves time and gives the language more > flexibility. Of course colored functions are inconvenient. But it's necessary or else = you open to a whole class of easily avoidable problems. _Those_ problems = are _much_ more inconvenient than colored functions. Code that was written to be synchronous should remain synchronous unless = it is explicitly modified to be asynchronous. > A developer should strive to minimize asynchronous code in a project. > The less of it there is, the better. Asynchronous code is evil. An > anti-pattern. A high-complexity zone. But if a developer chooses to > use asynchronous code, they shouldn=E2=80=99t act like they=E2=80=99re = three years old > and seeing a computer for the first time. Definitely not. This > technology requires steady, capable hands :) What this says to me is, "Here's a foot-gun. Please use it responsibly." Now, I definitely want to have advanced features available for when = they're needed. But that said, It would be great if we can avoid = introducing new foot-guns, especially when we have the knowledge and = experience from other languages to draw on and do better. And when we do = introduce new foot-guns, it's better if we can make them = strategically-targeted sniper rifles instead of blunderbusses. If we allow for hidden async behavior, the entire system becomes = impossible to reason about. Some library I'm using can cause an async = race condition without me asking for it, and I can't know it doesn't = unless I audit it and its interaction with my code.=20 And we know from practice that enough people won't use async responsibly = that it will make the language look bad. What will happen is a junior = dev will decide (or be told) that some code is performing poorly and = they will see a forum post that says "use coroutines" or "use async" and = they will cargo-cult their way to a hidden problem because they didn't = take into consideration the full problem space. Not to say that can't = happen with explicit suspensions, but the ceremony of declaring you have = a possible suspension at least gives a pointer of, "this is where = there's a suspension; what happens if it does?". -John