Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129647 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 0933A1A00BC for ; Thu, 18 Dec 2025 00:18:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1766017088; bh=Q9lE2da8k27OPkFReErCEgNcX9ayYY+4jlcAlBX7uQY=; h=Date:Subject:To:References:From:In-Reply-To:From; b=DHMXcSM4CAt18wpnI4LkyOYa+KiR1tHemiDcwmdQFNoj3ai8/fvMlWrcMBQEALEZk kRyVvCfyAilUxakhQdboEbzzlr4eFT0d15AS5+xazWV0/bgJgYcBJfoIUDRL7QmImj /XGW+WFTsDhVCTa8+zx/Cf9o/Je6C1YarW68jAcA7DuSg9BrwB6PtwaWO6IkenR6TN Azj/x/Rx9el/3ptLBOsB2WTDfQ1spBBpAvAUYcvfopd2LqCtJSQcBidS1r0BSVIcN9 0K9JJqnULdryL7Bvt7YjM7jncVO40xdrWoSRF4oM3V24nKxVojWhRrf06Grjj+lw5I tqJF45FgL5wRg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 592881801D4 for ; Thu, 18 Dec 2025 00:18: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_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 ; Thu, 18 Dec 2025 00:18:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bastelstu.be; s=mail20171119; t=1766017080; bh=cL85X91Mk+0VS0BWPMuaVLVj+9Xien8DiRpCVZ1dD68=; h=Message-ID:Date:MIME-Version:Subject:To:References:From: In-Reply-To:Content-Type:from:to:cc:subject:message-id; b=P0WNH5rMqH6m4Y47z8PIjSLU/cMBovoiKotsvT/Jc5yyH3Hpl78MduNZvcTUtnaxC xqQIIbowlVmPn6NwBPUXzxO/pWsVr0SC85d8RucgOYwkJQV0Y2dQFhAo7/4I4DoZdZ phQdylOlVkmmeU4n2RYGLYlRp8qe04sXDxzBIn3/S76UNG6yFzJkOxZbWhcRXyFtuL 2K3VIsx53Ki7FB18j2dwK2aN90bDTRpg2hga9Si7HY3vMbDHyF/kiUqM95eAkGShtN Jr4MwGQjGrP0QLV0SOUiv8WWEF32611EMw1E0/LqDuDFs2NjuptuWKLenYLA0mdykh lVU9MRtitANWA== Message-ID: <954a2c05-af46-4df0-bc42-fc14a80dae51@bastelstu.be> Date: Thu, 18 Dec 2025 01:17:55 +0100 Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 Subject: Re: [PHP-DEV] Examples comparing Block Scoped RAII and Context Managers To: "Rowan Tommins [IMSoP]" , internals@lists.php.net References: <26a2f13c-f318-4d6c-9595-bfaaebcbabcb@rwec.co.uk> <78bfa50ad7c5111a1c6caaff3a525255@bastelstu.be> <52165B35-D495-40C8-97B3-9684ED30F220@rwec.co.uk> Content-Language: en-US In-Reply-To: <52165B35-D495-40C8-97B3-9684ED30F220@rwec.co.uk> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit From: tim@bastelstu.be (=?UTF-8?Q?Tim_D=C3=BCsterhus?=) Hi On 12/18/25 00:04, Rowan Tommins [IMSoP] wrote: > 5) Wait, does that mean this is just a sequence of declaration statements in disguise? Yes. let ($foo, $bar) { … } is equivalent to let ($foo) { let($bar) { … } } And by extension let ($scoped, $scoped) { … } is equivalent to let ($scoped) { let ($scoped) { … } } In the example the outer `$scoped` will then effectively be shadowed by the inner `$scoped`, preventing it from being overwritten inside the block. The initializer behaves like regular assignments that PHP users are already familiar with, just with the extra feature that the old value will be backed up and then restored after the associated statement (list) finishes. The (effective) desugaring is showcased in the Proposal section of the RFC and the first example in the “Examples” section also showcase all possible situations. I have just updated the RFC to write this out more explicitly: https://wiki.php.net/rfc/optin_block_scoping?do=diff&rev2%5B0%5D=1765892090&rev2%5B1%5D=1766015568&difftype=sidebyside > If you can do that, presumably you can do this: > > let( > $foo = bar($baz), // What is $baz referring to? Particularly if it is a by-reference out parameter. > $baz = 1, > ) > > Which is a direct translation of an example you gave here: The `$baz` in `bar($baz)` is referring to whatever value `$baz` has at that point in time. > Thinking about it, even the dynamic coding features of PHP you say would be so difficult aren't automatically prohibited: I assume you are referring to this email here: https://news-web.php.net/php.internals/129641? I was specifically mentioning the dynamic coding features as problematic in combination with a possible “temporal dead zone”. Since the `let()` construct requires all variables to be declared at the start of the block in a dedicated section there is no (or less) issue of there being multiple equally-valid interpretations for the behavior of variables that are declared “halfway through” a block: 1. The “temporal dead zone” is not something that can exist. 2. And users do not need to wonder if declarations are hoisted. For the example in the email you linked, I am including it here once more (with an additional $baz = 2 assignment at the start): $baz = 2; { let $foo = bar($baz); let $baz = 1; } 1. If there is a temporal dead zone, the call `bar($baz)` is invalid (throws an Error). 2. If declarations are hoisted, the call to `bar($baz)` could be (1) an access to an undefined variable (if it behaves as if there was an `unset($baz)`, which would be behavior that is technically different from the TDZ). It could also be a valid access to a variable containing `null` (if all variables are initialized to `null`). *Theoretically* it could also be `1`, if only constant expressions are legal and the initializer is also hoisted. 3. If the lifetime of the block-scoped `$baz` only starts at the point of declaration - effectively an invisible nested block - it behaves as if it was `bar(2)`, since the current value of `$baz` is `2`. To me the syntax of the `let()` construct very strongly suggests (3) and when there is only one variable declared (or one knows the desugaring of let($foo, bar) == let($foo) let($bar)) there is no other possible interpretation. This is what I meant by “there is a less rigid relationship between the individual statements” in the previous email. Note that it also said “Forcing all the declarations into a single statement would resolve that ambiguity […]”, since that would be isomorphic to the `let()` construct if the declaration is forced to be at the top of the block. Best regards Tim Düsterhus