Почему unserialize_callback_func требуется, когда spl_autoload_register уже используется?

ini_set('unserialize_callback_func', 'spl_autoload_call'); spl_autoload_register(array(self::getInstance(), 'autoload')); 

Зачем устанавливать spl_autoload_call как указано выше?

Я сделал тест:

 $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 

Может кто-нибудь объяснить это?

Я сделал несколько тестов, и вот заметки, которые я взял (надеюсь, это будет понятно ^^ ;; и что я не потерялся в своей собственной мысли ^^)
Примечание. Я провел тесты на 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 для регистрации функции автозагрузки, которая фактически автоматически 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 функция автозагрузки, зарегистрированная функцией spl_autoload_register
    • И на этот раз для этого потребовался файл, содержащий определение класса
  • Неусериализация прошла успешно
    • т.е. мы больше не получаем экземпляр __PHP_Incomplete_Class ,
    • мы фактически получаем экземпляр

Итак, здесь я бы сказал, что unserialize_callback_func не требуется, когда используется spl_autoload_register .

Я думаю, здесь, я как-то ответил на вопрос? Но я отправлю пару других тестов, просто для удовольствия ^^


Теперь, что, если мы попытаемся использовать unserialize_callback_func и не spl_autoload_register использовать 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) 

Итак, все работает нормально:

  • Вызывается функция обратного callback_no_spl callback_no_spl, зарегистрированная через unserialize_callback_func
    • Он загружает определение класса
  • И данные неэтериализованы должным образом
    • т.е. мы получаем экземпляр

Отправляясь немного дальше, давайте попробуем то, что мы можем получить, когда оба:

  • Установка функции автозагрузки, называемой 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) 

В основном :

  • spl_autoload_register функция автозагрузки, зарегистрированная с помощью 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 функция, зарегистрированная с помощью spl_autoload_register
    • И не загружает определение класса
  • Затем вызывается функция, зарегистрированная с помощью unserialize_callback_func
    • Он не загружает класс «defition» …
  • Как и магия, функция, зарегистрированная с помощью spl_autoload_register вызывается снова!
    • Он по-прежнему не загружает определение класса
  • И бум, мы получаем предупреждение о том, что функция, зарегистрированная с помощью unserialize_callback_func , не загружала определение класса
    • Обратите внимание, что это происходит только после callback_spl во второй раз!
    • Это, по-видимому, указывает на то, что происходит некоторая автозагрузка, даже если функция, определенная с помощью unserialize_callback_func , не загрузила то, что она должна была иметь …

Должен признаться, это так приятно и сложно – и я совершенно не понимаю, почему это происходит, поскольку это, похоже, не имеет большого смысла …

Я полагаю, что это странное поведение связано с тем, что:

  • unserialize_callback_func существует с PHP 4.2
  • в то время как spl_autoload_register существует только тогда, spl_autoload_register PHP 5.1 и __autoload были введены в PHP 5

Полагаю, что поведение «stack / queue» spl_autoload_register может иметь некоторые помехи со старым поведением unserialize_callback_func

unserialize () требует, чтобы определение класса загружалось до фактического нессериализации данных. unserialize_callback_func вызывается, когда определение класса не загружается, и spl_autoload_call пытается использовать все автозагрузчики, зарегистрированные для загрузки класса, необходимого для unserialize ().