Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129271 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 737231A00BC for ; Sun, 16 Nov 2025 15:29:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1763306984; bh=DmHyGlr8kVrcarpmHzqSXJ6WFBu2bHeIRViB5R/PsJI=; h=Date:From:Subject:To:From; b=dBDZ7guacZ/Wbib7XmxtucvLcmMy/EcsvAbmFGpKz23U3ajQTrzpzLADrMAakMe0s w8ol1jUQmLPzjy04vAVun4cUSzKX3BtS/B6WC5Bjima3L5RKtKy8bkS6fQDwUBXpWP AEBSh7C5Cg23FYgTzbZatHfoHp2EE8njWgMvJt9ScP5RRXodcbxCZyvOLD0QIVCvyX sEdroCO7HTkAIzrENLqDp1X5qdJIDEpcZ2SF6hU1oiLeuKR9V0SBRv+h0kEpnvoXZc Bk1UmNDUqaYTBmmGVsJxupyW5NuoJQm4xE1C36DeQvfuGGNR0rSDm74HDz0/vkLTRF BQNry2pKvXVGA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 65D2D18033A for ; Sun, 16 Nov 2025 15:29:43 +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.2 required=5.0 tests=BAYES_40,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 mta3.mail.genkgo.net (mta3.mail.genkgo.net [2.58.165.21]) (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, 16 Nov 2025 15:29:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=genkgo.nl; s=ge-k4; h=Content-Transfer-Encoding:Content-Type:To:Subject:From: MIME-Version:Date:Message-ID:Sender:Reply-To:Cc:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=rL3XnQ+09Pns1sRqHKG7fMlEeGyARU+28j/an08CZ4I=; b=TECZoT0bjq7sZSc+Bhit0gkkVR k2jM3pvRjU01ot7Dnq5YpXlL8zHWDRJiePthQTXhqpbOC4imZqNINLf6ZoMhnTr7AT6FCoHKUzZf+ TlM+QPXcDsQUoGXE6OmySqGi3Fd5++JCY/jrBGlQgYTWXwd3qba61DfVbumQYCn6LmnrmlqmXb5Hj RAxxV94bFpSSo6IyD+8sF5y5JiIxViasQ0/ovQ+F0FwVJCpvFJ/rz/jnZhulMnNWZhMqQmX2uO1M1 842qhWhFBs5FXdtLYGN/dARipq08C8jT0PRmm9mzajE8YUtSTHqoA8FzKkqvIJqz2h37fKmAjlRHC trz/jfyw==; Received: from 62-131-46-46.fixed.kpn.net ([62.131.46.46] helo=[192.168.2.13]) by mta3.mail.genkgo.net with esmtpsa (TLS1.3) tls TLS_AES_128_GCM_SHA256 (Exim 4.97.1) (envelope-from ) id 1vKeh7-00000000dLx-0j9d for internals@lists.php.net; Sun, 16 Nov 2025 15:29:37 +0000 Message-ID: <93ce222c-a497-4e9f-86fc-a96f22fcf947@genkgo.nl> Date: Sun, 16 Nov 2025 16:29:35 +0100 Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: [PHP-DEV] Re: Examples comparing Block Scoped RAII and Context Managers To: internals@lists.php.net Content-Language: en-US, nl Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit From: f.bosch@genkgo.nl (Frederik Bosch) On Sat, 15 Nov 2025 23:11:44 +0000, Rowan Tommins [IMSoP] wrote: > Hi all, > > The Block Scoping RFC and the Context Manager RFC cover a lot of similar > use cases, and a lot of the discussion on both threads has been > explicitly comparing them. > > To try to picture better how they compare, I have put together a set of > examples that implement the same code using both features, as well as > some other variations, in this git repo: > > https://gitlab.com/imsop/raii-vs-cm > > A few notes: > > - The syntax for the two proposals is based on the current RFC text. If > they are updated, e.g. to use different keywords, I will update the > examples. > > - I have included examples with closures which automatically capture by > value, since a lot of the same use cases come up when discussing those. > > - There are many scenarios which could be included, and many ways each > example could be written. I have chosen scenarios to illustrate certain > strengths and weaknesses, but tried to fairly represent a "good" use of > each feature. However, I welcome feedback about unintentional bias in my > choices. > > - Corrections and additional examples are welcome as Merge Requests to > the repo, or replies here. > > > With that out of the way, here are my own initial thoughts from working > through the examples: > > - RAII + block scope is most convenient when protecting an existing > object which can be edited or extended. > > - When protecting a final object, or a native resource, RAII is harder > to implement. In these cases, the separation of Context Manager from > managed value is powerful. > > - Context Managers are very concise for safely setting and resetting > global state. RAII can achieve this, but feels less natural. > > - An "inversion of control" approach (passing in a callback with the > body of the protected block) requires capturing all variables *not* > scoped to the block. Even with automatic by-value capture, those needed > *after* the block would need to be listed for capture by reference. > > - Building a Context Manager from a Generator can lead to very readable > code in some cases, and closely mimics an "inversion of control" > approach without the same variable capture problems. > > > I would be interested in other people's thoughts. > > Regards, > > -- > Rowan Tommins > [IMSoP] Another suggestion would be to follow the Java try-with-resources syntax. It does not require a new keyword to be introduced, as with the Context Manager syntax. Moreover, it aligns with current try-catch-finally usage already implemented by PHP developers. try ($transaction = $db->newTransaction()) {     $db->execute('UPDATE tbl SET cell = :cell', ['cell'=>'value']); } Any object that implements TryWithContext can be used with such syntax. The function returns the exit context operation as callback. interface TryWithContext {    public function tryWith(): \Closure; } For a transaction it might look like this. Rather auto-capture I'd suggest explicit complete scope capture, by using the use keyword without parenthesis. class Transaction implements TryWithContext {     public function tryWith(): \Closure     {         $this->db->beginTransaction();         return function (?\Throwable $e = null) use {             if ($e) {                 $this->db->rollbackTransaction();                 return;             }             $this->db->commitTransaction();         };     } }