17. Overriding Object Handlers
If you remember, each object keeps an object handlers table. We started to use it in the previous chapter on embedding C data.
There are many different handlers, and all of them can be overridden to change object behavior. For example:
- ArrayObject overrides read/write/has/unset_dimension handlers to make an object behave as an array.
- ext/simplexml allows traversing XML tree through both property and dimension handlers.
- ext/ffi calls native functions through get_method handler etc.
We will override get_debug_info handler to make var_dump() print the value of our C factor field. This method takes the “object” argument and returns a HashTable with properties to zvals that are going to be displayed. The default implementation returns a real PHP properties table, but we don’t have any PHP properties. Instead, we construct a new one and add the value of C factor, using the magic name “{factor}”. We also specify that this is not the real properties table, but a temporary table, that should be freed after printing.
static HashTable* scaler_get_debug_info(zval *object, int *is_temp)
{
scaler_t *scaler = OBJ_SCALER(object);
HashTable *ret = zend_new_array(1);
zval tmp;
ZVAL_LONG(&tmp, scaler->factor);
zend_hash_str_add(ret, “{factor}”, sizeof(“{factor}”)-1, &tmp);
*is_temp = 1;
return ret;
}
Of course, we have to override the default value of get_debug_info handler, of Scaler class, by our own.
memcpy(&scaler_object_handlers, &std_object_handlers,
sizeof(zend_object_handlers));
scaler_object_handlers.offset = XtOffsetOf(scaler_t, std);
scaler_object_handlers.get_debug_info = scaler_get_debug_info;
zend_declare_class_constant_long(scaler_class_entry,
“DEFAULT_FACTOR”, sizeof(“DEFAULT_FACTOR”)-1, DEFAULT_SCALE_FACTOR);
Works without problems:
$ php -r ‘$o = new Scaler(4); $x = 5; $o->scale($x); var_dump($x,$o);’
int(20)
object(Scaler)#1 (1) {
[“{factor}”]=>
int(4)
}