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