How does ArrayAccess work?
Asked Answered
A

1

5

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.

Aleron answered 1/1, 2011 at 16:31 Comment(0)
T
12

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).

Tester answered 1/1, 2011 at 23:12 Comment(1)
Wow, thanks Artefacto for that comprehensive response, it certainly filled in the gaps of my understanding. I definitely have much to learn.Aleron

© 2022 - 2024 — McMap. All rights reserved.