rfc:propertygetsetsyntax-implementation-details

Differences

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

Link to this comparison view

Next revision
Previous revision
rfc:propertygetsetsyntax-implementation-details [2012/12/30 18:35] – created cpriestrfc:propertygetsetsyntax-implementation-details [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== Internal Implementation Details for Property Accessors ====== ====== Internal Implementation Details for Property Accessors ======
-  * Version: 1.1 (to be updated prior to vote) +  * Version: 1.2 
-  * Created2012-12-29+  * Updated2013-01-17
   * Author: Clint Priest <phpdev at zerocue dot com>   * Author: Clint Priest <phpdev at zerocue dot com>
   * Contributors: Nikita Popov   * Contributors: Nikita Popov
 +  * RFC Document: [[https://wiki.php.net/rfc/propertygetsetsyntax-v1.2|v1.2 Document]]
 +  * The code for this RFC are available here: https://github.com/cpriest/php-src/tree/accessors
  
-  * RFC Document: [[https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented|https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented]] +==== Overview ====
-  * The changes for this RFC are available here: https://github.com/cpriest/php-src/tree/accessors+
  
-===== Internal Implementation =====+The current implementation of property accessors can be thought of as properties which have their read/write/isset/unset access  
 +guarded by accessor functions, the primary changes that permit this functionality to work are all within standard zend object handling 
 +function calls.
  
-**Note: These implementation details have not been kept up with the semi-rapidly changing internal implementation and will be updated near the beginning of the voting period when all code has been completed**+The rest of the code changes are involved in compilation of the property accessor syntax, allowing for automatic implementation, etc.
  
-Accessor information is stored in a new zend_accessor_info struct.  These structures are stored in a new HashTable property in a zend_class_entry structure named accessors.  They are indexed by the hash_value of the property name and are thus quickly accessed during property resolution.+Finally few functions were added to reflection to reflect on the new features.
  
-<code c> +==== Memory Structure Changes ====
-typedef struct _zend_accessor_info { +
- zend_uint flags; +
- const char *doc_comment; +
- int doc_comment_len; +
- zend_function *getter; +
- zend_function *setter; +
- zend_function *isset; +
- zend_function *unset; +
-} zend_accessor_info; +
-</code>+
  
-Internally the accessors are implemented as ordinary functions (with appropriate access levels) with specialized names.  get/set/isset/unset for a property named $Hours would be %%__getHours()%%, %%__setHours($value)%%, %%__issetHours()%% and %%__unsetHours()%% respectively.+Accessor information is stored as an array of zend_function pointers added to the zend_property_info structure.
  
-Two new function flags have been defined: 
 <code c> <code c>
-#define ZEND_ACC_READONLY     0x20000000 +typedef struct _zend_property_info { 
-#define ZEND_ACC_WRITEONLY    0x40000000+ /* ... */ 
 + union _zend_function **accs; 
 +} zend_property_info;
 </code> </code>
  
-An additional byte was added to zend_internal_function: +The memory space is only allocated for the array of pointers if a property has accessors. 
-<code c> + 
-zend_uchar purpose; +The correct accessor is referenced by using an enum value from the following new enum:
-</code>+
  
-This was in lieu of using 4 additional flag values for which there was not room.  There are presently five states purpose can be in, they are: 
 <code c> <code c>
-#define ZEND_FNP_UNDEFINED 0 /* No special purpose function */ +/* Offsets into zend_property_info->accs */ 
-#define ZEND_FNP_PROP_GETTER 1 /* Special purpose accessor: getter */ +typedef enum { 
-#define ZEND_FNP_PROP_SETTER 2 /* Special purpose accessor: setter */ + ZEND_ACCESSOR_GET, 
-#define ZEND_FNP_PROP_ISSETTER 3 /* Special purpose accessor: issetter */ + ZEND_ACCESSOR_SET, 
-#define ZEND_FNP_PROP_UNSETTER 4 /* Special purpose accessor: unsetter */+ ZEND_ACCESSOR_ISSET, 
 + ZEND_ACCESSOR_UNSET, 
 +} zend_acc_index; 
 +#define ZEND_NUM_ACCESSORS 4
 </code> </code>
  
- * %%__get()%%%%__set()%%%%__isset()%% and %%__unset()%% guards were used and the functionality is the same with the new accessors.+The ''zend_function''s of the accessors have the ''ZEND_ACC_ACCESSOR'' flag set. 
 + 
 +==== Compilation Changes ==== 
 + 
 +During compilation if a guarded property is parsed it will create the given property, allocate the function pointer array  
 +and begin parsing the accessor code within the context of a function.   
 + 
 +Note that these functions are not methods of the class entry and are only referenced through the zend_function pointers of the  
 +property_info structurethis also means that they may not be called directly by userland codeonly through accessing the 
 +property using ordinary property access syntax. 
 + 
 +==== zend_object_handler.c Changes ==== 
 + 
 +Each of the functions that handled read/write/isset/unset functionality checks to see if the property has accessors for  
 +the property and if so checks that there is an accessor for the specific action (read/write, etcbeing performed and 
 +handles the situation accordingly. 
 + 
 + 
 +Much of the pre/post magic call code that %%__get/__set/__isset/__unset%% used was refactored and centralized into their respective zend_std_call_*() functions. 
 +The new accessors also utilize these functions so that all pre/post condition handling is the same for accessors as they are for the magics. 
 + 
 + 
 +new function flag was added ''ZEND_ACC_CALL_GUARD'' which flags a function as "being called and guarded," this was necessary to allow for parent 
 +accessors being able to be properly called. In the case of recursion with accessors a warning will be emitted if recursion is detected and that  
 +recursion is not called from the context of the validly scoped accessor. 
 + 
 + 
 +For example a get accessor is allowed to get it's own value and does not produce a warning, but instead the ordinary property access routines occur while attempts to read that property from a context other than the get accessor will emit a warning and the value will be returned as NULL. 
  
- * Error producing lines have been modified to check the function for ZEND_ACC_IS_ACCESSOR mask with more appropriate error report occurring.  For example: Cannot override final property getter TimePeriod::$Hours+ * Error producing lines have been modified to produce a useful error report.  For example: Cannot override final property getter TimePeriod::$Hours
  
 ==== Static Accessors ==== ==== Static Accessors ====
-There was no built-in mechanism to handle custom get/set/isset/unset for static properties, these were handled by catching references to static properties, checking for the existence of a static accessor and converting the compilation into a function call When a static setter is being used, the compiled code first becomes a static getter call and the zend_do_assign backpatches the op_array to become a call to the setter, as appropriate.+Static accessors were abandoned due to the unique way in which static properties are presently handledit would require significant engine changes to facilitate at this time and is 
 +left for another RFC to refactor the static property handling to bring it more in line with existing zend_object_handlers.code.
  
-This yielded the possibility that a getter call was being made while it should not be allowed (if there was no getter defined) and so pass_two() was changed to look for these non-backpatched illegal static getter calls and a compile time error is produced.+==== Tests ==== 
 +Roughly 80 additional tests were added to test the new accessors functionality, they are stored in ~/Zend/tests/accessors
  
rfc/propertygetsetsyntax-implementation-details.1356892530.txt.gz · Last modified: 2017/09/22 13:28 (external edit)