I've been reading about the commonly used interfaces of PHP from the SPL, such as Iterator
, Countable
, and ArrayAccess
. However, I don't understand exactly how they work.
Do their implementations modify the core functionality of PHP, for example overloading the []
array operator?
I've read also about the Operator extension, which provides the ability to overload other operators in the same fashion as lower level languages. Since the Operator extension clearly modifies the PHP core, I was wondering if ArrayAccess
acts in the same way behind the scenes?
I'm a tinkerer, consequently I find it difficult to use something without knowing what's under the hood.
PHP and PHP extensions are built on top of the Zend Engine. They expose the Zend Engine functionality to user-land (PHP scripts) and add features of their own, which are either exposed to user-land or to other PHP extensions.
The Zend Engine provides an object model with a way to access object dimensions (the functionality exposed by ArrayAccess
) and a general iteration mechanism that's used to iterate over objects (idem for Iterator
). This object model consists of a number of handlers that PHP and any extension can replace for a type of object (the zend object handlers). Over its object model, the Zend engine implements a standard type of objects (the "zend objects"); each object has follows the zend_object
data structure, and each class -- which is a concept that the low-level object interface doesn't know apart from providing a way to retrieve it -- by a zend_class_entry
structure).
ArrayAccess
is actually not an SPL interface; it's defined in the Zend Engine itself. The read_dimension
/write_dimension
/has_dimension
low-level handlers of zend objects are implemented in such a way that they check whether the object implements such interface and call the respective methods if that's the case (see here).
Iterator
is also not an SPL interface; it's also defined in the Zend Engine. In this case, the support for this interface is done at a slightly higher level. The low-level object handlers know nothing of object iteration; this is a property of Zend Objects. The zend_class_entry
structure has two relevant members here: the iterator_funcs
field and the get_iterator
field. These define the iterator operations and state and how to create a new iterator. For Iterator
in particular, when a class is registered with the runtime, it's checked whether it implements that interface, and if it does, the relevant fields in the zend_class_entry
variable for that class are set to native methods that bridge the native iteration interface to PHP methods. If one writes a PHP extension, one can opt by either writing a native iterator (which implements the iteration methods natively) or to, just like in user-land, implement Iterator
and write PHP methods (in this case, native PHP methods) for the several operations, like the interface describes.
The Countable
interface is the only one that's actually an SPL interface; the Zend Engine knows nothing about it. Its functionality is derived from the fact that the implementation of the count
function checks for its presence and calls the count
method if the interface exists.
The operator extension operates at a more low-level setting. At runtime, in directly writes into the memory of the Zend Engine and replaces the handlers of the opcodes PHP code compiles into (so that now e.g. the ZEND_ASSIGN_ADD
has a new native implementation, which defers to some PHP function/method the user can choose).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With