Search code examples
php-extensionphp-internalsphp-7

How to upgrade PHP function parameters work with new Zend API?


I am working on a php extension to upgrade it to PHP7, my question is about INTERNAL_FUNCTION_PARAMETERS. In the previous version it is defined as:

INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC

and in the new zend engine it is defined as:

INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value

I have php function which returns an array and it looks like this: `

PHP_FUNCTION( myFunc ){ zval* myArray;
   array_init(myArray);
   /////
   zval_ptr_dtor( &return_value );
   *return_value_ptr = myArray;
}

How should I get similar functionalities without hanvig the return_value_ptr? Should I use #define RETURN_ARR(r)?, If so how does this affect the performance?


Solution

  • In PHP 7, most pointers to zvals (zval*) in PHP 5 have become plain zval structs (zval) - instead of passing around pointers to heap-allocated (emalloc) zvals, zvals themselves are copied. Because of this, in a sense, return_value is the new return_value_ptr, because there's one less level of indirection everywhere.

    So, to go through line-by-line:


    Line 1:

    zval* myArray;
    

    In PHP 7, you don't hold a pointer to a zval, you put it directly on the stack. No external allocation. So the first line of your function should be instead:

    zval myArray;
    

    Line 2:

    array_init(myArray);
    

    array_init needs a pointer to a zval (zval*), so this should be:

    array_init(&myArray);
    

    Line 4:

    zval_ptr_dtor( &return_value );
    

    Again, PHP 7 removes a level of indirection here. It would just be this now:

    zval_dtor(return_value);
    

    However, you don't need this line in PHP 7. The zval doesn't need deallocating (in fact you can't deallocate it), you can simply overwrite it. You would need to use zval_dtor(); if the zval contained a pointer to a string, array, or some other heap-allocated object, though. But in this case it's just a null, so you don't need to run it. Carrying on:


    Line 5:

    *return_value_ptr = myArray;
    

    This should now be:

    *return_value = myArray;
    

    However, while you can directly overwrite return_value here, it is recommended to use the ZVAL_COPY_VALUE macro for this:

    ZVAL_COPY_VALUE(return_value, &myArray);
    

    Even better, you could use RETVAL_ZVAL which is a shortcut for setting the return value:

    RETVAL_ZVAL(&myArray);
    

    I should point out that you probably don't need the myArray zval in this case, as you can store the array in the return_value directly and save you having to copy it later. Another thing to bear in mind is that you should probably handle parameters. If you don't take any, zend_parse_parameters_none(); is sufficient.

    I suggest reading the phpng upgrading guide and the internals upgrading guide.