Erik van Velzen wrote on 28/10/2015 15:02:
The ScopeGuard's destructor can now detect the condition:

if ( $this->success_registered ) {
    // Function reached checkpoint for this scope
    $this->callSuccessHandlers();
} else {
    // Function aborted early, due to a throw or early return
    $this->callExitHandlers();
}
$this->callExitHandlers();


No boilerplate throw-catch needed, works even if there is already a catch or
finally within the function's definition.

In fact, I kind of want to use this somewhere now... ;)

On the downside, it's worth noting that while PHP destructors are technically deterministic, the language can actually prevent them running on scope exit, because Exceptions hold references to everything used as a parameter in their stack traces.

In the below very simple example, both err() and foo() have completed, but the destructor fires only once the Exception is caught and discarded. So if you passed your ScopeGuard object around at all, you might find things executing in a surprising order.

(Personally, I think this is bad behaviour, and have argued that Exceptions should not capture these references, but I haven't been able to convince anyone it's worth changing.)


# https://3v4l.org/Kc9Ck
class KillMe {
    public function __destruct() {
        echo 'Thank you!';
    }
}

function err($ignored) {
    throw new Exception;
}

function foo() {
    $k = new KillMe;
    err($k);
}

try {
    foo();
}
catch ( Exception $e ) {
    echo 'Handling error. Destructor has not yet fired. ';
}

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to