Destructing PHP

Johannes Schlüter
johannes@php.net
@johannescode

function foo($db, $data) {
    $db->beginTransaction();

    foreach ($data as $row) {
        $db->insert($row);
    }

    $db->commit();
}

Exception Safety

Exception Safety

  1. No Exception Safety
  2. Basic Exception Safety (no-leak guarantee, might have side-effects)
  3. Strong Exception Safety (commit/rollback semantics, no side effects)
  4. No-throw Guarantee

(David Abrahams)

function foo($db, $data) {
    $db->beginTransaction();

    try {
        foreach ($data as $row) {
            $db->insert($row);
        }
    } catch(\Exception $e) {
        $db->rollback();
        throw $e;
    }
    $db->commit();
}
function runInTransaction($db, $cb) {
    $db->beginTransaction();
    try {
        $cb();
    } catch(\Exception $e) {
        $db->rollback();
        throw $e;
    }
    $db->commit();
}

function foo($db, $data) {
    runInTransaction($db, function () 
            use($db, $data) {
        foreach ($data as $row) {
            $db->insert($row);
        }
    });
}
function foo($db, $data) {
    $transaction = new Transaction($db);

    foreach ($data as $row) {
        $db->insert($row);
    }

    $transaction->commit();
}

Deterministic Destructors!

class Transaction {
    private $db;
    private $success = false;

    function __construct($db) {
        $this->db = $db;
        $db->begin();
    }
    function commit() {
        $this->db->commit();
        $this->success = true;
    }
    function __destruct() {
        if (!$this->success) {
            $this->db->rollback();
        }
    }
}

RAII

RAII

Resource Acquisition Is Initialization

YAY C++ \o/

Reference Counting

function foo() {
    $a = new A();
    $b = $a;
}
function a() {
    try {
        b();
    } catch (\Exception $e) {
        Logger::error($e);
    }
}

function b() {
    $o = new O();
    c();
}

function c() {
    throw new \Exception();
}

What else?

Ensure Usage of Return Value

echo expensiveCalculation(); // works



$a = expensiveCalculation();
unset($a); // will complain
class EnforceUsage {
    private $value;
    private $used = false;

    function __construct($value) {
        $this->value = $value;
    }
    function __toString() {
        $this->used = true;
        return (string)$this->value;
    }
    function __destruct() {
        if (!$this->used) {
            Logger::notice("Return value not used");
        }
    }
}

Useful? - Maybe ...

Short Rant

JAVA

A language built around non-deterministic Garbage Collection

finally

Java's initial solution

(no Java invention - at leat Object Pascal and Modula had finally before)

void foo(Database db, Object data) {
    boolean success = false;
    db.beginTransaction();

    try {
        db.insert(data);
        db.commit();
        success = true;
    } finally {
        if (!success) {
            db.rollback();
        }
    }
}

Java 7

introduced try-with-resources

http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

try (Transaction t =
           new Transaction(db) {
    db.insert();
    t.commit();
}

So what does PHP do?

Introduce finally

In PHP 5.5

Destructors Are Powerful!

Know Your Language!

Thank You

Johannes Schlüter

johannes@php.net

@johannescode

https://slides.com/johannes4321/froscon15