Hi

I've had the opportunity to take a look now.

Am 2025-11-16 00:11, schrieb Rowan Tommins [IMSoP]:
- The syntax for the two proposals is based on the current RFC text. If they are updated, e.g. to use different keywords, I will update the examples.

The block scoping RFC has been updated to `let()`.

- There are many scenarios which could be included, and many ways each example could be written. I have chosen scenarios to illustrate certain strengths and weaknesses, but tried to fairly represent a "good" use of each feature. However, I welcome feedback about unintentional bias in my choices.

1.

For db-transaction/implementation/1-raii-object.php I'd like to note that it is not necessary to proxy execute() through the transaction object. It could also be used as a simple guard object which only purpose is to be constructed and destructed.

    let ($txn = $db->begin()) {
        $db->execute('…');
    }

or possibly:

    let (
        $db = connect(),
        $txn = $db->begin(),
    ) { … }

In that way it is similar to the 2x-context-manager-anon-class.php example. The same “guard object” possibility also exists for the other examples as far as I can tell.

2.

The RAII object in 'file-handle' serves no purpose. PHP will already call `fclose()` when the resource itself goes out of scope, so this is existing behavior with extra steps. The same is true for the 0-linear-code example in file-object. You don't need the `fclose()` there.

3.

The docblock in locked-pdf/application/2-context-manager.php is incorrectly copy and pasted.

With that out of the way, here are my own initial thoughts from working through the examples:

- RAII + block scope is most convenient when protecting an existing object which can be edited or extended.

- When protecting a final object, or a native resource, RAII is harder to implement. In these cases, the separation of Context Manager from managed value is powerful.

- Context Managers are very concise for safely setting and resetting global state. RAII can achieve this, but feels less natural.

- An "inversion of control" approach (passing in a callback with the body of the protected block) requires capturing all variables *not* scoped to the block. Even with automatic by-value capture, those needed *after* the block would need to be listed for capture by reference.

- Building a Context Manager from a Generator can lead to very readable code in some cases, and closely mimics an "inversion of control" approach without the same variable capture problems.


I would be interested in other people's thoughts.

I was about to comment that the 'file' examples were not equivalent, because the context manager and IOC ones didn't include the error logging, until I noticed it was hidden away in the implementation. This probably suggests that I implicitly expected to see all relevant control flow. Exception handling and logging in particular probably greatly depend on the surrounding context to be useful (e.g. to adapt the log message or to enhance it with additional context data). So while it might superficially look cleaner / simpler, I feel that this kind of generic handling will bite you sooner or later. So with the context manager example, I would expect the “exception introspection” capability to be used to properly tear down the context, but not for cross-cutting concerns such as logging. I'm not sure if this would qualify as “unintentional bias”, but it's certainly something that affected by perception of the code.

Best regards
Tim Düsterhus

Reply via email to