When Objects Aren’t

When unserializing an object whose class definition is not present, PHP returns an instance of the special type, __PHP_Incomplete_Class, which issues notices if you attempt to call a method or access a property.

For example, this code produces the following:

andrew@fake:~$ php incomplete.php
object(__PHP_Incomplete_Class)#1 (2) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(4) "test"
  ["name"]=>
  string(2) "hi"
}

Notice: main(): The script tried to execute a method or access a property of an
incomplete object. Please ensure that the class definition "test" of the object you
are trying to operate on was loaded _before_ unserialize() gets called or provide
a __autoload() function to load the class definition  in /home/andrew/test2.php
on line 7
NULL

Interestingly, the is_object method returns false when given an instance of __PHP_Incomplete_Class. This seems to be in contradiction with var_dump (as evidenced above), gettype, and get_class, all of which return values indicating that the incomplete class is a normal object.

This was reported as bug 19842 way back in 2002, but didn’t seem to be considered a problem. (The suggested solution was simply to have all class definitions present before unserializing that object.)

To be fair, this behavior of is_object is documented in the notes section of its manual page. It also appears to be intentional, judging from this section in ext/standard/type.c, determining whether a variable is an object:

   220                          if (!strcmp(ce->name, INCOMPLETE_CLASS)) {
   221                                  RETURN_FALSE;
   222                          }

That said, it’s a little confusing when you first run into it, and means that if you’re examining a session for which you don’t have all the class definitions (writing tools outside of your application, for instance), it’s just a little bit harder to determine which variables within the session are objects.

The workaround, of course, is easy, given that most other methods treat the object as an object: $is_object = (get_class($o) !== FALSE);.

Leave a Reply