4
votes

I was working with PDO, and could not understand PDO::FETCH_LAZY. In PHP manual it says "...PDO::FETCH_LAZY creates the object variable names as they are accessed...". I have this code to test this:

class b{
    function __construct(){}
}
$b = new b();

$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'pssword');

//testtable{id int, title varchar, msg varchar, time varchar}

$res = $pdo->query("SELECT * FROM testtable limit 1");
$b = $res->fetch(PDO::FETCH_LAZY);
echo $b->msg;
var_dump($b);

This is supposed to print the object b with only 1 property, msg. But instead, the output is this:

This is a sample message.

object(PDORow)#6 (5) {
  ["queryString"]=>
  string(31) "SELECT * FROM testtable limit 1"
  ["id"]=>
  string(1) "1"
  ["title"]=>
  string(5) "sample title"
  ["msg"]=>
  string(13) "This is a sample message."
  ["time"]=>
  string(7) "1232123"
}

Can anyone please throw some light on this? Thanks.

2
Pretty sure that var_dump($b) would cause it to access all the properties and load them.Cfreak
Just curious. What DB backend are you using?Mihai Stancu

2 Answers

2
votes

PDORow is an internal class that is very poorly documented. It's not even in the manual (search results).

The only way to see a PDORow is if you FETCH_LAZY:

$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->bindValue(':id', 1, PDO::PARAM_INT);
$stmt->execute();
$lazy = $stmt->fetch(PDO::FETCH_LAZY);

The interesting thing is that all of its properties are public. The first one, 'queryString', is associated to the sql query. It is some kind of proxy.

You can reuse it for further statements, to get the full object. Fetching a PDORow (almost) doesn't increase memory usage. It's not serializable, and calling an undefined property on it doesn't raise an error.

More about it on phpdelusions.net

Objects returned from PDO when fetch lazy is used are NOT stdclass objects, they are of type pdorow and have some magic features including delayed data fetching - this is a bit obscured with the way pdo _ drivers are set up

You can follow this interesting discussion about it.

From the php-src, we can see that PDORow is not meant to be instantiated

You can see several details about the class in pdo_stmt.c Ctrl+F PDORow for the rest

Edit

A possible use case for FETCH_LAZY, would be:

// get the lazy object - aka, PDORow
    $stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
    $stmt->bindValue(':id', 100, PDO::PARAM_INT);
    $stmt->execute();
    $lazy = $stmt->fetch(PDO::FETCH_LAZY);

Next, reuse it:

// do whatever you please with the properties, since they're all public
   $publicProps = get_object_vars($lazy);

And then, load the real object if you need it:

// loading lazy object
    $stmt = $pdo->prepare($publicProps['queryString']);
    $stmt->bindValue(':id', $publicProps['id'], PDO::PARAM_INT); 
    /** you could use a regex to get an array of parameters' names prefixed by ':' in the original queryString
    * eg, $queryString = 'SELECT * FROM users WHERE firstName = :firstName AND email = :email';
    * preg_match_all('/:[^\s]+/', $queryString, $matches);
    * would give you an array with ":firstName" and ":email"
    */
    $stmt->execute([':id' => $publicProps['id']]);
    $notLazy = $stmt->fetch();
1
votes

in line

$b = $res->fetch(PDO::FETCH_LAZY);

you gave new value (PDORow object) to variable $b overwriting 'b' object