I did some tests, and here are the notes I took (hope it'll be understandable ^^ ;; and that I didn't get too lost in my own thought ^^ )
Note : I've done my tests on PHP 5.3.2-dev, in case it matters.
First of all, let's define a temp-2.php
file, that's going to contain only this :
<?php
class a {
}
i.e. the definition of the class that corresponds to the object we'll be trying to unserialize.
And all other portions of code I will post will be contained in a file called temp.php
-- which would have to include temp-2.php
so the class' definition is known.
First try : we try to unserialize the string, without having defined the class a
:
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
function callback_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
}
spl_autoload_register('callback_spl');
$data = unserialize($serialized_object);
var_dump($data);
As output, we get this :
string 'callback_spl : a' (length=16)
object(__PHP_Incomplete_Class)[1]
public '__PHP_Incomplete_Class_Name' => string 'a' (length=1)
public 'value' => string '100' (length=3)
Which means that :
- The autoloading function
callback_spl
has been called
- even if registered by
spl_autoload_register
- But it has not autoloaded anything
- And, as the class as not been autoloaded, we get an object that's an instance of
__PHP_Incomplete_Class
Now, let's try using spl_autoload_register
to register an autoloading function that actually autoloads the class' definition :
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
function callback_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
require dirname(__FILE__) . '/temp-2.php';
}
spl_autoload_register('callback_spl');
$data = unserialize($serialized_object);
var_dump($data);
And we get this ouput :
string 'callback_spl : a' (length=16)
object(a)[1]
public 'value' => string '100' (length=3)
Which means :
- The autoloading function registered by
spl_autoload_register
has been called
- And, this time, it did require the file containing the definition of the class
- The un-serialization has been successful
- i.e. we don't get an instance of
__PHP_Incomplete_Class
anymore,
- we actually get an instance of
a
So, here, I would say that unserialize_callback_func
is not needed when spl_autoload_register
is used.
I think, here, that I've kind of answered the question ? But I'll post a couple of other tests, just for fun ^^
Now, what if we try using unserialize_callback_func
, and not using spl_autoload_register
?
The code will look like his, I suppose :
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
ini_set('unserialize_callback_func', 'callback_no_spl');
function callback_no_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
require dirname(__FILE__) . '/temp-2.php';
}
$data = unserialize($serialized_object);
var_dump($data);
And, as output, we get :
string 'callback_no_spl : a' (length=19)
object(a)[1]
public 'value' => string '100' (length=3)
So, everything works OK :
- The
callback_no_spl
callback function registered via unserialize_callback_func
is called
- It loads the definition of the class
- And the data is unserialized properly
- i.e. we get an instance of
a
Going a bit farther, let's try what we can get when both :
- Setting an autoload function, called
callback_no_spl
, with unserialize_callback_func
- And setting another autoload function, called
callback_spl
, with spl_autoload_register
The code will look like this :
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
ini_set('unserialize_callback_func', 'callback_no_spl');
function callback_no_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
require dirname(__FILE__) . '/temp-2.php';
}
spl_autoload_register('callback_spl');
function callback_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
require dirname(__FILE__) . '/temp-2.php';
}
$data = unserialize($serialized_object);
var_dump($data);
And the output we get :
string 'callback_spl : a' (length=16)
object(a)[1]
public 'value' => string '100' (length=3)
Which means :
- only the autoloading function registered with
spl_autoload_register
has been called
- It did load the file that contains the class' definition
- And the data has been unserialized properly.
Now, just for fun, what if we try changing the order in which we set the autoloaders ?
i.e. use this portion of code :
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
spl_autoload_register('callback_spl');
function callback_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
require dirname(__FILE__) . '/temp-2.php';
}
ini_set('unserialize_callback_func', 'callback_no_spl');
function callback_no_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
require dirname(__FILE__) . '/temp-2.php';
}
$data = unserialize($serialized_object);
var_dump($data);
We get exactly the same output as before :
string 'callback_spl : a' (length=16)
object(a)[1]
public 'value' => string '100' (length=3)
Which seems to indicate that the autoloader defined with spl_autoload_register
as a higher priority than the one defined with unserialize_callback_func
.
What else can I test ?
Oh, let's test setting both autoloading functions, but have the one registered by spl_autoload_register
(i.e. the one with the highest priority) not actually load the class' definition :
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
ini_set('unserialize_callback_func', 'callback_no_spl');
function callback_no_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
require dirname(__FILE__) . '/temp-2.php';
}
spl_autoload_register('callback_spl');
function callback_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
//require dirname(__FILE__) . '/temp-2.php'; // We don't load the class' definition
}
$data = unserialize($serialized_object);
var_dump($data);
This time, here's the ouput we get :
string 'callback_spl : a' (length=16)
string 'callback_no_spl : a' (length=19)
object(a)[1]
public 'value' => string '100' (length=3)
Basically :
- The autoloading function registered with
spl_autoload_register
has been called
- It did not load the class' definition
- So the autoloading function registered with
unserialize_callback_func
has been called
- And it did load the class' definition
- So, we've obtained the data properly un-serialized.
Now, let's come back to the code example you posted -- translated to my functions names, it would give us something like this, I suppose :
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
ini_set('unserialize_callback_func', 'callback_no_spl');
function callback_no_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
//require dirname(__FILE__) . '/temp-2.php'; // We don't load the class' definition
}
spl_autoload_register('callback_spl');
function callback_spl($className) {
var_dump(__FUNCTION__ . ' : ' . $className);
//require dirname(__FILE__) . '/temp-2.php'; // We don't load the class' definition
}
$data = unserialize($serialized_object);
var_dump($data);
And, this time, I get the same kind of thing as you did :
string 'callback_spl : a' (length=16)
string 'callback_no_spl : a' (length=19)
string 'callback_spl : a' (length=16)
( ! ) Warning: unserialize() [function.unserialize]: Function callback_no_spl() hasn't defined the class it was called for ...
object(__PHP_Incomplete_Class)[1]
public '__PHP_Incomplete_Class_Name' => string 'a' (length=1)
public 'value' => string '100' (length=3)
And, this time :
- The function registered with
spl_autoload_register
is called
- And doesn't load the class' definition
- Then, the function registered with
unserialize_callback_func
is called
- It doesn't load the class' defition either...
- Like magic, the function registered with
spl_autoload_register
is called again !
- It still doesn't load the class' definition
- And boom, we get a warning saying that the function registered with
unserialize_callback_func
did not load the class' definition
- Note this only happens after
callback_spl
has been called for the second time !
- Which seems to indicate that there is some kind of autoloading happening even if the function defined with
unserialize_callback_func
didn't load what it should have...
I have to admit, this is both nice and tricky -- and I have quite no idea why this is happening, as it doesn't seem to make much sense...
I suppose this strange behavior has to do with the fact that :
The "stack / queue" behavior of spl_autoload_register
, I suppose, can have some interferences with the old behavior of unserialize_callback_func
...