The Automatic Resource Destructor pattern

Originally published at OpenCraft.

What happens if you need to open a file with fopen, but find that your function can exit at multiple points? It is tedious and error-prone to call fclose at each exit point. Alternatively, you could re-structure your code to only exit at the bottom, thereby calling fclose only once, but you would end up with many nested blocks that hamper readibility and are generally considered bad programming style.

A technique I like to use in those cases is the Automatic Resource Destructor. The idea is to create an object instance that destroys the used resource, in our case the file handle, when its own destructor is called. Here's how it works:

<?php
class FileDestructor {
  function
__construct($resource) {
   
$this->resource = $resource;
  }
  function
__destruct() {
   
fclose($this->resource);
  }
  function
get() {
    return
$this->resource;
  }
  private
$resource;
}
?>

The way to use this in your code is the following:

<?php
function foo() {
 
$file = new FileDestructor(fopen('file.txt', 'r'));
 
$text = fread($file->get(), 1024);
  if (
$text[0] != 'X') return FALSE;
 
// Some more processing...
 
return TRUE;
}
?>

Notice that you don't need to call fclose because the destructor of $file will be called automatically upon exiting the function. This is the benefit of using this file destructor.

You can generalize the above code to work with any kind of resource that has a single-valued destructor function:

<?php
class ResourceDestructor {
  function
__construct($resource, $destroy) {
   
$this->resource = $resource;
   
$this->destroy = $destroy;
  }
  function
__destruct() {
   
call_user_func($this->destroy, $this->resource);
  }
  function
get() {
    return
$this->resource;
  }
  private
$resource;
  private
$destroy;
}
?>

In this case, you would instantiate the object like the following:

<?php
$file
= new ResourceDestructor(fopen('file.txt', 'r'), 'fclose');
$db = new ResourceDestructor(mysql_connect(...), 'mysql_close');
?>

Finally, instead of repeating the close function every time, you can create subclasses for each resource type:

<?php
class FileDestructor extends ResourceDestructor {
  function
__construct($resource) {
   
parent::__construct($resource, 'fclose');
  }
}

class
MySqlDestructor extends ResourceDestructor {
  function
__construct($resource) {
   
parent::__construct($resource, 'mysql_close');
  }
}
?>

Happy coding!