Skip to content

Commit ee7dd70

Browse files
author
Julien Pauli
committed
Function args as references
1 parent bbe03ef commit ee7dd70

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

Book/php7/extensions_design/php_functions.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ But we don't need to have a look at the details here. Let's explain the crucial
273273
the stack, to know until when you should end reading them.
274274
* Everything goes by the ``zend_execute_data *execute_data`` you received as argument. But we can't detail that now.
275275

276+
Parsing parameters : zend_parse_parameters()
277+
--------------------------------------------
278+
276279
To read arguments, welcome ``zend_parse_parameters()`` API (called 'zpp').
277280

278281
.. note:: While programming PHP functions in C extensions, you receive PHP function arguments thanks to the
@@ -583,3 +586,63 @@ Here, the C part will be faster, as you don't call a PHP function in the loop fo
583586
inlined by the compiler) C function, which is orders of magnitude faster and requires tons less of low-level CPU
584587
instructions to run. It's not about that little demo function needs so much love in code performance, it's just to
585588
remember one reason why we sometimes use the C language over PHP.
589+
590+
Managing references
591+
*******************
592+
593+
Now let's go to play with PHP references. You've learnt from :doc:`the zval chapter <../internal_types/zvals>` that
594+
references are a special trick used into the engine. As a reminder, a reference (by that we mean a ``&$php_reference``)
595+
is a heap allocated ``zval`` stored into a ``zval`` container. Haha.
596+
597+
So, it is not very hard to deal with those into PHP functions, as soon as you remember what references are, and what
598+
they're designed to.
599+
600+
If your function accept a parameter as a reference, you must declare that in arguments signature and be passed a
601+
reference from your ``zend_parse_parameter()`` call. Let's see that like always, with a PHP example first:
602+
603+
.. code-block::php
604+
605+
function fahrenheit_to_celsius_by_ref(&$fahreinheit)
606+
{
607+
$fahreinheit = 9/5 * $fahrenheit + 32;
608+
}
609+
610+
So now in C, first we must change our ``arg_info``::
611+
612+
ZEND_BEGIN_ARG_INFO_EX(arginfo_fahrenheit_to_celsius, 0, 0, 1)
613+
ZEND_ARG_INFO(1, fahrenheit)
614+
ZEND_END_ARG_INFO();
615+
616+
*1*, passed in the ``ZEND_ARG_INFO()`` macro tells the engine that argument must be passed by reference.
617+
618+
Then, when we receive the argument, we use the *"z/"* argument type, to tell that we want to be given it as a ``zval *``.
619+
As we did hint the engine about the fact that it should pass us a reference, we'll be given a reference into that zval,
620+
aka it will be of type ``IS_REFERENCE``. We just need to dereference it (that is to fetch the zval stored into the
621+
zval), and modify it as-is, as the expected behavior of references is that you must modify the value carried by the
622+
reference::
623+
624+
PHP_FUNCTION(fahrenheit_to_celsius)
625+
{
626+
double result;
627+
zval *param;
628+
629+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/", &param) == FAILURE) {
630+
return;
631+
}
632+
633+
ZVAL_DEREF(param);
634+
convert_to_double(param);
635+
636+
ZVAL_DOUBLE(param, php_fahrenheit_to_celsius(Z_DVAL_P(param)));
637+
}
638+
639+
Done.
640+
641+
We used *"z/"*. If you read the `zpp readme <https://github.com/php/php-src/blob/
642+
ef4b2fc283ddaf9bd692015f1db6dad52171c3ce/README.PARAMETER_PARSING_API>`_, you'll notice that the *"/"* tells the engine
643+
to separate the value into the zval.
644+
645+
Remember that the zval is just a container, it could carry f.e an array (*zend_array*) and that latter could be shared
646+
elsewhere in the engine which would not expect it to be changed.
647+
648+
.. note:: The default ``return_value`` value is ``NULL``. If we don't touch it, the function will return PHP's ``NULL``.

0 commit comments

Comments
 (0)