Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP PDO::FETCH_LAZY - not creating object variable names as they are accessed

Tags:

php

pdo

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.

like image 274
Souvik Avatar asked Oct 22 '22 19:10

Souvik


2 Answers

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();
like image 115
Hugues D Avatar answered Nov 03 '22 04:11

Hugues D


in line

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

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

like image 28
Janos Szabo Avatar answered Nov 03 '22 04:11

Janos Szabo