Hello all.
> It makes it very easy to not call the exitContext() method when calling
> enterContext() manually
Consider the code below:
```php
class FileContext {
private $handle;
public function __construct(private string $filename, private
string $mode) {}
public function __enter() {
$this->handle = fopen($this->filename, $this->mode);
return $this->handle;
}
public function __exit(?Throwable $e = null) {
if ($this->handle) {
fclose($this->handle);
}
}
}
$ctx = new FileContext('example.txt', 'w');
$f = $ctx->__enter();
try {
fwrite($f, "Hello world");
} finally {
$ctx->__exit();
}
```
Question: what is the probability of making a mistake in this code?
What is the likelihood that a programmer will forget to call enter and exit?
```php
...
with (new FileContext('example.txt', 'w')) as $f {
fwrite($f, "Hello world");
}
```
In this case, the probability of forgetting to call enter or exit is
zero, since the language now supports this paradigm at the syntax
level.
Question: what is the probability of accidentally calling a method
instead of not calling it?
```php
...
with (new FileContext('example.txt', 'w')) as $f {
$f->__enter(); // Error!
fwrite($f, "Hello world");
}
```
I believe that finding a clear mathematical proof in this case is impossible.
But if we look at studies on error statistics, it is the absence of a
call that is the most common problem.
(https://tomgu1991.github.io/assets/files/19compsac.pdf)
> Thus, we have a big pitfall, wherein APIs may expect enterContext() and
> exitContext()
Is it really a big pitfall? If so, then functions like `fopen` and
`fclose` should be removed from the language altogether,
because their existence is an even bigger pitfall.
> Ultimately you definitely will need the capability of calling enterContext()
> and exitContext() manually too (i.e. restricting that is not realistic either)
Of course, they can be restricted: make the methods private, so that
only PHP itself can call them, and they cannot be accidentally called
anywhere else outside the class.
But I don't see any convincing reasons for doing that.
> The proposed approach only allows nesting contexts, but not interleaving them.
Why does this need to be done at all?
I don't know what "interleaving contexts" means in practice.
But even if they do exist, that goes beyond the scope of the current proposal.
Nevertheless, it is worth noting that studying Python bugs for this
RFC is a good thing:
https://bugs.python.org/issue29988 - with statements are not ensuring
that __exit__ is called if __enter__ succeeds.
Also:
https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager
Total:
**Advantages of `with`:**
* better semantics than try–catch
* less control-flow code
It would be strange to demand that `with` be safer than the rest of PHP code.
That’s an odd requirement. Of course, if PHP were a compiled language,
many checks could be done at compile time.
But we have static analysis for that.
---
Best regards, Ed