I just found an interesting quirk in PDO. If you do something like

  $stmt->execute(PDO::FETCH_CLASS, 'className'); 

it populates the attributes from the result row before it calls __construct() on the class className. If you want __construct() called first you need to do something like

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

PDO::FETCH_PROPS_LATE and this case don't seem to be very well documented.

This situation doesn't seem to be accounted for in DatabaseStatement::execute. It only allows for the first code case above.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Crell’s picture

Priority: Critical » Normal

Interesting. When would you want to do one or the other? Should we be defaulting to one or the other, or is there value to allowing both?

mfer’s picture

Here's an example, hopefully this clarifies

You have an object:

class myClass {

  function __construct($params = array()) {
    
    if (empty($params['id'])) $this->id = NULL;

  }

}

If you call

  $stmt->execute(PDO::FETCH_CLASS, 'className');

and have a resulting field called id the value on the object would be set to null. First $this->id would be set to the field result from the row. Then __construct() would be called setting it to NULL.

Calling

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

the resulting $this->id would be the value from the id field in the row. First __construct would be called setting it to null and then the attributes from the result row would be applied.

You'd want the second case if your __construct() function did any kind of setup that might override the attributes placed on the object from the database. The second case will follow the same flow to create an object as if you did

  $object = new myClass();

Personally, I prefer the second method. I'm a fan of having the object built in the same order everywhere. You have to account for less in your testing and less odd circumstances happen.

Just as PDO allows for the flexibility of both ways it might be good for us to as well. But, if we choose one I'd like to see PDO::FETCH_PROPS_LATE be used.

I know that we can write our __construct() functions to take the first situation into account. I found this issue when I was creating objects from an external library that had __construct() statements causing issues. In order to support using the external library in an unmodified way I needed to use PDO::FETCH_PROPS_LATE.

Crell’s picture

Hm. Makes sense. I'm not sure off hand how we'd allow both in the current setup, except adding yet another field to the options array. It seems it would cause fewer issues to just make it always do a late fetch. That's also easier to implement.

Can anyone see a reason we'd want an early fetch in this case? If not, let's just roll a patch to use late fetch.

mfer’s picture

Assigned: Unassigned » mfer
Status: Active » Needs review
FileSize
818 bytes

This patch adds PDO::FETCH_PROPS_LATE in with PDO::FETCH_CLASS and adds a comment into why we use FETCH_PROPS_LATE.

Status: Needs review » Needs work

Patch failed to apply. More information can be found at http://testing.drupal.org/node/14330. If you need help with creating patches please look at http://drupal.org/patch/create

mfer’s picture

Status: Needs work » Needs review
FileSize
1.08 KB

Fixed patch for drupalTestbedBot.

mfer’s picture

Rough night. Removed accidental change to another part of the file.

Dries’s picture

Status: Needs review » Fixed

I think this makes a ton of sense. I've committed it to CVS HEAD. Thanks.

c960657’s picture

It looks like this caused a regression: #310904: Use early fetch and document why

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.