Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130479 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 5EA611A00BC for ; Sun, 29 Mar 2026 11:14:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1774782852; bh=MaFSTeTEYmajtJ+qOyX51Q/REkSQSWzukZCoWxZYN4g=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=SKgeLmdBNuqaVDa7vDDSVdjxbjiQUBHaQEgCqeePxV5gDYMRHt0JPEk7OIleizC60 lsZJov9y7/LKC5qo62obL627nWmsH4alH9WpfXH3SIrm2J+XinVaxLE7IGF6s4Ve/f Dx8adeSGQt74RphtnzsadW+Dna2xpL9KclhrjPXYw9riuApEGZxW+TWR8SQnHpE5XG fv0nF3aXGn6ECgIgpgUvq9V+1NpcvygyD2KU5Q51pe8V5B3wqk/EUmubdXsnSlWEIs hTXm7y7/mofJCXcDGU2QIpx+KpNhiXrqG0T6Qb1+L5HrtIgvKzAumyqNUk6Clc4Gsk faRTXt7tnVtjw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 97A0C180061 for ; Sun, 29 Mar 2026 11:14:11 +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_PASS,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from chrono.xqk7.com (chrono.xqk7.com [176.9.45.72]) (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 ; Sun, 29 Mar 2026 11:14:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bastelstu.be; s=mail20171119; t=1774782843; bh=M11AY4/1dv+0FbchdP2T7NE6lXlubw0zrX0xcX1Jjtc=; h=MIME-Version:Date:From:To:Cc:Subject:In-Reply-To:References: Message-ID:Content-Type:from:to:cc:subject:message-id; b=lan5mT9LFecAPUcqAdYHlisMnGkPCmINufE45QUWjn1wSF/xXiiSpRJiR3r5AGmUp Z5J6aFPgYgBT5h7MW0QmN077rxz1g4yotatUUd+y+MRVHUtg+57nINS/8iaIYh5pWf t2VgvrHtg0xY42brznR0DCbeCjMt6dbco8HHoIKOhve5kdvhvV2dn6n9eLgVXB4P2W +acIHiKNkAxHVoD/N2hLgx9RIuKI9yhaqC3oAk7SORQbL2tAQ3fk/8wumwpdSO0wpV w/OOk2BVWrZW+7rpe1lstnENGYTtpxNplKIhahILuHv3D8Znax8OLcZWLbND+/QXSs V6GTiS6Cs1rGQ== Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 Date: Sun, 29 Mar 2026 13:14:03 +0200 To: Larry Garfield Cc: php internals Subject: Re: [PHP-DEV] [RFC] Context Managers In-Reply-To: References: Message-ID: <5d96fca3ca5418e6e9e5d8871b26477f@bastelstu.be> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit From: tim@bastelstu.be (=?UTF-8?Q?Tim_D=C3=BCsterhus?=) Larry, Am 2026-03-22 19:19, schrieb Larry Garfield: > Arnaud and I have made a number of changes to the RFC that should make > it sleaker and more consistent. The notable ones (that impact > behavior) are as follows: “Sleaker” is not a word my dictionary understands. Was this a typo for “sleeker” in the sense of “refined”? > 1. We went back and forth on the `continue` question several times, > before coming to the conclusion that `continue` is a tool for looping > structures only. That `switch` also uses it is just `switch` being > silly because reasons, and there is no reason `using` must inherit its > weirdness. Therefore, `continue` inside a `using` block now means > nothing at all. `continue` will ignore it, the same way it ignores an > `if` statement. I fail to see how “making break; and continue; behave inconsistently” is making the RFC (and by extension) the language any more consistent. In this following example snippet it's not at all obvious that the `break` is behaving incorrectly by targeting the `using()` with `continue` targeting the `foreach()`, despite both using the same “number”: $processed = 0; foreach ($entries as $entry) { using ($db->transaction()) { switch ($entry['type']) { case 'EOF': break 2; default: if (should_skip($entry)) { continue 2; } $db->insert($entry); } } $processed++; } I'm also noticing that the RFC still does not explain *why* the decision for `break` to target `using()` has been made. For your reference, my last email asking that question is this one: https://news-web.php.net/php.internals/129771. I didn't receive a reply to that email either (and neither do the list archives have a reply). > 2. Several people (including us) were uncomfortable with using a > boolean return from the exitContext() method. While that is what > Python does, it is indeed not self-evident how it works. (Should true > mean "true, I'm done" or "true, rethrow"?) We debated using an enum > value, but that appeared to be too verbose. > > Instead, we decided that exitContext() should return ?Throwable, which > is the same thing it is passed. In a success case, it is passed null. > In a failure case, it is passed a throwable. So it can then return > null (meaning "we're done, nothing else to do here") or a throwable, > which will then get thrown. Since in most cases an error should be > allowed to propagate, it means simply calling `return $exception` at > the end of the method will "do the right thing" 95% of the time. > Simple and easy and self-documenting. (If there's a reason to wrap and > rethrow the exception, do that and return the new exception. Or to > swallow the exception and not propagate it, return null.) That sounds like a “throw” statement with extra steps [1]. While nothing stopped you from writing `throw new SomeException();` within `exitContext()` with the `bool` return value, it at least *encouraged* you to not replace the original Exception with another Exception entirely and to just make a decision between “suppress” or “not suppress”. Now `return` is completely equivalent to `throw` (at least as long as `exitContext()` doesn't contain a `catch()` itself) adding even more layers of “using() is magically including behavior of other language constructs” that will be hard to reason about for humans and machines alike. Best regards Tim Düsterhus [1] function raise(\Throwable $e): ContextManager { return new class ($e) implements ContextManager { public function __construct(private \Throwable $e) { } public function enterContext(): mixed { } public function exitContext(?\Throwable $e = null): ?Throwable { return $this->e; } }; } using(raise(new \Exception())) { }