Hey Rowan,
On 6.11.2025 00:27:41, Rowan Tommins [IMSoP] wrote:
On 05/11/2025 22:38, Bob Weinand wrote:
I don't like that design, which effectively forces you to put safety
checks for all but the simplest cases onto the ContextManager
implementation.
And it forces the user to recognize "this returned object
DatabaseTranscation actually implements ContextManager, thus I should
put it into with() and not immediately call methods on it". (A
problem which the use() proposal from Tim does not have by design.)
I think you may have missed the key distinction between a "Context
Manager" (as designed by Python) and a "Disposable" (as used in C# and
others): the Context Manager is not the resource itself, it exists
only to meet the protocol/interface.
In this code:
with ( $dbConnection->transaction() as $handle ) {
$handle->execute('I am in the transaction');
}
$handle is *not* the value returned by $dbConnection->transaction(),
it's the value returned by $dbConnection->transaction()->enterContext().
One of the things that means is that if you just write
$foo=$dbConnection->transaction() you can't accidentally run any
methods on $foo, if all it has is enterContext and exitContext.
You are right, I missed that there's an extra layer of nesting inside this.
I think the DatabaseTransaction example put me on the wrong thought path
because it just returned the connection it came from instead of a
dedicated nested Transaction object. (The enterContext method in that
example ought to include a startTransaction call.)
However, I still think the proposed approach is dangerous with respect
to forgetting the exitContext() call. When using manual handling. But
yes, I agree, that's a much more manageable concern.
And the onus of handling duplicate enterContext() and multiple
exitContext() calls still lies on the implementer. The RFC does zero
effort at addressing this.
Thanks,
Bob