Re: [RFC] Context Managers

From: Date: Thu, 15 Jan 2026 18:38:46 +0000
Subject: Re: [RFC] Context Managers
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-129761@lists.php.net to get a copy of this message
On Tue, Nov 4, 2025 at 9:19 PM Larry Garfield <larry@garfieldtech.com> wrote: > > Arnaud and I would like to present another RFC for consideration: Context Managers. > > https://wiki.php.net/rfc/context-managers > > You'll probably note that is very similar to the recent proposal from Tim and Seifeddine. > Both proposals grew out of casual discussion several months ago; I don't believe either team > was aware that the other was also actively working on such a proposal, so we now have two. > C'est la vie. :-) > > Naturally, Arnaud and I feel that our approach is the better one. In particular, as Arnaud > noted in an earlier reply, __destruct() is unreliable if timing matters. It also does not allow > differentiating between a success or failure exit condition, which for many use cases is absolutely > mandatory (as shown in the examples in the context manager RFC). > > The Context Manager proposal is a near direct port of Python's approach, which is > generally very well thought-out. However, there are a few open questions as listed in the RFC that > we are seeking feedback on. > > Discuss. :-) > > -- > Larry Garfield > larry@garfieldtech.com > Hi Larry, Hi Internals, Last year I promised you (Larry) some feedback on-list as well and didn't get around to it until now. I recognize the strain that repeating arguments has on a discussion like this, and this topic has already taken up a lot of focus and time for the folks here. But I wanted to at least explain why I think PHP would be better off without having this in core and why I think it would be a net negative for PHP to have this. So to summarize, I find the feature doesn't fit in PHP. It's introducing more magically called methods, burdened with unnecessary complexity, while being very limited in its potential (sensible) uses. Combined with its class-only high-verbosity approach, I feel this is lacking places where it would improve PHP code in general and better suited for a library for people that want this type of, what I consider, magical indirection. With the name also being extremely generic and non-descriptive, this all feels like bloat to me that complicates the language for no tangible benefits. To expand a bit on the points: - Non-local behavior: Every using statement is a couple of function calls that are non-obvious in how they delegate to some __magic interface methods that are not supposed to (but very able to) be called explicitly. With the implicit catch and exitContext() ability to return true/false; to rethrow/suppress an exception, adding even more hidden branching to execution. - Variable masking: A new block masking and restoring the context variables but not others is an additional source of errors and confusion that I feel doesn't pay off in terms of value vs. added complexity and error sources. It's not behavior we have anywhere else in PHP and breaks the flow of reading and reasoning about code in non-obvious ways. - Break/Continue semantics: There is no clear reason for me why this block scope should allow early returns. If the content is growing to a point where it's needed, a function is already a reasonable scope. Given that PHP allows for break 2;, something that we'll see more of then, it's manageable. It just adds to the, for me, unreasonable complexity of the feature. - Naming: For me, despite having worked with Python, the name means absolutely nothing. It doesn't even manage the context of the invocation. If anything, it manages when a resource is released into and removed and deallocated from a scoped context. And that sentence also is rough. PHP, for better or worse, doesn't burden its users with having to study many CS concepts beyond basic OO or procedural programming and still allows them to write obvious, valuable, and predictable code. I understand that with its evolution this has changed, and we have added a lot of redundancy (short arrays, short functions, pipes, etc..) to provide sugar that has steepened the learning curve for some. Adding very specific single-use concepts to the language with their own disconnected naming schemes, syntax, or, in this case, hidden behaviors should be carefully considered. And while I'm sure you did we came to different conclusions. - Block scoping: Personally, I don't see the need for block scoping in PHP in general. But having a generic solution that works without creating a new class for each case would feel like something that at least can be used by everyone and every part of the language. Tying this to custom objects doesn't feel like a language level feature but something that should be in a library. The worst option would be to allow using() to take a context manager or a plain expression and make people guess every time the statement is used if hidden function calls are attached to it. - Verbosity: Having to implement three code paths for each ContextManager (enter, exitWithoutError, exitWithError) within two functions, with a near mandatory if in a separate class, doesn't strike me as useful over patterns like getting and returning a connection out of a pool “manually.” The trade-off between this and already existing solutions to this problem with try/finally or construct/destruct isn't enticing. - Object lifecycle in PHP: Just to reiterate because it bugs me as PHP zval life cycles are used as an argument here: Reference counting in PHP is fully deterministic, and code like function () { $x = new Foo(); return; } will deterministically construct and destruct (at the end of the function as the variable gets cleaned up). Use cases where the GC would actually come into play are extremely rare from the real-world usages we can see in Python. I also haven't seen an example in PHP nor something in the RFC that looks overly convincing in improving this with managed in-function unsets. The error handling option is nice, but for maintainability, simplicity, and effort in writing code, I'd still prefer this to try/(catch)/finally Layering another level of lifecycle management on top of the existing PHP behavior doesn't feel like a simplification but rather like another source of complexity with this new niece special case. -- In summary, this feels like beyond what's necessary to get rid of a couple of try/finally blocks per application and encourages bad patterns like using ContextMangers for async instead of more modern APIs that have evolved since then. Kind Regards, Volker

« previous php.internals (#129761) next »