Re: [RFC] Context Managers

From: Date: Thu, 02 Apr 2026 10:13:32 +0000
Subject: Re: [RFC] Context Managers
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-130530@lists.php.net to get a copy of this message
Hi Am 2026-03-30 20:48, schrieb Larry Garfield:
“Sleaker” is not a word my dictionary understands. Was this a typo for “sleeker” in the sense of “refined”?
Yes, typo. Sleeker in the sense of "fewer bumpy parts on it."
Okay. I think that updated semantics failed in that goal and instead added additional bumpy parts.
1. We went back and forth on the continue question several times, before coming to the conclusion that continue is a tool for looping structures only. That switch also uses it is just switch being silly because reasons, and there is no reason using must inherit its weirdness. Therefore, continue inside a using block now means nothing at all. continue will ignore it, the same way it ignores an if statement.
I fail to see how “making break; and continue; behave inconsistently” is making the RFC (and by extension) the language any more consistent. In this following example snippet it's not at all obvious that the break is behaving incorrectly by targeting the using() with continue targeting the foreach(), despite both using the same “number”:
     $processed = 0;
     foreach ($entries as $entry) {
         using ($db->transaction()) {
             switch ($entry['type']) {
             case 'EOF':
                 break 2;
             default:
                 if (should_skip($entry)) {
                     continue 2;
                 }
                 $db->insert($entry);
             }
         }
         $processed++;
     }
I'm also noticing that the RFC still does not explain *why* the decision for break to target using() has been made. For your reference, my last email asking that question is this one: https://news-web.php.net/php.internals/129771. I didn't receive a reply to that email either (and neither do the list archives have a reply).
I'm pretty sure I did explain in this thread somewhere... In short, we want a way to be able to terminate the using block early in a success case. An error case is easy (throw), but for a success case we cannot use return, as that will return from the function.
That is a self-referential argument - you made the decision, because you wanted to make the decision. I was looking for an explanation why context managers are sufficiently special that they *need* support for exiting their associated block early *and* why existing control structures are insufficient to handle that. try for example does not support exiting the block early and given that the primary semantics of context managers are that of a try-catch-finally, it is reasonable to ask what makes context managers different. I also note that none of the existing examples in the RFC make use of break, this capability only gets a passing mention. Please provide a use case.
Technically "goto and your own label" would work, but I really hope we don't need to get into a discussion about why making goto the only way to solve something is a bad idea...
No, please elaborate.
break is the natural keyword for that, as it already means "stop this control structure and go to the end of it."
Quoting my the previous email that I linked in the email you were replying to:
“break does a different thing here than it does in if, else, try, catch, finally, namespace, and declare” doesn't seem like a straightforward approach to me.
-
continue means "stop this iteration of a control structure and go to the next one." But in this case, there is no next one. switch makes it an alias for break, for whatever reason lost to history, but given that it now throws a warning that seems to now be considered a mistake, so we don't see a reason to propagate that mistake.
I think Rowan explained that well in his reply.
If you have an alternate suggestion for how to achieve this functionality, now is the time to propose it.
As implied by my email, I believe that throwing exceptions should be the job of the throw keyword, not the job of the return keyword. Otherwise users are going to wonder what makes `return new SomeException(); different from throw new SomeException()` in that case. Best regards Tim Düsterhus

« previous php.internals (#130530) next »