I'm developing a PHP-extension, where an object method needs to return an array zval
.
The method looks like:
ZEND_METHOD(myObject, myMethod)
{
zval **myArrayProperty;
if (zend_hash_find(Z_OBJPROP_P(getThis()), "myArrayProperty", sizeof("myArrayProperty"), (void **) &myArrayProperty) == FAILURE) {
RETURN_FALSE;
}
RETURN_ZVAL(*myArrayProperty, 1, 0);
}
The code works fine and does the expected thing - it returns object's myArrayProperty
. However, I'd like to optimize the process.
myArrayProperty
stores an array, which can be quite big. And the RETURN_ZVAL()
macro duplicates that array in order to return the value. The duplication process takes good amount of time to acquire memory and copy all the array values. At the same time, the returned array is usually used for read-only operations. So a nice optimization would be to use PHP's mechanism with reference counting and do not duplicate myArrayProperty
contents. Rather I'd increase refcount
of myArrayProperty
and just return pointer to it. This is the same tactic as usually used, when working with variables in a PHP extension.
However, seems, there is no way to do it - you have to duplicate value in order to return it from a PHP extension function. Changing function signature to return value by reference, is not an option, because it links the property and returned value - i.e. changing returned value later, changes the property as well. That is not an acceptable behavior.
The inability to engage reference counting looks strange, because same code in PHP:
function myMethod() {
{
return $this->myArrayProperty;
}
is optimized by the reference counting mechanism. That's why I'm asking this question at StackOverflow in case I missed something.
So, is there a way to return an array from a function in PHP extension, without copying the array in memory?
If your function returns by-value this is only possible as of PHP 5.6 (current master) using the RETURN_ZVAL_FAST
macro:
RETURN_ZVAL_FAST(*myArrayProperty);
If your function returns by-reference (return_reference=1
in the arginfo) you can return using the following code:
zval_ptr_dtor(&return_value);
SEPARATE_ZVAL_TO_MAKE_IS_REF(myArrayProperty);
Z_ADDREF_PP(myArrayProperty);
*return_value_ptr = *myArrayProperty;
If your function returns by-value and you're on PHP 5.5 or older you can still optimize the refcount=1
case:
if (Z_REFCOUNT_PP(myArrayProperty) == 1) {
RETVAL_ZVAL(*myArrayProperty, 0, 1);
Z_ADDREF_P(return_value);
*myArrayProperty = return_value;
} else {
RETVAL_ZVAL(*myArrayProperty, 1, 0);
}
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