Less PHP Database Code Using The Factory Design Pattern

It’s PHP design pattern time again! Today I’ll show a simple way to

  • Encapsulate database access in a class
  • Make queries return objects rather than records or arrays
  • Reduce code to process database results

All this is achieved by using the factory pattern. Read on!

It usually is a good idea to encapsulate database access into a class. Not necessarily because you may change your database more easily (since for most PHP applications the database will be MySQL for still a long time, due to provider configurations), but to get rid of all this repeating database access code, which tends to be error prone.

If you start to wrap db code fragments into a class, however, you’ll notice that having hidden MySQL inside a neat little class, you still have code like

while ($record = mysql_fetch_array($dbHandle)) doSomething($record);

spread all over your application. And that’s the last thing you want, actually. So it’s time for another abstraction, a recordset, is it?

Well, not necessarily. Try using the factory design pattern.

The idea of the factory pattern is to use a function to create an instance of a class rather than calling the constructor using new. This is because a function can be overridden, while a constructor cannot. This makes quite a difference, since for using the new keyword, we must know the concrete type of the instance to create. Having a function, this is not required, since it is enough to know the function exists.

Let’s start with a simple class like this one:

class Person {
  var $firstName = "";
  var $lastName = "";
  var $age = 0;
  
  function Person($firstName, $lastName, $age) {
    $this->firstName = $firstName;
    $this->lastName = $lastName;
    $this->age = $age;
  }
}

Now we write a factory. It is really simple, since it contains just one function. We pass a record, which actually is an associative array. This is a brief abstraction in this case. Here we go:

class PersonFactory {
  function &create(&$record) {
    return new Person(
      $record['firstname'],
      $record['lastname'],
      $record['age']
    );
  }
}

Simple, isn’t it? This of course assumes the fields in the database are called accordingly.

Now on to the database wrapper class. Having a factory class, a database query can return objects directly, rather then just records or a query handle:

class DB {
  // .. some other code to open connection etc.

  
  // returns an array of instances

  function &queryArray($sql, &$factory) {
    $queryID = mysql_query($sql);
    $ret = array();
    if ($queryID) {
      while ( $record = mysql_fetch_array($queryID) ) {
        $ret[] = $factory->create($record);
      }
      mysql_free_result($queryID);
    }
    return $ret;
  }
  
  // Returns a single instance	

  function &querySingle($sql, &$factory) {
    $queryID = mysql_query($sql);		
    if ($queryID) {
      if ( $record = mysql_fetch_array($queryID) ) {
        mysql_free_result($queryID);
        return $factory->create($record);
      }
    }
    return false;	
  }
}

I hope you get the idea. There is no magic in this code, everything is straight forward. Having the DB returning an array of instances makes it much easier to iterate through it, using a common foreach loop.

What’s missing is a function to load objects from database. Here are two simple implementations:

class PersonDB {
  // returns one instance

  function &findByID($id) {
    return DB::querySingle(
      'Select * from Person where id = $id',
      new PersonFactory()
    );
  }
  
  // returns an array

  function &findByAge($age) {
    return DB::queryArray(
      'Select * from Person where age = $age',
      new PersonFactory()
    );
  }
}

And finally here’s the client code that uses it all:

//print all persons that are 35 years old

if ( $arr = PersonDB::findByAge(35) ) {
  foreach($arr as $person) {
    echo $person->foreName . ' ' . $person->lastName . '\n';
  }
}

Neat, isn’t it? Notice that each of the functions and classes presented are simple and more or less self-explaining. Combined, however, they provide a great flexibility. Now compare this to the avarage PHP database code, you’ll find in oh so many PHP applications!

Published: January 27 2005