internals:engine:objects

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
internals:engine:objects [2010/12/21 18:33]
cataphract note on errors on internal constructor
internals:engine:objects [2017/09/22 13:28] (current)
Line 80: Line 80:
   * Called when an object is to be cloned (associated with usage of the ''​clone''​ operator in user space).   * Called when an object is to be cloned (associated with usage of the ''​clone''​ operator in user space).
   * Should return a ''​zend_object_value''​ that refers to a newly created object that is equal to the object referred to the passed reference. The two objects should not be identical, i.e., ''​==''​ applied to the references should return ''​true''​ but ''​===''​ should return ''​false''​. The ''​[[#​compare_objects|compare_objects]]''​ handlers must be the same since that is a requisite for ''​==''​ returning ''​true'',​ but typically, as one would want the two objects to have identical behavior, they ought to share all the handlers.   * Should return a ''​zend_object_value''​ that refers to a newly created object that is equal to the object referred to the passed reference. The two objects should not be identical, i.e., ''​==''​ applied to the references should return ''​true''​ but ''​===''​ should return ''​false''​. The ''​[[#​compare_objects|compare_objects]]''​ handlers must be the same since that is a requisite for ''​==''​ returning ''​true'',​ but typically, as one would want the two objects to have identical behavior, they ought to share all the handlers.
 +  * Zend standard object extensions can call ''​zend_objects_clone_members''​ to copy properties; this function also calls the class entry ''​clone''​ function (typically ''​%%__clone%%''​).
   * The created object should be initialized as if it had one reference.   * The created object should be initialized as if it had one reference.
   * May be ''​NULL''​ to forbid cloning.   * May be ''​NULL''​ to forbid cloning.
Line 492: Line 493:
  
 ==== Setup the Handlers Table ==== ==== Setup the Handlers Table ====
 +
 When one is implementing internal PHP classes, it is almost always undesirable to replace all of the standard handlers. The usual procedure for overriding the handlers follows these steps: When one is implementing internal PHP classes, it is almost always undesirable to replace all of the standard handlers. The usual procedure for overriding the handlers follows these steps:
  
Line 530: Line 532:
 } }
 </​code>​ </​code>​
 +
 +=== Beware of the clone_obj handler ​ ===
 +Most likely, the default ''​[[#​clone_obj|clone_obj]]''​ handler will have to be replaced because it assumes the ''​create_object''​ class entry handler is not replaced and directly allocates a standard ''​zend_object''​ data structure. Therefore, worse than the added custom fields to the object structure not being initialized (because the clone handler only knows how to so a shadow copy of the standard properties),​ these fields will not even exist because only a plain ''​zend_object''​ is allocated.
 +
 +You may also choose not to support the clone operation by setting the ''​clone_obj''​ handler to ''​NULL''​.
 +
  
 ==== Initialization of the Class Entry ==== ==== Initialization of the Class Entry ====
Line 774: Line 782:
  
     /* if there'​s an error that leaves the object in an invalid state and     /* if there'​s an error that leaves the object in an invalid state and
-     * you have to throw an exception, also destroy the $this reference*/+     * you have to throw an exception, also destroy the $this reference
 +     * The reason is that the exception may be caught in the constructor 
 +     * of the child class that's calling this constructor. ​*/
  
     if (bad_thing_happened()) {     if (bad_thing_happened()) {
Line 856: Line 866:
         sizeof object_handlers);​         sizeof object_handlers);​
     object_handlers.get_constructor = get_constructor;​     object_handlers.get_constructor = get_constructor;​
 +    object_handlers.clone_obj ​      = NULL;
  
     INIT_CLASS_ENTRY(ce,​ "​TestClass",​ ext_class_methods);​     INIT_CLASS_ENTRY(ce,​ "​TestClass",​ ext_class_methods);​
Line 899: Line 910:
  
 However, this is by far a more popular approach, since it's simple and portable -- it uses only stable parts of the API. However, this is by far a more popular approach, since it's simple and portable -- it uses only stable parts of the API.
 +
 +A variant of this strategy is to centralize the object state validation in the ''​[[#​get_method|get_method]]''​ handler and either throw a fatal error or return a method that throws an exception from the handler in case the object state is invalid. This makes it easier to fix current code without replacing the calls to ''​zend_object_store_get_object''​ in every method implementation.
  
 Finally, another option, certainly less complex but more limiting, is to make the superclass constructor final. Finally, another option, certainly less complex but more limiting, is to make the superclass constructor final.
Line 1122: Line 1135:
   - Do post-creation initialization on the new objected (the construction phase), typically through an auxiliary function.   - Do post-creation initialization on the new objected (the construction phase), typically through an auxiliary function.
  
-For instantions ​with ''​new'':​+For instantiations ​with ''​new'':​
   - Call the class entry'​s ''​create_object''​ handler.   - Call the class entry'​s ''​create_object''​ handler.
     - (see above)     - (see above)
Line 1128: Line 1141:
   - Call the PHP constructor,​ if any. Typically, the internal implementation of the constructor delegates the construction task to the same auxiliary function referred to in the last step of the list before.   - Call the PHP constructor,​ if any. Typically, the internal implementation of the constructor delegates the construction task to the same auxiliary function referred to in the last step of the list before.
  
-Stored objects should not be destroyed explicitly; in fact, the store API doesn'​t even expose a function to destroy a particular object. Instead, the destruction should be managed through the refcount. When the reference count hits 0, the store will call the object "​destruct"​ store handler (if the object construction didn't fail) and the "free object"​ handler and remove the entry from its table. See also the ''​[[#​add_ref|add_ref]]''​ and ''​[[#​del_ref|add_ref]]''​ handlers.+Stored objects should not be destroyed explicitly; in fact, the store API doesn'​t even expose a function to destroy a particular object. Instead, the destruction should be managed through the refcount. When the reference count hits 0, the store will call the object "​destruct"​ store handler (if the object construction didn't fail) and the "free object"​ handler and remove the entry from its table. See also the ''​[[#​add_ref|add_ref]]''​ and ''​[[#​del_ref|del_ref]]''​ handlers.
  
internals/engine/objects.1292956424.txt.gz · Last modified: 2017/09/22 13:28 (external edit)