2

We have an error handler that is throwing an error: __PHP_Incomplete_Class could not be converted to string.

The error handler currently does an 'is_object' test, which oddly is false for an 'Incomplete' object. I'm attempting to adjusting the error handler, but I'm not able to get the original class name out, without parsing the re-serialized version.

<?php

$o = 'O:14:"BogusTestClass":0:{}';

$c = unserialize($o);

var_dump(
    array(
        'subject' => $c,
        'is_object' => is_object($c), // false !?!?
        'get_class' => get_class($c), // __PHP_Incomplete_Class
        'gettype' => gettype($c),     // 'object'
        'Is instance of?' => $c instanceof __PHP_Incomplete_Class, // true
        'serial' => serialize($c),
    )
);    

// Tried:

var_dump($c->__PHP_Incomplete_Class_Name);
// Error:
//   The script tried to execute a method or access a property of
//   an incomplete object


$refObj = new ReflectionObject($c);
$refProp = $refObj->getProperty('__PHP_Incomplete_Class_Name');
$refProp->setAccessible(true);
var_dump($refProp->getValue($c));
// Error:
//   ReflectionProperty::getValue(): The script tried to execute a
//   method or access a property of an incomplete object.


// This works, but is fragile, since it depends on internal behavior
// of serialize
function getBadClassName($subject)
{
    $serial = serialize($subject);
    $parts  = explode(':', $serial, 4);

    if ('O' === $parts[0] && strlen($parts[2]) -2 == $parts[1]) {
        return substr($parts[2], 1, -1);
    }
    return '-- Error --';
}

var_dump(getBadClassName($c));

Attempting to get the name of the serialized class out of the incomplete object for use in an error message.

Avoiding parsing the string, because I'm guessing string parsing will break down when extensions that redefine serialize/unserialize are used, such as http://pecl.php.net/package/igbinary or http://pecl.php.net/package/APC/3.1.7 apc.serializer hook.

rrehbein
  • 4,120
  • 1
  • 17
  • 23
  • 2
    The error is throwing an error? You divided by zero didn't you? DIDN'T YOU?! – Madara's Ghost Sep 18 '12 at 15:13
  • Error is being thrown from Symfony2's FlattenException, and would be trivial to add a bit for if incomplete object, but would like to add the missing name if possible. – rrehbein Sep 18 '12 at 15:14

2 Answers2

5

Based on a suggestion to look at

forcing access to __PHP_Incomplete_Class object properties

The property can be accessed via foreach and ArrayObject

<?php

$array = new \ArrayObject($object);
var_dump($array['__PHP_Incomplete_Class_Name']);
Community
  • 1
  • 1
rrehbein
  • 4,120
  • 1
  • 17
  • 23
0

You really can't work with the PHP incomplete class objects, and it makes sense to me that they don't count as objects since you really can't use them. The only reason for them to exist is so they can persist in the session on pages where they aren't needed.

If you actually need it, you have to include the definition of the class before the object is unserialized (and if it's in the session, before session_start). The error message even says this.

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • 1
    Your correct that in most cases, it is just a matter of fixing the auto-loader, or including the missing class(es). However, in the case I ran into, the error was triggered by a class that was refactored away coming back out of caching, rather then a failed auto-loading. The fix of course was to flush the cache, but in the mean time, we had an error on our live system due to a deploy, but an error message with little clue, due to the error triggered in the error handler. The question is about fixing the error handler, not the missing class. – rrehbein Sep 19 '12 at 18:49