ini_set('unserialize_callback_func', 'spl_autoload_call');
spl_autoload_register(array(self::getInstance(), 'autoload'));
Why set spl_autoload_call
like above?
I made a test:
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
ini_set('unserialize_callback_func','mycallback');
function mycallback($classname) {
echo 1;
}
function func2()
{
echo 2;
}
spl_autoload_register('func2');
unserialize($serialized_object);
The output is:
212
Can someone explain this?
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 :
callback_spl
has been called
spl_autoload_register
__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 :
spl_autoload_register
has been called
__PHP_Incomplete_Class
anymore,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 :
callback_no_spl
callback function registered via unserialize_callback_func
is called
a
Going a bit farther, let's try what we can get when both :
callback_no_spl
, with unserialize_callback_func
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 :
spl_autoload_register
has been called
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 :
spl_autoload_register
has been called
unserialize_callback_func
has been called
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 :
spl_autoload_register
is called
unserialize_callback_func
is called
spl_autoload_register
is called again !
unserialize_callback_func
did not load the class' definition
callback_spl
has been called for the second time !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 :
unserialize_callback_func
exists since PHP 4.2spl_autoload_register
only exists since PHP 5.1
and __autoload
has been introduced in PHP 5The "stack / queue" behavior of spl_autoload_register
, I suppose, can have some interferences with the old behavior of unserialize_callback_func
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With