On Wed, 2015-10-28 at 16:02 +0100, Erik van Velzen wrote:
> I didn't see how it could be generalized but your example clears that up.

Quick attempt of a generalization:

abstract class AbstractRAIIGuard {
    private $succeeded = false;

    protected abstract function fail();

    protected function success() {}

    public function succeed() {
        if (!$this->succeeded) {
            throw new RAIIAlreadyMarkedAsSuccessfulException();
        }
        $this->success();
        $this->succeeded = true;
    }

    public function __destruct() {
        if (!$this->succeeded) {
            $this->fail();
        }
    }
}

class CallbackRAIIGuard extends AbstractRAIIGuard {
    private $success;
    private $fail;

    public __construct(callable $fail, callable $success = null) {
        $this->success = $success;
        $this->fail = $fail;
    }

    protected function fail() {
        call_user_func($this->fail());
    }

    public function success () {
        if ($this->success) {
            call_user_func_array($this->success, func_get_args());
        }
    }
}

class DBRAII extends AbstractRAII {
    private $db;
    public function __construct(DB $db) {
        $this->db = $db;
        $db->begin();
    }

    protected function fail() {
        $this->db->rollback();
    }

    public function success () {
        $this->db->commit();
    }
}

function foo(DB $db) {
    $guard = new DBRAII($db);

    // or using the more generic class

    $guard = new CallbackRAIIGuard(
        [$db, "rollback"], [$db, "commit"]
    );
    
    // ....

    $guard->succeed();
}

johannes

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to