ClassesClasses are similar to functions in that, like functions, they are stashed in their own global symbol table; but they are more complex than functions. Whereas functions are similar to scripts (possessing the same instruction set), classes are like a miniature version of the entire execution scope. A class is represented by a zend_class_entry, like this: struct _zend_class_entry { char type; char *name; zend_uint name_length; struct _zend_class_entry *parent; int refcount; zend_bool constants_updated; zend_uint ce_flags; HashTable function_table; HashTable default_properties; HashTable properties_info; HashTable class_table; HashTable *static_members; HashTable constants_table; zend_function_entry *built-in_functions; union _zend_function *constructor; union _zend_function *destructor; union _zend_function *clone; union _zend_function *_ _get; union _zend_function *_ _set; union _zend_function *_ _call; /* handlers */ zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC); zend_class_entry **interfaces; zend_uint num_interfaces; char *filename; zend_uint line_start; zend_uint line_end; char *doc_comment; zend_uint doc_comment_len; }; Like the main execution scope, a class contains its own function table (for holding class methods), and its own constants table. The class entry also contains a number of other items, including tables for its attributes (for example, default_properties, properties_info, static_members) as well as the interfaces it implements, its constructor, its destructor, its clone, and its overloadable access functions. In addition, there is the create_object function pointer, which, if defined, is used to create a new object and define its handlers, which allow for fine-grained control of how that object is accessed. One of the major changes in PHP 5 is the object model. In PHP 4, when you create an object, you are returned a zval whose zvalue_value looks like this: typedef struct _zend_object { zend_class_entry *ce; HashTable *properties; } zend_object; This means that zend_objects in PHP 4 are little more than hashtables (of attributes) with a zend_class_entry floating around to hold its methods. When objects are passed to functions, they are copied (as all other variable types are), and implementing controls of attribute accessors is extremely hackish. In PHP 5, an object's zval contains a zend_object_value, like this: struct _zend_object_value { zend_object_handle handle; zend_object_handlers *handlers; }; The zend_object_value in turn contains a zend_object_handle (an integer that identifies the location of the object in a global object storeeffectively a pointer to the object proper) and a set of handlers, which regulate all accesses to the object. This intrinsically changes the way that objects are handled in PHP. In PHP 5, when an object's zval is copied (as happens on assignment or when passed into a function), the data is not copied; another reference to the object is created. These semantics are much more standard and correspond to the object semantics in Java, Python, Perl, and other languages. The Object HandlersIn PHP 5 it is possible (in the extension API) to control almost all access to an object and its properties. A handler API is provided that implements the following access handlers: typedef struct _zend_object_handlers { /* general object functions */ zend_object_add_ref_t add_ref; zend_object_del_ref_t del_ref; zend_object_delete_obj_t delete_obj; zend_object_clone_obj_t clone_obj; /* individual object functions */ zend_object_read_property_t read_property; zend_object_write_property_t write_property; zend_object_read_dimension_t read_dimension; zend_object_write_dimension_t write_dimension; zend_object_get_property_ptr_ptr_t get_property_ptr_ptr; zend_object_get_t get; zend_object_set_t set; zend_object_has_property_t has_property; zend_object_unset_property_t unset_property; zend_object_has_dimension_t has_dimension; zend_object_unset_dimension_t unset_dimension; zend_object_get_properties_t get_properties; zend_object_get_method_t get_method; zend_object_call_method_t call_method; zend_object_get_constructor_t get_constructor; zend_object_get_class_entry_t get_class_entry; zend_object_get_class_name_t get_class_name; zend_object_compare_t compare_objects; zend_object_cast_t cast_object; } zend_object_handlers; We'll explore each handler in greater depth in Chapter 22, "Extending PHP: Part II," where you'll actually implement extension classes. In the meantime, you just need to know that the handler names offer a relatively clear indication as to what they do. For example, add_ref is called whenever a reference to an object is added: $object2 = $object; and compare_objects is called whenever two objects are compared by using the is_equal operator: if($object2 = = $object) {} Object CreationIn the Zend Engine version 2, object creation happens in two phases. When you call this: $object = new ClassName; a new zend_object is created and placed in the object store, and a handle to it is assigned to $object. By default (as happens when you instantiate a userspace class), the object is allocated by using the default allocator, and it is assigned the default access handlers. Alternatively, if the class's zend_class_entry has its create_object function defined, that function is called to handle the allocation of the object and returns the array of zend_object_handlers for that object. This level of control is especially useful if you need to override the basic operations of an object and if you need to store resource data in an object that should not be touched by the normal memory management mechanisms. The Java and mono extensions both use these facilities to allow PHP to instantiate and access objects from these other language. Only after the zend_object_value is created is the constructor called on the object. Even in extensions, the constructor (and destructor and clone) are "normal" zend_functions. They do not alter the object's access handlers, which have already been established. Other Important StructuresIn addition to the function and class tables, there are a few other important global data structures worth mentioning. Knowledge of how these work isn't terribly important for a user of PHP, but it can be useful if you want to modify how the engine itself works. Most of these are elements of either the compiler_globals struct or the executor_globals struct and are most often referenced in the source via the macros CG() and EG(), respectively. These are some of the global data structures you should know about:
This is just a selection of the globals set in executor_globals and compiler_globals. The globals listed here were chosen either because they are used in interesting optimizations in the engine (the just-in-time population of autoglobals) or because you will want to interact with them in extensions (such as resource lists).
|