Releasing unmanaged resources (a PHP port from C#’s “using” statement)


Sometimes we work with instances that needs to released even when exceptions happens. Something typical when we work with resources (Files, Database connections, …) Let me show you with an example:

Imagine this class for handling file resources:

class File
{
    private $resource;
    private $logger;

    public function __construct($filename, Loger $logger)
    {
        $this->logger = $logger;
        $this->resource = fopen($filename);
    }

    public function write($string)
    {
        fwrite($this->resource, $string);
    }

    public function close()
    {
        $this->logger->log("file closed")   
        fclose($this->resource);
    }
}

We can use this class:

$file = new File(__DIR__ . "/file.txt", 'w');
$file->write("Hello\n");
// ...
// some other things
// ...
$file->write("Hello\n");
$file->close();

OK. What happens if one exception happens inside “some other things”? Simple answer: close() function isn’t called. This can be a problem. We can face this problem with a try/catch block like this:

try {
    $file->write("Hello\n");
    // ...
    // some other things
    // ...
    $file->write("Hello\n");
    $file->close();
} catch (\Exception $e) {
    $file->close();
}

Or even if we’re using PHP5.5 we can use “finally” keyword

try {
    $file->write("Hello\n");
    // ...
    // some other things
    // ...
    $file->write("Hello\n");
} catch (\Exception $e) {
} finally {
    $file->close();
}

Sometimes I need collaborate with C# projects. C# is a great language. I really like it. It has a really cool feature to solve this problem: the “using” statement. Because of that we are going to build today one small library to implement something similar in PHP.

First we will add G\IDisposable interface to our File class

namespace G;

interface IDisposable
{
    public function dispose();
}

Now our File class looks like this:

use G\IDisposable;

class File implements IDisposable
{
    private $resource;

    public function __construct($filename, $mode)
    {
        $this->resource = fopen($filename, $mode);
    }

    public function write($string)
    {
        fwrite($this->resource, $string);
    }

    public function close()
    {
        fclose($this->resource);
    }

    public function dispose()
    {
        $this->close();
    }
}

And we can use our “using” function in PHP:

using(new File(__DIR__ . "/file.txt", 'w'), function (File $file) {
        $file->write("Hello\n");
        $file->write("Hello\n");
        $file->write("Hello\n");
    });

As we can see we can forget to close() our file instance. “using” will do it for us, even if one exception is triggered inside. We need to take into account that “using” is not a way to handle exceptions. If you want to handle them you need to do it. The only responsibility of “using” is to ensure that dispose() is been called.

We also can use an array of instances (implementing the IDisposable interface of course)

using([new Bar, new Foo], function (Bar $bar, Foo $foo) {
        echo $bar->hello("Gonzalo");
        echo $foo->hello("Gonzalo");
    });

And that’s all. Library is available in github and also you can use it with composer.

Update!
I’ve changed the Example. The first example wasn’t a good one. Now File::close() closes the resource and also write a log. With the first example (without the logger) it wasn’t important to close the resorce (PHP closes it).

Advertisement

12 thoughts on “Releasing unmanaged resources (a PHP port from C#’s “using” statement)

    1. __destruct() isn’t called if one exception is thrown. “using” ensures that disponse() is called (even with exceptions)

      1. Actually it does, unless you are using the global namespace.


        <?php
        class Test
        {
        public function __destruct() {
        echo 'Destructed!'.PHP_EOL;
        }
        }
        // Destructed!
        call_user_func(function() {
        $test = new Test();
        throw new Exception('Stuff just got messed up!');
        });
        // Not destructed.
        $test = new Test();
        throw new Exception('Stuff just got messed up!');

      2. I realized this within this post. That’s because $test goes out (or not) of scope. My first impression was it was a bug but it isn’t (php facts :)). We can do the same with __desctruct (if we wrap the code within a block) but anyway I still prefer the usage of dispose() instead of __destruct

  1. I don’t want to sound pedantic, but what’s the gain versus “finally”?

    I see the same amount of code, and it’s a little less readable and explicit.

    1. In fact the “using” function creates a try/finally block (I not use finally keyword because of compatibility). IMHO is more readable with the interface. If one class implements IDisposable it must implements dispose() function (where we release resources). It’s very common in C# and Python (“with” keyword).

      “using” also allows you to use an array of IDisposable instances. You can do it of course with try/finally blocks but the code will be more comples

  2. You don’t need this complication. PHP will automatically clean up resources (close them) when the variable goes out of scope and is garbage collected. So when an exception is thrown, and the stack frame is popped, the variables will all be collected (assuming there are no other references).

    When that happens, the resource is no longer reachable and will be closed. Take this code for example:

    function readFile($fileName) {
    $f = fopen($fileName, ‘r’);
    return fread($f, 1024);
    }

    The file handle is not leaked. Since `$f` goes out of scope at the end of the return, it’s destructed. And since PHP resources are closed on destruction, the resource will be closed as well.

    In short, there’s no need to go through all of this complication **for this specific reason**. You may want it for other reasons (such as closing of transactions, etc), but not for resource cleaning.

    1. touche! I’ve use the File example because is simple to understand (and it’s also the example used in almost all c# documentation about “using” 🙂 ). But PHP handles resources as you said. So maybe my example is not the best one.

      I’m using something similar with PDO database transactions (in fact DBAL implements the same idea with its transactional() function)

      Also it can be used when dispose() action is more complex (not only close a resource). For example, unlink temporally files, register logs or things like that.

      many thanks for the clarification.

      Do you think it would be a good idea to implement this functionality in the PHP core:

      For example:

      using($bar = new Bar(), $foo = new Foo()) {
      echo $bar->hello("Gonzalo");
      echo $foo->hello("Gonzalo");
      });

      1. I answer myself. Maybe is not a good thing to include “using” in the core (as in C# or “with” in python) due to it’s deterministic destruction.

        Maybe if we want to use we can use it as a library or maybe using __destruct() (I’m not a big fan of __destruct() but is more or less the same)

  3. Hi, I think that the functionality “using” is very interesting, in a specific scope It could be a good solution, is a good tool, thanks. By the way, the code of your first example, at line 19, there is a bug, the $logger variable does not exists, it may be $this->logger.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.