On Thu, 7 May 2026 at 19:03 Rowan Tommins [IMSoP] <[email protected]>
wrote:

> On 07/05/2026 13:16, Bob Weinand wrote:
> > I am not opposed at all to such a consistent macro system though.
> > ... but I would not make a transaction like that a macro. For inlining
> variables in a html or sql snippet with proper escaping, definitely great.
> > To me, macros should meaningfully transform their contained code rather
> than wrapping a bit of logic around, which would be covered by this RFC.
> > It's complimentary, not a replacement.
>
>
> Thinking about this further, I agree that full-blooded macros would be
> overkill for this case, but my starting point was that closures don't
> feel like the right solution either - they're a different feature being
> bent into shape.
>
> So rather than starting with a Closure, and taking things away, I was
> trying to think of ways to start with a simple block of code, and build
> it up.
>
>
> For instance, the array_walk example in the RFC is just an ugly (and
> probably inefficient) way of writing a foreach loop:
>
> array_walk($numbers, fn($number) {
>      $count = bcadd($count, '1');
>      $sum = bcadd($sum, $number);
> });
>
> foreach($numbers as $number) {
>      $count = bcadd($count, '1');
>      $sum = bcadd($sum, $number);
> }
>
> So, what would it look like to generalise that, so we could do the same
> for other scenarios, like async() and transaction()?
>
>
> A simple first step would be something that could take a block of code,
> and say when to execute it:
>
> custom_block transaction($dbConnection) {
>      try {
>          $dbConnection->beginTransaction();
>          __execute_block_body();
>      }
>      catch (\Throwable $e) {
>          $dbConnection->rollbackTransaction();
>          throw $e;
>       }
>       $dbConnection->commitTransaction();
> }
>
> transaction($myDb) {
>      $myDb->query('UPDATE ...');
> }
>
> If the block body is never represented as a variable, there's no need to
> define what happens when it outlives scope, or the user tries to clone
> it, rebind it, etc.
>
> And if the calling code doesn't look like it's creating a Closure, users
> won't have any wrong expectations about variable scopes or lifetimes.
>
>
> Onto that, we can add syntax to push values into the block, e.g. using
> the "as" keyword like in "foreach" (example based on the "Generator
> decorator managers" section at the end of the Context Managers RFC):
>
> custom_block opening($filename) {
>      $f = fopen($filename, "r");
>      if (!$f) {
>          throw new Exception("fopen($filename) failed");
>      }
>      try {
>          __execute_block_body($f);
>      } finally {
>          fclose($f);
>      }
> }
>
> opening(__FILE__ as $f) {
>      var_dump($f);
> }
>
>
> And some way to pull values out, e.g. a "break with" keyword:
>
> custom_block transaction(DBConnection $conn) {
>    $conn->beginTran();
>    try {
>      if (__execute_block_body() === DBConnection::TRANSACTION_ABORT) {
>        $conn->rollbackTran();
>        return;
>      }
>    } catch (\Throwable $e) {
>      $conn->rollback();
>      throw $e;
>    }
>    $conn->commitTran();
> }
>
> transaction($connection) {
>      $affectedRows = $connection->query("UPDATE ...");
>      if ($affectedRows === 0) {
>          break with DBConnection::TRANSACTION_ABORT;
>      }
>      // ...
> }



That looks like a function (aka closure) with a lot of weird extra steps.
It’s been years, several proposals and multiple demonstrations on how arrow
function syntax can be expanded to be useful with multi-statements. So much
gymnastics goes on to deny such a simple and elegant syntax.

>

Reply via email to