How can I store objects in a session in PHP? - php

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

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()"
}

Related

Default super class in PHP [duplicate]

I've been working on code that's intended to be used with objects, without really caring what the kind of object is. I wanted to type hint that the method being written expected an object of any type, but ran into some difficulty.
I tried function myFunc (object $obj) and function myFunc (stdClass $obj) but both of these generated errors when I tried to pass objects in:
Catchable fatal error: Argument 1 passed to MyClass::MyFunc() must be an instance of object, instance of ObjectActualClass given
The same happened with stdClass as well
What am I missing? I thought that all classes that didn't explicitly inherit from another class inherited from stdClass, meaning that the base class of every class in PHP would be stdClass. Is this not the case?
stdClass is NOT a base class! PHP classes do not automatically inherit from any class. All classes are standalone, unless they explicitly extend another class. PHP differs from many object-oriented languages in this respect.
The best way to enforce this would be to create a degenerate interface called Object. A degenerate interface means it has no defined methods.
interface Object {
// leave blank
}
Then in your base classes, you can implement Object.
class SomeBase implements Object {
// your implementation
}
You can now call your function as you wanted to
function myFunc (Object $obj);
myFunc($someBase);
If you pass any object which inherits from your Object interface, this type hint will pass. If you pass in an array, int, string etc, the type hint will fail.
Well it only took eight years, but this will soon be possible: PHP 7.2 introduces the object type hint! As I write this, it's currently in the RFC stage, and is due to be released in November.
Update, 30th November: PHP 7.2 has been released
RFC: Object typehint
Discussion
This behaves exactly as you might expect:
<?php
class Foo {}
class Bar {}
function takeObject(object $obj) {
var_dump(get_class($obj));
}
takeObject(new Foo);
takeObject(new Bar);
takeObject('not an object');
Will result in:
string(3) "Foo"
string(3) "Bar"
Fatal error: Uncaught TypeError: Argument 1 passed to takeObject() must be an object, string given, called in...
See https://3v4l.org/Svuij
One side-effect of this is that object is now a reserved word, which unfortunately renders #Gaz_Edge's existing solution above broken. Fortunately, all you have to do to fix it is delete the interface.
Although there is no type hinting for objects, you can use:
if (!is_object($arg)) {
return;
}
There is no base class that all objects extend from. You should just remove the typehint and document the expected type in the #param annotation.
There is no built-in mechanism to do this without requiring all users of your interface to extend a specified class. But why would you want to do this anyway? What do all object types have in common that's enough to make them suitable input for your API?
In all probability you wouldn't gain anything even if able to type hint like this. On the other hand, type hinting a parameter to implement an interface (such as Traversable) would be much more meaningful.
If you still want something akin to type hinting, the best you can do is substitute a runtime check with is_object on the parameter.
As of php 7.2 this feature has now been implemented. you can type hint for any object now.
function myFunc(object $myObject): object {
return $myObject;
}
You can review this in the official documentation
Typehint for stdClass works since PHP 5.3+ (if I am not wrong).
Following is valid code using typehint for stdClass construct:
Example test.php:
class Test{
function hello(stdClass $o){
echo $o->name;
}
}
class Arg2 extends stdClass{
public $name = 'John';
function sayHello(){
echo 'Hello world!';
}
}
$Arg1 = new stdClass();
$Arg1->name = 'Peter';
$Arg2 = new Arg2();
$Arg2->sayHello();
$test = new Test();
// OK
$test->hello($Arg1);
$test->hello($Arg2);
// fails
$test->hello(1);
Prints out:
Hello world!
Peter
John
Catchable fatal error: Argument 1 passed to Test::hello() must be an instance of stdClass, integer given, called in test.php on line 32 and defined in test.php on line 5
You could do something like this:
function myFunc ($obj)
{
if ($obj instanceof stdClass) { .... }
}

Use of PHP Magic Methods __sleep and __wakeup

