I love RAII. Unfortunately, most popular enterprisey languages don’t support it. I’ve seen people claim that Java’s finally is essentially RAII, but that’s not quite right. I hate seeing try/catch/finally scattered throughout application code.

One thing I definitely haven’t seen is any mention of RAII in PHP. Nasty ugly weak PHP that’s fallen out of favor with the hip. I can’t possibly be the only persion to have thought about this, because one of the bugfixes in PHP 5.2 is properly ordered destructors. However, since most people aren’t developing for PHP 5.2, I suppose it’s not a surprise that the subject isn’t googleable. Anyhow, prior to PHP 5.2, objects in the same scope would be destructed in arbitrary scope (usually the order in which they were declared, which sounds backwards), so multiple resources acquired in one function couldn’t be interdependent without invoking undefined behavior. That’s bad, but it’s not a show-stopper.

Just because I’m bored, here’s an example I’ve whipped up for you. It attempts an HTTP connection to your local host. If the connection succeeds, both the wget and widget objects get destructed upon exiting doit(). If it fails in the wget constructor, the widget still gets destructed. w00t!

<?php
function msg($text) {
    print "$textn";
}

class widget {
    function __construct() {
        msg('created widget.');
    }
    function __destruct() {
        msg('destroyed widget.');
    }

}

class wget {
    private $fd;
    private $widget;
    function __construct($url) {
        msg('creating socket...');
        $this->widget = new widget();
        $this->fd = @stream_socket_client($url, $errno, $errstr, 30);
        if (!$this->fd) {
            // destructor *won't* get called here,
            // however, any existing member objects will get destructed,
            // so $this->widget will get destructed properly
            throw new exception("$errstr ($errno)");
        }
        fwrite($this->fd, "GET / HTTP/1.0rnHost: localhostrnrn");
        msg('created socket.');
    }

    function read() {
        $text = array();
        while (!feof($this->fd)) {
            $text[] = fgets($this->fd, 1024);
        }
        return join('', $text);
    }

    function __destruct() {
        if ($this->fd) {
            fclose($this->fd);
            msg('closed socket.');
        }
    }
}

function doit() {
    $wget = new wget('tcp://localhost:80');
    $text = $wget->read();
    $lines = explode("n", $text);
    msg('got ' . count($lines) . ' lines of text.');
}

doit();
msg('exiting program');

?>
About these ads