Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129791 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 9E4AA1A00BC for ; Mon, 19 Jan 2026 18:10:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1768846263; bh=slQlJAElxYN9CNj/peN6enTJbwT1Sq4P531Ko82IVco=; h=Date:Subject:To:References:From:In-Reply-To:From; b=jgR2To1oSmzSiG6mA01a6xN4V259hr5YuLwVDAMhzmHarxr4ZXTTrY1UsKYEUvHCE Pu2LV2CCU6bV1jn0D9CXjQdlPNQMVWgBMj3lCQwQ4lM2GGdMa0/hoVSbFKyI9SIqFi d5Gi1z2MEVaaNdaBu6lV070yaj1b7ZKf8ABOYKiqxDoqPu/CsiWMw436CR/b9A9F4d IdSXFiMReyhlYSQaG1sisXwyv3RTqAxdstPxB+JsiZC6LtvRHC9TV/5Tq+Ltq0Hrtg nx9Abe9uDefg7h9UyBWoaKFuz0uvlBpNgyB0WIQWBMzarfBrZ/ONRHS+57aO2SUmPH sBt5cFvK2qUwA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 397E0180084 for ; Mon, 19 Jan 2026 18:11:02 +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.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-a1-smtp.messagingengine.com (fhigh-a1-smtp.messagingengine.com [103.168.172.152]) (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 ; Mon, 19 Jan 2026 18:10:51 +0000 (UTC) Received: from phl-compute-03.internal (phl-compute-03.internal [10.202.2.43]) by mailfhigh.phl.internal (Postfix) with ESMTP id 30B9114007B3 for ; Mon, 19 Jan 2026 13:10:46 -0500 (EST) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-03.internal (MEProxy); Mon, 19 Jan 2026 13:10:46 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rwec.co.uk; h=cc :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=fm2; t=1768846246; x=1768932646; bh=RQXt6B0vpS x51IoNjnGvOoUyf2z/KPG0eP65L+1L+mE=; b=vSqXx7a61PK3HiJA1Di42DBXZB aNHpC+d7mbUO1N8UOQ5j98DcRnuTMgROPTFlde/mjA6wpqwKr0zRyyLge7Q19gcE TR9EnwcOKCmeCXQTSSUpCa2d2GX3MKjsBUfhBoreOcXnDieCUkPwC+U/T8WtIEM8 WK6jgch1Pb1J8Q817CVJpLmZMXUvqnXaEj48TMzt4pQh9TsqFjJR1whu57pi+q1r QB2v3fyKsigur2sNETbOXYkTgcow2WdiT1jBczZm9k4SGh7/T3TRPAUshvNCM7Kx rlAyuEjidgkURlTDNBQE7eCqfZjkoK0YrFMc1fw4C1bM+mfg6lNusxm2VTqw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc: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=fm2; t= 1768846246; x=1768932646; bh=RQXt6B0vpSx51IoNjnGvOoUyf2z/KPG0eP6 5L+1L+mE=; b=QT3jORZpfCKTsyjmTn/MFa+aGsRCeKm8z3rpHAo4vpuix17EDmO OJI6pKWUR16H1j4eHyAw4yOsKYs12DkT6rn2p5ahROb98PlVIznNRrHZpeS6lc2U cNyZaJd96TYGLw5ZhzryxKZT7YvtAo2GuXu+9WkdIGcXijFtArFO/hVMkDlvAnRI O5revc26OlP2I3Mk4sCWvCqWvuI//QJWjrIzLUR1TaSD6u9RTOipzfScw8sbtPr6 FNhZRBPDBiGQqELhsma/AbsMoqLzRGRpLOw4QT+tggYzrC27vup1V1jwmp5fIFub +liFxTLgcB4Sxv5TGcQ8TFwiU77zMb7h63Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddufeekvdegucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucenucfjughrpegtkfffgggfuffvfhfhjgesrgdtreertd dvjeenucfhrhhomhepfdftohifrghnucfvohhmmhhinhhsucglkffoufhorfgnfdcuoehi mhhsohhprdhphhhpsehrfigvtgdrtghordhukheqnecuggftrfgrthhtvghrnhepheetle eiiefgueduieeuieffvdevheduueefkeejuefgffeftdeitdegtedtleetnecuvehluhhs thgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepihhmshhophdrphhhph esrhifvggtrdgtohdruhhkpdhnsggprhgtphhtthhopedupdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: id5114917:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA for ; Mon, 19 Jan 2026 13:10:45 -0500 (EST) Content-Type: multipart/alternative; boundary="------------lcL0HfyFzmPucVqfPopI8D9Q" Message-ID: <44015fee-b20c-4018-8b77-49955aeb4c31@rwec.co.uk> Date: Mon, 19 Jan 2026 18:10:43 +0000 Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PHP-DEV] [RFC] Context Managers To: internals@lists.php.net References: Content-Language: en-GB In-Reply-To: From: imsop.php@rwec.co.uk ("Rowan Tommins [IMSoP]") This is a multi-part message in MIME format. --------------lcL0HfyFzmPucVqfPopI8D9Q Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit On 19/01/2026 15:58, Larry Garfield wrote: > In an ideal world, if we had auto-capturing long-closures, then I would agree this is largely unnecessary and could instead be implemented like so (to reuse the examples from the RFC): > > $conn->inTransaction(function () { > // SQL stuff. > }); > > ... > > If we had auto-capturing closures, I would probably argue that is a better approach. I haven't caught up with the discussion fully, but I want to pick up on this specifically, because I disagree. Inversion of control like this would only be suitable in the general case if we had auto-capture *by reference*. I believe every proposal so far has limited automatic capture to *values only*. Auto-capture by value helps you get values *into* the closure, but does not help get anything backĀ *out*. So, if the code you want to sugar looks like this: ``` try{ $db->beginTransaction(); // ... $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId'); $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId'); // ... $db->commitTransaction(); } finally{ if( $db->isInTransaction()) { $db->rollbackTransaction(); } } // use $newFooId and $newBarId here ``` Then your options with a capture-by-value closure are either a) list the outputs as manual by-ref captures: ``` $newFooId = $newBarId = null; $db->inTransaction(fn() use (&$newFooId, &$newBarId) { // ... $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId'); $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId'); // ... }); // use $newFooId and $newBarId here ``` or b) return the outputs, and extract them using array destructuring or similar: ``` [$newFooId, $newBarId] = $db->inTransaction(fn() { // ... $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId'); $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId'); // ... return [$newFooId, $newBarId]; });// use $newFooId and $newBarId here ``` A Context Manager - or any other syntax based on a code block rather than a full stack frame - instead gives you direct access to the local variables: ``` using($db->transaction()) { // ... $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId'); $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId'); // ... }// use $newFooId and $newBarId here ``` Even if we had automatic capture by value, I think Context Managers would be a useful proposal to discuss. -- Rowan Tommins [IMSoP] --------------lcL0HfyFzmPucVqfPopI8D9Q Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit
On 19/01/2026 15:58, Larry Garfield wrote:
In an ideal world, if we had auto-capturing long-closures, then I would agree this is largely unnecessary and could instead be implemented like so (to reuse the examples from the RFC):

$conn->inTransaction(function () {
  // SQL stuff.
});

...

If we had auto-capturing closures, I would probably argue that is a better approach.


I haven't caught up with the discussion fully, but I want to pick up on this specifically, because I disagree.

Inversion of control like this would only be suitable in the general case if we had auto-capture *by reference*. I believe every proposal so far has limited automatic capture to *values only*.

Auto-capture by value helps you get values *into* the closure, but does not help get anything backĀ *out*.

So, if the code you want to sugar looks like this:

```
try {
    $db->beginTransaction();
    // ...
    $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId');
    $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId');
    // ...
    $db->commitTransaction();
}
finally {
    if ( $db->isInTransaction() ) {
        $db->rollbackTransaction();
    }
}
// use $newFooId and $newBarId here
```


Then your options with a capture-by-value closure are either

a) list the outputs as manual by-ref captures:

```
$newFooId = $newBarId = null;
$db->inTransaction(fn() use (&$newFooId, &$newBarId) {
    // ...
    $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId');
    $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId');
    // ...
});
// use $newFooId and $newBarId here
```


or b) return the outputs, and extract them using array destructuring or similar:

```
[$newFooId, $newBarId] = $db->inTransaction(fn() {
    // ...
    $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId');
    $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId');
    // ...
    return [$newFooId, $newBarId];
});
// use $newFooId and $newBarId here
```


A Context Manager - or any other syntax based on a code block rather than a full stack frame - instead gives you direct access to the local variables:

```
using($db->transaction()) {
    // ...
    $newFooId = $db->execute('INSERT INTO Foo ... RETURNING FooId');
    $newBarId = $db->execute('INSERT INTO Foo ... RETURNING BarId');
    // ...
}
// use $newFooId and $newBarId here
```


Even if we had automatic capture by value, I think Context Managers would be a useful proposal to discuss.


-- 
Rowan Tommins
[IMSoP]
--------------lcL0HfyFzmPucVqfPopI8D9Q--