2010-02-24 18 views
3
ini_set('unserialize_callback_func', 'spl_autoload_call'); 

spl_autoload_register(array(self::getInstance(), 'autoload')); 

为什么设置spl_autoload_call像上面那样?当spl_autoload_register已被使用时,为什么需要unserialize_callback_func?

我做了一个试验:

$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); 

输出是:

212 

有人能解释一下吗?

+0

您是否有机会通过查看symfony代码来提出这个问题? – VolkerK 2010-02-24 13:42:40

+0

是的!我正在检查symfony代码,以便知道它是如何工作的!它源自sfCoreAutoload.class.php中的'register'方法。 – user198729 2010-02-24 13:49:26

回答

-1

unserialize()需要在实际反序列化数据之前加载类定义。未加载类定义时会调用unserialize_callback_func,并且spl_autoload_call会尝试使用注册的所有自动加载器加载unserialize()所需的类。

+0

函数是否在自动加载的'spl_autoload_register'中注册了函数? – user198729 2010-02-24 12:42:24

+0

不好意思,但问题不在于'unserialize_callback_func'的作用,而是为什么你必须以unserialize_callback的身份重新注册一个完美工作的自动加载器。 – VolkerK 2010-02-24 13:19:13

+0

问题是“什么时候将spl_autoload_call调用?”,我已经回答了。这就是为什么答案很奇怪。 – 2010-02-24 14:39:16

15

我做了一些测试,下面是我笔记(希望这将是可以理解的^^ ;;而我并没有太迷失在我自己的想法^^)
注:我已经对PHP 5.3.2-dev进行了测试,以防万一。


首先,让我们定义一个temp-2.php文件,那将只包含此:

<?php 

class a { 

} 

即对应于我们试图反序列化对象的类的定义。

而我将发布的所有其他代码部分将包含在名为temp.php的文件中 - 这将包括temp-2.php,因此该类的定义是已知的。


首先尝试:我们尝试反序列化的字符串,而不必定义的类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); 

作为输出,我们得到这样的:

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) 

这意味着, :

  • 自动加载功能callback_spl被称为
    • 即使抢注spl_autoload_register
    • 但一直没有自动加载的东西
  • 而且,作为类不被自动加载,我们得到了一个对象,它是一个的__PHP_Incomplete_Class


现在例子,让我们尝试使用spl_autoload_register注册,实际上自动加载的类的定义的自动加载功能:

$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); 

我们得到这个输出中:

string 'callback_spl : a' (length=16) 

object(a)[1] 
    public 'value' => string '100' (length=3) 

这意味着:

  • 通过spl_autoload_register注册的自动加载功能有被称为
    • 而且,这个tim E,它确实需要包含类
  • 将未序列化已经成功的定义文件
    • 即我们没有得到的__PHP_Incomplete_Class了一个实例,
    • 我们实际上得到的的a

例如所以,在这里,我要说的是unserialize_callback_func不neede d当使用spl_autoload_register时。

我想,在这里,我有种回答这个问题?但我会后一对夫妇的其他测试,只是为了好玩^^



现在,如果我们尝试使用unserialize_callback_func,而不是使用spl_autoload_register什么?
代码看起来像他,我想:

$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); 

而且,作为输出,我们得到:

string 'callback_no_spl : a' (length=19) 

object(a)[1] 
    public 'value' => string '100' (length=3) 

所以,一切正常OK:

  • callback_no_spl回调函数通过unserialize_callback_func注册被称为
    • 它加载的类
  • 的定义和数据正确地去系列化
    • 即我们得到的a


一个实例去更远一些,让我们试着我们可以得到什么时候:

  • 设置的自动加载功能,称为callback_no_spl,与unserialize_callback_func
  • 并设置另一个自动加载功能,称为callback_spl,与spl_autoload_register

的代码看起来就像这样:

$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); 

和输出我们得到:

string 'callback_spl : a' (length=16) 

object(a)[1] 
    public 'value' => string '100' (length=3) 

其中意思是:

  • 只有spl_autoload_register注册的自动加载函数被调用
  • 它没有加载包含类的定义
  • 而且数据已经被正确去系列化的文件。


现在,只是为了好玩,如果我们试图改变中,我们设置的自动加载机的顺序?
即使用此代码部分:

$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); 

我们得到完全相同的输出前:

string 'callback_spl : a' (length=16) 

object(a)[1] 
    public 'value' => string '100' (length=3) 

这似乎表明,自动装载机,spl_autoload_register定义为比定义的一个更高的优先级与unserialize_callback_func


我还能测试什么?
哦,让我们来测试同时设置自动加载的功能,但拥有spl_autoload_register(即具有最高优先级)注册的一个不实际加载类的定义:

$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); 

这个时候,这里的输出中我们得到:

string 'callback_spl : a' (length=16) 

string 'callback_no_spl : a' (length=19) 

object(a)[1] 
    public 'value' => string '100' (length=3) 

基本上是:

  • 自动加载函数的n,其中spl_autoload_register注册已被称为
    • 它没有加载类的定义
  • 因此,与unserialize_callback_func注册的自动加载函数被调用
    • 它没有加载类的定义
    • 因此,我们已经正确地获得了未序列化的数据。


现在,让我们回过头来您发布的代码示例 - 转换为函数的名称,它会给我们这样的事情,我想:

$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); 

而且,这一次,我得到了和你一样的东西:

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) 

而且,这一次:

  • spl_autoload_register注册的函数被调用
    • 并不会加载这个类的定义
  • 然后,unserialize_callback_func注册的函数被调用
    • 它不会加载类的定义...
  • 和魔术一样,用spl_autoload_register注册的功能再次被调用!
    • 它仍然没有加载类的定义
  • 和繁荣,我们得到一个警告说,与unserialize_callback_func注册功能没有加载类的定义
    • 注意这只发生在callback_spl第二次被调用!
    • 这似乎表明,即使用unserialize_callback_func定义的函数没有加载应该有的内容,也会发生某种自动加载。

我不得不承认,这是两个很好的和有难度的 - 和我有相当不知道为什么发生这种情况,因为似乎没什么道理不...


我想这奇怪行为是与事实,这样做:

的“栈/队列”的spl_autoload_register的行为,我想,可以有一些干扰与unserialize_callback_func旧的行为...

+1

+1非常好的答案,谢谢帕斯卡尔马丁 – Michael 2011-03-11 10:33:03

+0

呃......一个TL; DR绝对是需要的! – 2017-08-14 22:12:46

相关问题