Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129461 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 257A81A00BC for ; Wed, 26 Nov 2025 18:08:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1764180518; bh=WdaPSSAU1cQqFIFrAiymqT6iUwJg5YSLE9I7GEh96iY=; h=Date:From:To:In-Reply-To:References:Subject:From; b=fNv5VIot4qBRTUZeXxioY9nDK1KjSY928KbPU3PpqPNdbNS+6ZQD02fIWCbh9ef/c Rlv1tJJQnUdIAzSEsv1bNVDa1YDmig2w3QhMKzvS8Bo9Hws51YDQ0bPj7Jimify1Yl gM3fg7I5rQa1GBFtRUooyYF77Q36yBaSkHo+33GUmp0rUS5lg3NTnXpt7cWn51+6vF GZrhX1YCx2i7sPYtq/EMNm6u9o1zdrtYej2MnseiCgXiT7LpeMiOBvpguG5HvieYe1 IvyX/7hHrEBGHpFa5tVewRZpGBCviSo8/U8PCsOX18hNyKYCOaszGwEQeYcXXuxNxR cw9m4J+R8sKxg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 0D16B1801E3 for ; Wed, 26 Nov 2025 18:08:38 +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=-1.4 required=5.0 tests=BAYES_05,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,RCVD_IN_DNSWL_LOW, SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from fout-a2-smtp.messagingengine.com (fout-a2-smtp.messagingengine.com [103.168.172.145]) (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 ; Wed, 26 Nov 2025 18:08:37 +0000 (UTC) Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfout.phl.internal (Postfix) with ESMTP id 7A30FEC03B8 for ; Wed, 26 Nov 2025 13:08:32 -0500 (EST) Received: from phl-imap-01 ([10.202.2.91]) by phl-compute-04.internal (MEProxy); Wed, 26 Nov 2025 13:08:32 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to; s=fm3; t=1764180512; x=1764266912; bh=K/dxdBpnGV45fkp6Rz8WY 0OmoGyhNlQzPAiW2cxdrMs=; b=BG9Tukb654POZKiAJQ/xbWrjiepuYzjl4wS07 HfhrfrbpD8yBuH6cLPGugNDx5nvrkyuX/5DyE2MHYDKg3PBH9ppHqEPvbR0HIjxw WIMwWY8Uq9rjnEVXEQ44Y/AyoESw+2sKf9TxcPEDFBXrGuYqaInsIvKSDeDBkeOM gMWVrgh5VCQZQJgguitFtJf07vi7rwRuD/+T5nWOWqYdOEQAUzQ6c+el+NN+kUeN jX951YL6j5P94c6GbUu45RMNbw8LdLQLAsc4ZtsL9WZvp0ZEFC2Aods+JWQoEAzz US19ZelNGsj2DarGbcvJxjWT62Xs3pr+JJndrU0EYRLKab+Aw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1764180512; x=1764266912; bh=K /dxdBpnGV45fkp6Rz8WY0OmoGyhNlQzPAiW2cxdrMs=; b=vLcBljDAxQuf6NDSe LocQbNkp9gGs4z5RhHYHFG/GLUUJrvlM3mWNHq+3oTNESDWoCs/GwhZp3rYomd+C gFXtDocq2fu2JeRClVxh2N5LOVeQRaH8n0WkqBr/Vey/psmn35BI48aGh8Y2IxFi Vjx2jsDQpiAZ3WZ3Y/NO35Dg70kpKdd8UnbX/Off97K+MgH0r3vUWj/9dQT3hZRw zYnlKTc5KYQmItH6afFWt1qBxrQ4W8M0qk8bRc/8BhiKyXtZ20ncWlRV2DY2Se1E PCZ5w621BKXRZ0SiaKheh/klZvwcV+30R1LvM4lubZ1UYKH2jbkEwXWVBu84I0Cc ezwLw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggddvgeehtddvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepofggfffhvffkjghfufgtgfesthejredtredttdenucfhrhhomhepfdfnrghrrhih ucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhmqe enucggtffrrghtthgvrhhnpedugedvlefgueegheefjeetffduveeltefhfeegjeffffel gedttdevkeegkedugfenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrih hlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomhdpnhgspghrtghp thhtohepuddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepihhnthgvrhhnrghlsh eslhhishhtshdrphhhphdrnhgvth X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 2B24B18C004E; Wed, 26 Nov 2025 13:08:32 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: AQWJq8Gl4GWJ Date: Wed, 26 Nov 2025 12:08:11 -0600 To: "php internals" Message-ID: <5e39ba4d-8335-45c0-b2c2-a61d816a3206@app.fastmail.com> In-Reply-To: References: <26a2f13c-f318-4d6c-9595-bfaaebcbabcb@rwec.co.uk> <432ca4ad-7bcc-43bd-8e05-3121839b4ff7@app.fastmail.com> Subject: Re: [PHP-DEV] Examples comparing Block Scoped RAII and Context Managers Content-Type: text/plain Content-Transfer-Encoding: 7bit From: larry@garfieldtech.com ("Larry Garfield") On Wed, Nov 19, 2025, at 4:19 PM, Rowan Tommins [IMSoP] wrote: > On 18/11/2025 17:23, Larry Garfield wrote: >> One thing I definitely do not like is the need for a `FileWrapper` class in the RAII file-handle example. That seems like an unnecessary level of abstraction just to squeeze the `fclose()` value onto the file handle. The fully-separated Context Manager seems a more flexible approach. > > > Yes, exploring how exactly that flexibility could be used was part of > my motivation for the examples I picked. > > The downside is that it is slightly harder to understand at first > glance: someone reading "using (file_for_write('file.txt') as $fh)" > might well assume that $fh is the value returned from > "file_for_write('file.txt')", rather than the value returned from > "file_for_write('file.txt')->enterContext()". > > What made sense to me was comparing to an Iterator that only goes > around once - in "foreach (files_to_write_to() as $fh)", the > "files_to_write_to()" call doesn't return $fh either, > "files_to_write_to()->current()" does. That's a good analogy, I like it. >> I also noted that all of the examples wrap the context block (of whichever syntax) in a try-catch of its own. I don't know if that's going to be a common pattern or not. If so, might it suggest that the `using` block have its own built-in optional `catch` and `finally` for one-off additional handling? That could point toward the Java approach of merging this functionality into `try`, but I am concerned about the implications of making both `catch` and `finally` effectively optional on `try` blocks. I am open to discussion on this front. (Anyone know what the typical use cases are in Python?) > > > Looking at the parser, I realised that a "try" block with neither > "catch" nor "finally" actually matches the grammar; it is only rejected > by a specific check when compiling the AST to opcodes. Without that > check, it would just compile to some unnecessary jump table entries. > > > > I guess an alternative would be allowing any statement after the > using() rather than always a block, as in Seifeddine and Tim's > proposal, which allows you to stack like this: > > using ($db->transactionScope()) try { > // ... > } > catch ( SomeSpecificException $e ) { > // ... > } > > Or, the specific combination "try using( ... )" could be added to the > parser. (At the moment, "try" must always be followed by "{".) > > > > As I noted in one of the examples > (file-handle/application/1b-raii-with-scope-block.php), there is a > subtle difference in semantics between different nesting orders - with > "try using()", you can catch exceptions thrown by enterContext() and > exitContext(); with "using() try", you can catch exceptions before > exitContext() sees them and cleans up. > > It seems Java's try-with-resources is equivalent to "try using()": > >> In a try-with-resources statement, any catch or finally block is run after the resources declared have been closed. Thanks. I'll discuss these options with Arnaud. Anyone else want to weigh in here? >> Which is exactly the benefit of the separation of the Context Manager from the Context Variable. The CM can be written to rely on `unset()` closing the object (risk 2), or to handle closing it itself (risk 1), as the developer determines. > > > Something the examples I picked don't really showcase is that a Context > Manager doesn't need to be specialised to a particular task at all, it > can generically implement one of these strategies. > > The general pattern is this: > > class GeneralPurposeCM implements ContextManager { > public function __construct(private object $contextVar) {} > public function enterContext(): object { return $this->contextVar; } > public functoin exitContext(): void {} > } > > - On its own, that makes "using(new GeneralPurposeCM(new Something) as > $foo) { ... }" a very over-engineered version of "{ let $foo = new > Something; ... }" True! It may make sense eventually to provide a "UnsetThis(mixed $var)" CM in the stdlib. Not something to include now, but I've no issue with it existing eventually. > Incidentally, while checking I had the right method name in the above, > I noticed the Context Manager RFC has an example using "leaveContext" > instead, presumably an editing error. :) Indeed. Fixed now, thanks. --Larry Garfield