11Registering and using PHP functions
22===================================
33
4- The main goal of a PHP extension is to register new PHP functions for userland. PHP functions are complex to fully
5- understand their mechanics that hook very deep into the Zend Engine, but fortunately we don't need this knowledge
4+ The main goal of a PHP extension is to register new PHP functions for userland. PHP functions are complex to fully
5+ understand their mechanics that hook very deep into the Zend Engine, but fortunately we don't need this knowledge
66for our chapter, as the PHP extension mechanism provides many ways to abstract a lot such a complexity.
77
8- Registering and using new PHP functions in an extension is an easy step. Deeply understanding the big picture is
9- however pretty more complex. A first step :doc: `to the zend_function chapter<../internal_types/functions> ` could help
8+ Registering and using new PHP functions in an extension is an easy step. Deeply understanding the big picture is
9+ however pretty more complex. A first step :doc: `to the zend_function chapter<../internal_types/functions> ` could help
1010then.
1111
12- Obviously, you'll need to master :doc: `types<../internal_types> `, especially :doc: `zvals<../internal_types/zvals> ` and
12+ Obviously, you'll need to master :doc: `types<../internal_types> `, especially :doc: `zvals<../internal_types/zvals> ` and
1313:doc: `memory management<../memory_management> ` here. Also, know your :doc: `hooks<../extensions_design/php_lifecycle> `.
1414
1515zend_function_entry structure
1616*****************************
1717
18- Not to be confused with :doc: `the zend_function structure<../internal_types/functions> `, ``zend_function_entry `` is
18+ Not to be confused with :doc: `the zend_function structure<../internal_types/functions> `, ``zend_function_entry `` is
1919used to register functions against the engine while in an extension.
2020Here it is::
2121
@@ -44,7 +44,7 @@ return value is passed to our handler as a parameter.
4444Arguments. The ``arg_info `` variable is about declaring the API arguments our function will accept. Here again,
4545that part can be tricky to deeply understand, but we don't need to get too deep and we'll once more use macros to
4646abstract and ease arguments declaration. What you should know is that you are not required to declare any arguments
47- here for the function to work, but it is highly recommanded. We'll get back to that. Arguments are an array of
47+ here for the function to work, but it is highly recommanded. We'll get back to that. Arguments are an array of
4848``arg_info ``, and thus its size is passed as ``num_args ``.
4949
5050Then come ``flags ``. We won't detail flags in this chapter. Those are used internally, you'll find some details in the
@@ -53,9 +53,9 @@ dedicated :doc:`zend_function<../internal_types/functions>` chapter.
5353Registering PHP functions
5454*************************
5555
56- PHP functions are registered into the engine when the extension gets loaded. An extension may declare a function vector
57- into the extension structure. Functions declared by extensions are called "internal" functions, and at the opposite of
58- "user" functions (functions declared and used using PHP userland) they don't get unregistered at the end of the
56+ PHP functions are registered into the engine when the extension gets loaded. An extension may declare a function vector
57+ into the extension structure. Functions declared by extensions are called "internal" functions, and at the opposite of
58+ "user" functions (functions declared and used using PHP userland) they don't get unregistered at the end of the
5959current request: they are permanent.
6060
6161As a reminder, here is the PHP extension structure shorten for readability::
@@ -129,16 +129,16 @@ Here is the same code, but with the macros expanded, so that you can have a look
129129 (uint32_t) (sizeof(((void *)0))/sizeof(struct _zend_internal_arg_info)-1), 0 },
130130 }
131131
132- Notice how ``PHP_FUNCTION() `` expanded to a C symbol beginning by ``zif_ ``. *'zif' * stands for
133- *Zend Internal Function *, it is added to the name of your function to prevent symbol name collisions in the compilation
134- of PHP and its modules. Thus, our ``fahrenheit_to_celsius() `` PHP function uses a C handler named
135- ``zif_fahrenheit_to_celsius() ``. It is the same for nearly every PHP function. If you look for "zif_var_dump", you'll
132+ Notice how ``PHP_FUNCTION() `` expanded to a C symbol beginning by ``zif_ ``. *'zif' * stands for
133+ *Zend Internal Function *, it is added to the name of your function to prevent symbol name collisions in the compilation
134+ of PHP and its modules. Thus, our ``fahrenheit_to_celsius() `` PHP function uses a C handler named
135+ ``zif_fahrenheit_to_celsius() ``. It is the same for nearly every PHP function. If you look for "zif_var_dump", you'll
136136read the PHP ``var_dump() `` source code function, etc...
137137
138138Declaring function arguments
139139****************************
140140
141- So far so good, if :doc: `you compile<../build_system/building_extensions> ` the extension and load it into PHP, you can
141+ So far so good, if :doc: `you compile<../build_system/building_extensions> ` the extension and load it into PHP, you can
142142see with reflection that the function is present::
143143
144144 > ~/php/bin/php -dextension=pib.so --re pib
@@ -149,10 +149,10 @@ see with reflection that the function is present::
149149 }
150150 }
151151
152- But its arguments are missing. If we want to publish a ``fahrenheit_to_celsius($fahrenheit) `` function signature, we
152+ But its arguments are missing. If we want to publish a ``fahrenheit_to_celsius($fahrenheit) `` function signature, we
153153need one mandatory argument.
154154
155- What you must know is that argument declaration has nothing to do with the function internal work. That means that this
155+ What you must know is that argument declaration has nothing to do with the function internal work. That means that this
156156function could have worked if we would have written its body now. Even with no declared arguments.
157157
158158.. note :: Declaring arguments is not mandatory but highly recommanded. Arguments are used by the reflection API to get
@@ -207,7 +207,7 @@ This bunch of macros allow you to deal with every use-case.
207207 *'arginfo_[function name]' * pattern.
208208
209209So back to our ``fahrenheit_to_celsius() `` function, we declare a simple return by value function (very classical
210- use-case), with one argument called ``fahrenheit ``, not passed by reference (here again, very traditionnal ).
210+ use-case), with one argument called ``fahrenheit ``, not passed by reference (here again, very traditional ).
211211
212212That created the ``arginfo_fahrenheit_to_celsius `` symbol of type ``zend_internal_arg_info[] `` (a vector, or an array,
213213that is the same), and we must now use that back into our function declaration to attach it some args::
@@ -231,15 +231,15 @@ Ok. Here is a PHP function like you use it and declare it with the PHP language
231231
232232 function fahrenheit_to_celsius($fahrenheit)
233233 {
234- return 9/5 * $fahrenheit + 32;
234+ return 5/9 * ( $fahrenheit - 32) ;
235235 }
236236
237237 This is an easy function so that you understand things.
238238Here is what it looks like when programmed in C::
239239
240- PHP_FUNCTION(celsius_to_fahrenheit )
240+ PHP_FUNCTION(fahrenheit_to_celsius )
241241 {
242- /* code to go here */
242+ /* code to go here */
243243 }
244244
245245Macro expanded, that gives::
@@ -249,7 +249,7 @@ Macro expanded, that gives::
249249 /* code to go here */
250250 }
251251
252- Take a break and think about the majors differences.
252+ Take a break and think about the major differences.
253253
254254First strange thing, in C, the function is not expected to return anything. That's a ``void `` declared function, you
255255can't here in C return something. But we notice we receive an argument called ``return_value `` of type ``zval * ``,
@@ -289,18 +289,18 @@ float as an integer, and give it to you.
289289
290290Let's see that function::
291291
292- PHP_FUNCTION(celsius_to_fahrenheit )
292+ PHP_FUNCTION(fahrenheit_to_celsius )
293293 {
294- double c ;
294+ double f ;
295295
296- if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &c ) == FAILURE) {
297- return;
298- }
296+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &f ) == FAILURE) {
297+ return;
298+ }
299299
300- /* continue */
300+ /* continue */
301301 }
302302
303- We want to be given a double on the c variable. We then call ``zend_parse_parameters() ``.
303+ We want to be given a double on the f variable. We then call ``zend_parse_parameters() ``.
304304
305305The first argument is the number of arguments the runtime have been given. ``ZEND_NUM_ARGS() `` is a macro that tells
306306us, we then use it to tell zpp() how many arguments to read.
@@ -330,18 +330,18 @@ So far so good, we received a double. Let's now perform the math operations and
330330
331331 static double php_fahrenheit_to_celsius(double f)
332332 {
333- return ((double)5/9) * (double)(f - 32);
333+ return ((double)5/9) * (double)(f - 32);
334334 }
335335
336336 PHP_FUNCTION(fahrenheit_to_celsius)
337337 {
338- double f;
338+ double f;
339339
340- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &f) == FAILURE) {
341- return;
342- }
340+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &f) == FAILURE) {
341+ return;
342+ }
343343
344- RETURN_DOUBLE(php_fahrenheit_to_celsius(f));
344+ RETURN_DOUBLE(php_fahrenheit_to_celsius(f));
345345 }
346346
347347Returning values should be easy to you, as you know :doc: `how zvals work <../internal_types/zvals >`. You must fill-in
@@ -386,10 +386,10 @@ Let's add the opposite function: ``celsius_to_fahrenheit($celsius)``::
386386
387387 PHP_FUNCTION(celsius_to_fahrenheit)
388388 {
389- double c;
389+ double c;
390390
391391 if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &c) == FAILURE) {
392- return;
392+ return;
393393 }
394394
395395 RETURN_DOUBLE(php_celsius_to_fahrenheit(c));
@@ -427,7 +427,7 @@ Now a more complex use case, we show it in PHP before implementing it as a C ext
427427 That example helps us introduce **constants **.
428428
429429Constants are easy to manage in extensions, like they are in their userland counter-part. Constants are persistent,
430- most often, that means that they should persist their value accross requests. If you are aware of
430+ most often, that means that they should persist their value across requests. If you are aware of
431431:doc: `the PHP lifecycle<./php_lifecycle> `, you should have guessed that ``MINIT() `` is the right stage to register
432432constants against the engine.
433433
@@ -465,7 +465,7 @@ API and macros are located into
465465zend_constants.h> `_.
466466
467467The flags are mixed *OR * operation between ``CONST_CS `` (case-sensitive constant, what we want), and
468- ``CONST_PERSISTENT `` (a persistent constant, accross requests, what we want as well).
468+ ``CONST_PERSISTENT `` (a persistent constant, across requests, what we want as well).
469469
470470Now our ``temperature_converter($temp, $type = TEMP_CONVERTER_TO_CELSIUS) `` function in C::
471471
@@ -515,9 +515,9 @@ Remember to well look at `README.PARAMETER_PARSING_API <https://github.com/php/p
515515ef4b2fc283ddaf9bd692015f1db6dad52171c3ce/README.PARAMETER_PARSING_API> `_. It's not a hard API, you must familiarize
516516with it.
517517
518- We use *"d|l" * as arguments to ``zend_parse_parameters() ``. One double and optionnaly (the pipe *"|" *) one long. Take
519- care, if the optionnal argument is not provided at runtime (what ``ZEND_NUM_ARGS() `` tells us about, as a reminder),
520- then the ``&mode `` variable won't be touched by zpp(). That's why we provide a default value of
518+ We use *"d|l" * as arguments to ``zend_parse_parameters() ``. One double and optionaly (the pipe *"|" *) one long. Take
519+ care, if the optional argument is not provided at runtime (what ``ZEND_NUM_ARGS() `` tells us about, as a reminder),
520+ then the ``&mode `` variable won't be touched by zpp(). That's why we provide a default value of
521521``TEMP_CONVERTER_TO_CELSIUS `` to that variable.
522522
523523Then we use ``strpprintf() `` to build a :doc: `zend_string <../internal_types/strings/zend_strings >`, and return it into
@@ -590,14 +590,14 @@ remember one reason why we sometimes use the C language over PHP.
590590Managing references
591591*******************
592592
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 ``)
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 ``)
595595is a heap allocated ``zval `` stored into a ``zval `` container. Haha.
596596
597- So, it is not very hard to deal with those into PHP functions, as soon as you remember what references are, and what
597+ So, it is not very hard to deal with those into PHP functions, as soon as you remember what references are, and what
598598they're designed to.
599599
600- If your function accept a parameter as a reference, you must declare that in arguments signature and be passed a
600+ If your function accept a parameter as a reference, you must declare that in arguments signature and be passed a
601601reference from your ``zend_parse_parameter() `` call. Let's see that like always, with a PHP example first:
602602
603603.. code-block::php
@@ -616,9 +616,9 @@ So now in C, first we must change our ``arg_info``::
616616*1 *, passed in the ``ZEND_ARG_INFO() `` macro tells the engine that argument must be passed by reference.
617617
618618Then, 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
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
622622reference::
623623
624624 PHP_FUNCTION(fahrenheit_to_celsius)
0 commit comments