Я пишу модуль для php cms. В функции (обратном вызове) я могу получить доступ к объекту, который поступает из кода рамки.
Этот объект имеет тип __PHP_Incomplete_Class
потому что необходимый заголовочный файл не включается до начала сеанса. Я не могу включить его без взлома кода cms cms.
Интересно, возможно ли вообще получить доступ к свойствам объекта (приведение в массив не работает). Я спрашиваю об этом, потому что я вижу значения с помощью var_dump()
но используя $object->var
я всегда получаю null.
Эта проблема добавляется, когда вы не сериализуете объект класса, который еще не был включен. Например, если вы вызываете session_start перед включением класса.
К объекту PHPIncompleteClass нельзя получить доступ напрямую, но это нормально с foreach, serialize и gettype. Вызов is_object с объектом PHPIncompleteClass приведет к ошибке.
Итак, если вы обнаружите объект __PHP_Incomplete_Class в своем сеансе, и вы включили свой класс после session_load, вы можете использовать эту функцию:
function fixObject (&$object) { if (!is_object ($object) && gettype ($object) == 'object') return ($object = unserialize (serialize ($object))); return $object; }
Это приведет к использованию полезного объекта:
fixObject($_SESSION['member']);
Я нашел этот хак, который позволит вам бросить объект:
function casttoclass($class, $object) { return unserialize(preg_replace('/^O:\d+:"[^"]++"/', 'O:' . strlen($class) . ':"' . $class . '"', serialize($object))); }
С http://blog.adaniels.nl/articles/a-dark-corner-of-php-class-casting/
Таким образом, вы можете:
$obj = casttoclass('stdClass', $incompleteObject);
а затем доступ к свойствам как обычно.
Вы также можете определить unserialize_callback_func
в файле конфигурации .htaccess / Apache. Таким образом, вам не нужно будет взломать любой PHP, но вы можете включить файл по требованию.
В качестве дополнения здесь представлена моя версия функции fix_object (): Основное изменение – это шаг 3 в коде: Сделать все свойства общедоступными .
Когда PHP сериализует объект, все частные и защищенные свойства имеют префикс с двумя нулевыми байтами! Эти нулевые байты являются фактической причиной, почему свойство не может быть доступно с помощью $obj->key
потому что на самом деле это что-то вроде $obj->{NULL*NULL}key
.
/** * Takes an __PHP_Incomplete_Class and casts it to a stdClass object. * All properties will be made public in this step. * * @since 1.1.0 * @param object $object __PHP_Incomplete_Class * @return object */ function fix_object( $object ) { // preg_replace_callback handler. Needed to calculate new key-length. $fix_key = create_function( '$matches', 'return ":" . strlen( $matches[1] ) . ":\"" . $matches[1] . "\"";' ); // 1. Serialize the object to a string. $dump = serialize( $object ); // 2. Change class-type to 'stdClass'. $dump = preg_replace( '/^O:\d+:"[^"]++"/', 'O:8:"stdClass"', $dump ); // 3. Make private and protected properties public. $dump = preg_replace_callback( '/:\d+:"\0.*?\0([^"]+)"/', $fix_key, $dump ); // 4. Unserialize the modified object again. return unserialize( $dump ); }
var_dump
не отобразит эти NULL байтовые префиксы, но вы можете увидеть их с помощью этого кода:
class Test { private $AAA = 1; protected $BBB = 2; public $CCC = 3; } $test = new Test(); echo json_encode( serialize( $test ) ); // Output: // "O:4:\"Test\":3:{s:9:\"\u0000Test\u0000AAA\";i:1;s:6:\"\u0000*\u0000BBB\";i:2;s:3:\"CCC\";i:3;}" $test2 = fix_object( $test ); echo json_encode( serialize( $test2 ) ); // Output: // "O:8:\"stdClass\":3:{s:3:\"AAA\";i:1;s:3:\"BBB\";i:2;s:3:\"CCC\";i:3;}"
Там вы видите:
NULL + classname + NULL
NULL + "*" + NULL
Если вам просто нужно получить доступ к исходным данным (например, переменным класса) из объекта PHP_Incomplete_Class, вы можете использовать foreach hack, или вы также можете:
$result_array = (array)$_SESSION['incomplete_object_index']; echo $result_array['desired_item'];
Я прочитал много предложений о том, как исправить неполные классные объекты, и мне действительно нужно было самостоятельно решить эти проблемы в проекте электронной коммерции.
Одно из предложений, которое я нашел, – просто использовать json_decode / json_encode для преобразования незавершенных классов без предварительной загрузки. Однако я не хотел рисковать этим, если есть более старые версии PHP, которые зависят, например, от PECL, описанного по адресу http://php.net/manual/en/function.json-encode. php – поэтому мне, наконец, удалось сделать свое собственное решение.
Тем не менее, код является способом получения данных из объекта должным образом, поэтому он может не соответствовать всем потребностям – и в первую очередь он будет использовать json-решение, если он доступен в среде и не подходит для ручной обработки если нужно.
Он также работает рекурсивно, что в моем случае необходимо, чтобы сохранить весь массив.
/** * Convert a object to a data object (used for repairing __PHP_Incomplete_Class objects) * @param array $d * @return array|mixed|object */ function arrayObjectToStdClass($d = array()) { /** * If json_decode and json_encode exists as function, do it the simple way. * http://php.net/manual/en/function.json-encode.php */ if (function_exists('json_decode') && function_exists('json_encode')) { return json_decode(json_encode($d)); } $newArray = array(); if (is_array($d) || is_object($d)) { foreach ($d as $itemKey => $itemValue) { if (is_array($itemValue)) { $newArray[$itemKey] = (array)$this->arrayObjectToStdClass($itemValue); } elseif (is_object($itemValue)) { $newArray[$itemKey] = (object)(array)$this->arrayObjectToStdClass($itemValue); } else { $newArray[$itemKey] = $itemValue; } } } return $newArray; }
Поместите session_start () после вашего требования к классу объекта, который вы пытаетесь прочитать с СЕССИИ