This is an old revision of the document!
Internal Implementation Details for Property Accessors
- Version: 1.1 (to be updated prior to vote)
- Created: 2012-12-29
- Author: Clint Priest <phpdev at zerocue dot com>
- Contributors: Nikita Popov
- The changes for this RFC are available here: https://github.com/cpriest/php-src/tree/accessors
Internal Implementation
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
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.
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;
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.
Two new function flags have been defined:
#define ZEND_ACC_READONLY 0x20000000 #define ZEND_ACC_WRITEONLY 0x40000000
An additional byte was added to zend_internal_function:
zend_uchar purpose;
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:
#define ZEND_FNP_UNDEFINED 0 /* No special purpose function */ #define ZEND_FNP_PROP_GETTER 1 /* Special purpose accessor: getter */ #define ZEND_FNP_PROP_SETTER 2 /* Special purpose accessor: setter */ #define ZEND_FNP_PROP_ISSETTER 3 /* Special purpose accessor: issetter */ #define ZEND_FNP_PROP_UNSETTER 4 /* Special purpose accessor: unsetter */
* __get(), __set(), __isset() and __unset() guards were used and the functionality is the same with the new accessors.
* 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
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.
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.