A gotcha with PHP's PDO::FETCH_CLASS

Posted in PHP -

PHP's PDO has a nifty way of fetching database records into an object, but there's a slight gotcha when also using a constructor which initializes the class properties.

tl;dr

Data is populated before the constructor is called. To populate data after the constructor use PDO::FETCH_PROPS_LATE i.e.:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'className');

Longer answer

PDO's setFetchMode() allows you to specify the way data is retrieved, e.g. as an associative array, indexed array, etc or into an object.

In the following examples:
- $pdo is a connected PDO database object
- $sql is the query to run, with ? placeholders
- $data is an array of data for those placeholders
- $class is the name of the class to fetch the data into

Run a query using PDO and then fetch the result into an object like this:

$stmt = $pdo->prepare($sql);
$stmt->execute($data);
$stmt->setFetchMode(PDO::FETCH_CLASS, $class);
$object = $stmt->fetch();

This is really useful if you are implementing some sort of data object with a bunch of functions attached to it; the object returned is populated from the database and you can then call those functions.

The gotcha

In the above example, the data is populated into the object first, and then the constructor is called (if there is one). If the constructor does some sort of initialization, then values from the database may be overwritten with the same values every time.

Using the following trivial example, no matter what the value of "id" is in the database, the object will always set it to 1 after the record is loaded:

class foo {
    public $id;
    function __construct()
    {
        $this->id = 1;
    }
}

Again, this is a trivial example which you probably wouldn't do, but it illustrates the point. You might have a data object that sets default values in the constructor, which clobbers the values loaded from the database after they are set into the object.

The solution

This may not be an issue for you, and you may indeed want the constructor to run after the data is populated into the object. But if you don't, simply add PDO::FETCH_PROPS_LATE when calling setFetchMode() and the constructor will be called first:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'foo');

Done! I hope this was useful :)



Related posts:


Comments