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

Reply via email to