8

Hello I would like to store or save an object inside a session,using classes like SessionHandler or arrays $_SESSION,I've seen that it is possible if I serialize the object,and I don't want to lose the methods of that object instance.. I've seen seralizing it is possible but the objects what I want to store is created by PDOStatement::fetchObject() althought the instance class is "Users" I get this error:

PDOException: You cannot serialize or unserialize PDO instances Why? It is not a PDO instance..

Sorry I am spanish and I don't speak english very well.. Thanks

Carlos
  • 177
  • 1
  • 3
  • 8
  • 1
    Show how are you trying to serialize it, from the exception it seems that you are trying to serialize statement, not it's result. – dev-null-dweller Oct 30 '12 at 23:11
  • What @dev-null-dweller said. I can serialize the result of `PDOStatement::fetchObject` just fine. – Explosion Pills Oct 30 '12 at 23:18
  • If the object is from the database, why would you want to serialize it in a session? Just grab it from the DB again. Sessions should be avoided as much as possible. – Francis Avila Oct 30 '12 at 23:22

1 Answers1

15

PHP's native $_SESSION sessions transparently serialize and unserialize objects that support PHP's serialization protocol or the Serializable interface. You do not need to explicitly serialize them.

PHP cannot serialize resources because these are handles to some stateful resource outside PHP's control. This is why you cannot serialize PDO or PDOStatement objects.

By default an object is serialized by saving all property names and values and unserialized by creating an object with the same class (without invoking the constructor) and directly setting the serialized properties. You can customize serialization behavior for your objects using the __sleep and __wakeup magic methods or by implementing the Serializable interface. But not both! If you use implements Serializable, __sleep and __wakeup are ignored.

One important note: when using object serialization, you must have the class definition loaded before you unserialize (or have an autoloader that can load it) and it must match the class definition of the object that was serialized. Class definitions are not stored in the serialized data.

For example suppose you have the following:

class Test {
    public $version = 1;
    protected $abc;
    public function setAbc($abc) {
        $this->abc = $abc;
    }
}

$t = new Test();
$t->setAbc(123);
$_SESSION['mytest'] = $t;

Now imagine you change Test one day to be like this instead:

class Test {
    public $version = 2;
    private $def;
    public function setDef ($def) {
        $this->def = $def;
    }
}

Now suppose you load into your new code an object serialized when Test was at version 1:

$t = $_SESSION['mytest']; // this was stored yesterday, when Test was version 1

var_dump($t)

You will get this:

object(Test)#1 (3) {
  ["version"]=>
  int(1)
  ["def":"Test":private]=>
  NULL
  ["abc":protected]=>
  int(123)
}

Furthermore, you can't use old methods:

if ($t->version == 1) { // Check for class version
    $t->setAbc(345); // "Fatal error: Call to undefined method Test::setAbc()"
}
EmRa228
  • 1,226
  • 13
  • 22
Francis Avila
  • 31,233
  • 6
  • 58
  • 96
  • Thanks it solved my problem,but I have a new problem,on that class I pass the PDO Object in __constructor(that is connected to MySQL) and I set a member variable to PDO Object, but when I unserialize the "container object" it doesn't execute __constructor function,so the member variable that is a PDO object will not be set.. How can I solve it? Thanks – Carlos Nov 01 '12 at 11:19
  • 4
    This is explained in the answer. Constructors are not executed because the object is *restored* not *initialized*. Create a `__wakeup()` or the `Serializer` interface `unserialize()` method that does what you want, or add a `setPDO()` method and set the PDO object manually. Bottom line, though, **you should not serialize objects that contain resources**! Use a different class design. – Francis Avila Nov 01 '12 at 13:29
  • Thank you so much,I like your idea adding a setPDO method,you are right :) – Carlos Nov 01 '12 at 15:15