What is the use of the __sleep and __wakeup magic methods in PHP? I read the PHP documentation but it's still not clear:
class sleepWakeup {
public function __construct() {
// constructor //
}
public function __sleep() {
echo 'Time to sleep.';
}
public function __wakeup() {
echo 'Time to wakeup.';
}
}
$ob = new sleepWakeup();
// call __sleep method
echo $ob->__sleep();
echo "\n";
// call __wakeup method
echo $ob->__wakeup();
This sample code prints:
Time to sleep.
Time to wakeup.
If I were to rename __sleep and __wakeup to foo and bar then it does the same thing. What is the proper use of these two methods?
As already described, __sleep() is called when you serialize() an object and __wakeup() after you unserialize() it.
Serialization is used to persist objects: You will get a representation of an object as a string that can then be stored in $_SESSION, a database, cookies or anywhere else you desire.
Resource values
However, serialize() cannot serialize (i.e. transform into a textual representation) values of the resource type. This is why all of these values will go missing after unserialize()ing it.
Object graph
or members, and the member's members and the ... ad infinitum
Another, perhaps more important point is, that serialize() will traverse the entire object graph of $obj if you serialize it. This is great when you need it, but if you only need parts of the object and certain linked objects are "runtime-specific" and shared across a lot of objects but also by other objects, you may not want that behavior.
PHP handles cyclic graphs correctly! Meaning: If (a member of) $a links to $b, and $b links to $a is handled correctly however many levels deep.
Example - session specific (shared) objects
For instance, a $database object is referenced by $obj->db, but also by other objects. You will want $obj->db to be the same objects - after unserialize()ing - that all the other objects in your next session have, not an isolated instance of the database object.
In this case, you would have __sleep() method such as this:
/**
/* DB instance will be replaced with the one from the current session once unserialized()
*/
public function __sleep() {
unset($this->db);
}
and then restore it like this:
public function __wakeup() {
$this->db = <acquire this session's db object>
}
Another possibility is, that the object is part of some (global) datastructure where it needs to be registered. You could do this manually of course:
$obj = unserialize($serialized_obj);
Thing::register($obj);
However, if it is part of the objects contract that it needs to be in that registry, it's not a good idea to leave this magical call up to the user of your object. The ideal solution is, if the object cares about its responsibilities, i.e. being registered in Thing. That's what __wakeup() allows you to do transparently (i.e. he need no longer worry about that magical dependency) to your client.
Similarly, you could use __sleep() to "un-register" an object if appropriate. (Objects are not destroyed when they're serialized, but it may make sense in your context.)
Closures
Last but not least, closures do not support serialization either. This means that you will have to re-create all attached closures in __wakeup().
They are pretty much like hook functions, which we can use according to our needs. I came up with this simple real time example. Now try executing this code in two scenarios:
class demoSleepWakeup {
public $resourceM;
public $arrayM;
public function __construct() {
$this->resourceM = fopen("demo.txt", "w");
$this->arrayM = array(1, 2, 3, 4); // Enter code here
}
public function __sleep() {
return array('arrayM');
}
public function __wakeup() {
$this->resourceM = fopen("demo.txt", "w");
}
}
$obj = new demoSleepWakeup();
$serializedStr = serialize($obj);
var_dump($obj);
var_dump($serializedStr);
var_dump(unserialize($serializedStr));
Scenario 1:
First by commenting __sleep() and __wakeup() methods, check the output. You will find the resource missing when you unserialize it.
Scenario 2:
Now try running it uncommenting them, you will figure out that the object dumped in first and last var_dump would be same.
These methods are used when calling serialize() and unserialize() on the objects to make sure you have a hook to remove some properties like database connections and set them back when loading. This happens when storing objects in sessions among other things.
Since PHP 7.4 there will be new methods __serialize() and __unserialize() available which should slightly change the usage of __sleep and __wakeup magic methods.
PHP currently provides two mechanisms for custom serialization of
objects: The __sleep()/__wakeup() magic methods, as well as the
Serializable interface. Unfortunately, both approaches have issues
that will be discussed in the following. This RFC proposes to add a
new custom serialization mechanism that avoids these problems.
More in PHP RFC manual https://wiki.php.net/rfc/custom_object_serialization.
// Returns array containing all the necessary state of the object.
public function __serialize(): array;
// Restores the object state from the given data array.
public function __unserialize(array $data): void;
The usage is very similar to the Serializable interface. From a practical perspective the main difference is that instead of calling serialize() inside Serializable::serialize(), you directly return the data that should be serialized as an array.
The following example illustrates how __serialize()/__unserialize() are used, and how they compose under inheritance:
class A {
private $prop_a;
public function __serialize(): array {
return ["prop_a" => $this->prop_a];
}
public function __unserialize(array $data) {
$this->prop_a = $data["prop_a"];
}
}
class B extends A {
private $prop_b;
public function __serialize(): array {
return [
"prop_b" => $this->prop_b,
"parent_data" => parent::__serialize(),
];
}
public function __unserialize(array $data) {
parent::__unserialize($data["parent_data"]);
$this->prop_b = $data["prop_b"];
}
}
This resolves the issues with Serializable by leaving the actual serialization and unserialization to the implementation of the serializer. This means that we don't have to share the serialization state anymore, and thus avoid issues related to backreference ordering. It also allows us to delay __unserialize() calls to the end of unserialization.
try out this
<?php
$ob = new sleepWakeup();
$safe_me = serialize($ob);
$ob = unserialize($safe_me);
?>

How does PDOStatement::fetchObject set properties before the class is constructed?

When I call this function, and add a constructor to my class, all my class properties are already set. How is that possible -- I thought you had to construct a class before you could set its properties?
I guess that PDO uses some internal code to create an object without invoking the constructor. However it is possible to instance a new object without calling the constructor even in pure PHP, all you have to do is to deserialize an empty object:
class SampleClass {
private $fld = 'fldValue';
public function __construct() {
var_dump(__METHOD__);
}
// getters & setters
}
$sc = unserialize(sprintf('O:%d:"%s":0:{}', strlen('SampleClass'), 'SampleClass'));
echo $sc->getFld(); // outputs: fldValue, without calling the construcotr
As of PHP 5.4.0+ ReflectionClass::newInstanceWithoutConstructor() method is available in reflection API.
In php, any array can be cast to an object. My assumption is pdo creates an associative array an then jus casts it. I dont know if he constuctor is called on cast...
Actually, a cast isnt the right word, a conversion occurs behind the scenes. Read this. Blurb on what happens: http://php.net/manual/en/language.types.object.php

Type hinting for any object

I've been working on code that's intended to be used with objects, without really caring what the kind of object is. I wanted to type hint that the method being written expected an object of any type, but ran into some difficulty.
I tried function myFunc (object $obj) and function myFunc (stdClass $obj) but both of these generated errors when I tried to pass objects in:
Catchable fatal error: Argument 1 passed to MyClass::MyFunc() must be an instance of object, instance of ObjectActualClass given
The same happened with stdClass as well
What am I missing? I thought that all classes that didn't explicitly inherit from another class inherited from stdClass, meaning that the base class of every class in PHP would be stdClass. Is this not the case?
stdClass is NOT a base class! PHP classes do not automatically inherit from any class. All classes are standalone, unless they explicitly extend another class. PHP differs from many object-oriented languages in this respect.
The best way to enforce this would be to create a degenerate interface called Object. A degenerate interface means it has no defined methods.
interface Object {
// leave blank
}
Then in your base classes, you can implement Object.
class SomeBase implements Object {
// your implementation
}
You can now call your function as you wanted to
function myFunc (Object $obj);
myFunc($someBase);
If you pass any object which inherits from your Object interface, this type hint will pass. If you pass in an array, int, string etc, the type hint will fail.
Well it only took eight years, but this will soon be possible: PHP 7.2 introduces the object type hint! As I write this, it's currently in the RFC stage, and is due to be released in November.
Update, 30th November: PHP 7.2 has been released
RFC: Object typehint
Discussion
This behaves exactly as you might expect:
<?php
class Foo {}
class Bar {}
function takeObject(object $obj) {
var_dump(get_class($obj));
}
takeObject(new Foo);
takeObject(new Bar);
takeObject('not an object');
Will result in:
string(3) "Foo"
string(3) "Bar"
Fatal error: Uncaught TypeError: Argument 1 passed to takeObject() must be an object, string given, called in...
See https://3v4l.org/Svuij
One side-effect of this is that object is now a reserved word, which unfortunately renders #Gaz_Edge's existing solution above broken. Fortunately, all you have to do to fix it is delete the interface.
Although there is no type hinting for objects, you can use:
if (!is_object($arg)) {
return;
}
There is no base class that all objects extend from. You should just remove the typehint and document the expected type in the #param annotation.
There is no built-in mechanism to do this without requiring all users of your interface to extend a specified class. But why would you want to do this anyway? What do all object types have in common that's enough to make them suitable input for your API?
In all probability you wouldn't gain anything even if able to type hint like this. On the other hand, type hinting a parameter to implement an interface (such as Traversable) would be much more meaningful.
If you still want something akin to type hinting, the best you can do is substitute a runtime check with is_object on the parameter.
As of php 7.2 this feature has now been implemented. you can type hint for any object now.
function myFunc(object $myObject): object {
return $myObject;
}
You can review this in the official documentation
Typehint for stdClass works since PHP 5.3+ (if I am not wrong).
Following is valid code using typehint for stdClass construct:
Example test.php:
class Test{
function hello(stdClass $o){
echo $o->name;
}
}
class Arg2 extends stdClass{
public $name = 'John';
function sayHello(){
echo 'Hello world!';
}
}
$Arg1 = new stdClass();
$Arg1->name = 'Peter';
$Arg2 = new Arg2();
$Arg2->sayHello();
$test = new Test();
// OK
$test->hello($Arg1);
$test->hello($Arg2);
// fails
$test->hello(1);
Prints out:
Hello world!
Peter
John
Catchable fatal error: Argument 1 passed to Test::hello() must be an instance of stdClass, integer given, called in test.php on line 32 and defined in test.php on line 5
You could do something like this:
function myFunc ($obj)
{
if ($obj instanceof stdClass) { .... }
}

What advantage is provided by object overloading in PHP?

PHP object overloading is explained here.
Basically it allows you to define some custom actions when an inaccessible object property or method is accessed.
What are some practical uses for this feature?
Usually, those methods are useful when you are communicating with a 3rd party API or when the method/members structure is unclear.
Let's say you are writing a generic XML-RPC wrapper. Since you don't know the methods available to you before you download the WDL file, it makes sense to use Overloading.
Then, instead of writing the following:
$xmlrpc->call_method('DoSomething', array($arg1, $arg2));
You can use:
$xmlrpc->DoSomething($arg1, $arg2);
which is a more natural syntax.
You can also use member overloading in the same way as method overloading for variable objects.
Just one thing you want to watch for: limit its use only to variable-structure objects or use it only for syntactical shortcuts to getters and setters. It makes sense to keep getters and setters in your class to seperate business logic in multiple methods, but there is nothing wrong in using it as a shortcut:
class ShortcutDemo {
function &__get($name) {
// Usually you want to make sure the method
// exists using method_exists, but for sake
// of simplicity of this demo, I will omit
// that logic.
return call_user_method('get'.$name, $this);
}
function __set($name, &$value) {
return call_user_method('set'.$name, $this, $value);
}
private $_Name;
function &getName() { return $this->_Name; }
function setName(&$value) { $this->_Name = $value; }
}
That way you can continue using your getters and setters to validate and set your data, and still use the syntactic shortcuts as such:
$shortcut->Name = 'Hello';
Another method that Andrew didn't mention (or hasn't mentioned at the time of writing) is for getting rid of getters and setters. Instead of having to declare each setter and getter like this:
$obj->setName("Chacha");
$obj->setRep(10000000000000000000000);
You can instead just do
$obj->Name = "chacha";
$obj->Rep = 100000000000000000;
The second method is more natural.
Magic Methods basically further the thought of Object Oriented programming, and the idea that how you implement a job should not matter to the outside world. Through Magic Methods, it allows you to store your variables however you want, and just let other classes set them in a natural way.
Example: I could store all my user's account preferences in a single array that would make it really easy to iterate through to push it all up to the session.
If I didn't use a Magic Method for this, I would either have to make a bunch of sets or gets, which means writing more code, or allow direct access to the array, which reveals the implementation, so I can't go and change it later.
Instead, using Magic Methods, I just have them set the variable regularly, and I deal with it internally.
You could use it for cases when a class has complex rules for isset and unset. For example, a class containing a variable $a could be an array of objects or other resources, and when unset, they have to do perform some other functionalities.
Though I am not sure why they allow the adding of a new property and retrieving of a non-private property, but you could use it to change the internal state of an object by calling other code depending on the name of the property/member variable being set.
In some cases, this resembles operator overloading in C++
Message forwarding for when you have composed or aggregated objects where polymorphism isn't an option (say, you're using a library class you can't control).
<?php
// Class A is final, so we can't make subclasses.
final class A
{
public function hello( $callback )
{
echo call_user_func( $callback, 'hello world' );
}
}
// so instead, we make a wrapper class that will take an instance
// of A as an aggregate
class B
{
private $a;
public function __construct( A $a )
{
$this->a = $a;
}
// this mimics inheritance on the aggregate object
// method calls are automatically forwarded to instance of A
// if they are valid
public function __call( $method, $args )
{
if ( method_exists( $this->a, $method ) )
{
return call_user_func_array( array( $this->a, $method ), $args );
}
throw new Exception( "Method [$method] not found." );
}
}
class C extends B
{
// This mimics overriding an "inherited" method
public function hello( $callback )
{
echo call_user_func( $callback, 'bonjour le monde' );
}
}
$a = new A;
$b = new B( $a );
$c = new C( $a );
$b->hello( 'strtoupper' );
$c->hello( 'strtoupper' );
This feature is actually what object oriented programming is all about, in the mind of its inventor Alan Kay: Objects sending each other messages, and potentially reacting to any kind of message. Methods fixed at compile time are a limited (but also more efficient) implementation of this concept. That's where Kay's famous-quote "I invented the term object oriented, and I can tell you that C++ wasn't what I had in mind." comes from.
Basically, allowing objects to react to method calls without having a corresponding method fixed at compile time implements this original, broader definition of object orientation. Most modern "dynamic" languages support it in one form or another.
As for what it's good for: take a look at Groovy's Builders for a good example. Basically, it allows very compact low-redundancy syntax by turning method names themselves into data.
One way, which is quite a bit fancier, that I've used it is to create a Linq like Object Relational Management (ORM) system. Where you can then load up a database table structure and manipulated the data (from the database table) as if it were just an object.
i.e.
include('blibrary/bLinq.class.inc');
$linq = new bLinq(new bLinqSql('mysql://dsn'));
$r = $linq->from('Users')
->password
->select();
which translates to the following SQL:
SELECT `password` from Users;
The password in the select statement comes from the overloaded method.
The result can be used like:
(array)$r->password; // which outputs an array multiple results of password;
(string)$r->password; // which outputs a string of the first password hash;
$r->password[2]; // which outputs a string of the third password hash;
The point is that the word "password" could be substituted for any other field in the database on the fly when programming.
I use __get and __set to link objects together e.g.
$user = new User();
echo $user->Profile->views;
This (usually) calls some SQL linking users.id = profile.user_id.
Properties (like that in Python or C#). For example when you use something like this in Nette, you create some class, which shows some property as public:
<?php
class Foo extends Object
{
public $bar;
}
You can access this property natural way – $instance->bar. But when you want to do some validation etc., you just add getter and setter:
<?php
class Foo extends Object
{
private $bar;
public function getBar()
{
return $this->bar;
}
public function setBar($bar)
{
if ($bar === NULL) throw new Exception('…');
$this->bar = $bar;
}
}
And still you use $instance->bar. But when you do $instance->bar = NULL;, it's like calling $instance->setBar(NULL);.

Categories