Except for a few & quot; previews & quot;, all the extended functions you have processed so far are simple and only return results. however, most functions do not have only one purpose. you usually pass some parameters and want to receive useful responses based on values and other additional processing. statement of Rights
This translation can be freely transmitted without restrictions without profit.
Except for a few "previews", all the extended functions you have processed so far are simple and only return results. however, most functions do not have only one purpose. you usually pass some parameters and want to receive useful responses based on values and other additional processing.
Automatic type conversion of zend_parse_parameters ()
Like the return values you saw in the previous chapter, the parameter values are also centered on inter-access to zval references. the simplest way to obtain the zval * values is to use the zend_parse_parameters () function.
Calling zend_parse_parameters () is almost always followed by the ubiquitous TSRMLS_CC using the ZEND_NUM_ARGS () macro. ZEND_NUM_ARGS () indicates the number of actually passed parameters of the int type. because zend_parse_parameters () internal working method, you may not need to know this value directly, so now you only need to pass it.
The next parameter of zend_parse_parameters () is the format string parameter. it is a character sequence consisting of the basic type description characters supported by the Zend Engine and is used to describe the function parameters to be accepted. the following table lists the basic types of characters:
The remaining parameters of zend_parse_parameters () depend on the type description specified in your format string. for simple types, the basic types of the C language are directly referred. for example, the long data type is solved as follows:
PHP_FUNCTION(sample_getlong) { long foo; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &foo) == FAILURE) { RETURN_NULL(); } php_printf("The integer value of the parameter you " "passed is: %ld\n", foo); RETURN_TRUE; }
Although the storage space of integer and long is usually the same, they are not completely consistent. if you try to dereference an int type data to the long * parameter, unexpected results may occur, especially on the 64-bit platform. therefore, use the data types listed in the following table strictly.
Note that all other complex types are actually parsed to simple zval. the reason for doing so is the same as not using the RETURN _ * () macro to RETURN complex data types. these structures cannot be simulated in the C space. what zend_parse_parameters () can do for your function is to ensure that the zval * you receive is of the correct type. if needed, it will even perform implicit type conversion, such as converting an array to an object of stdClass.
The s and O types must be described separately, because they require two parameters for one call. in chapter 10th "php4 objects" and Chapter 11th "php5 objects", you will learn more about O. for the s type, we extend the sample_hello_world () function in chapter 5th "your first extension" so that it can greet the specified person.
Function sample_hello_world ($ name) {echo "Hello $ name! \ N ";}/* in C, you will use the zend_parse_parameters () function to accept a string */PHP_FUNCTION (sample_hello_world) {char * name; int name_len; if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "s", & name, & name_len) ==failure) {RETURN_NULL ();} php_printf ("Hello"); PHPWRITE (name, name_len); php_printf ("! \ N ");}
The zend_parse_parameters () function may fail because too few parameters passed by the function cannot meet the format string, or because a parameter cannot be converted to the request type. in this case, it will automatically output the error message, so your extension does not need to do so.
To request more than 1 parameter, you need to expand the format string, including other characters, and press the other parameters following the zend_parse_parameters () call to stack. parameters are the same as their behaviors defined in the user space function. they are parsed from left to right.
function sample_hello_world($name, $greeting) { echo "Hello $greeting $name!\n"; } sample_hello_world('John Smith', 'Mr.'); Or: PHP_FUNCTION(sample_hello_world) { char *name; int name_len; char *greeting; int greeting_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &greeting, &greeting_len) == FAILURE) { RETURN_NULL(); } php_printf("Hello "); PHPWRITE(greeting, greeting_len); php_printf(" "); PHPWRITE(name, name_len); php_printf("!\n"); }
In addition to the basic type, there are 3 metacharacters for modifying the parameter processing method, as shown in the following table:
Optional parameter
Let's take a look at the sample of the revised version sample_hello_world (). The next step is to add an optional $ greeting parameter:
function sample_hello_world($name, $greeting='Mr./Ms.') { echo "Hello $greeting $name!\n"; }
Sample_hello_world () can now be called with only the $ name parameter or two parameters at the same time.
sample_hello_world('Ginger Rogers','Ms.'); sample_hello_world('Fred Astaire');
When the second parameter is not passed, the default value is used. in C language implementation, optional parameters are also specified in a similar way.
To complete this function, we need to use the pipe character (|) in the zend_parse_parameters () format string ). parameters on the left of the pipeline operator are parsed from the call stack. if the parameters on the right of all pipeline operators are not provided in the call stack, they are not modified (parameters corresponding to the zend_parse_parameters () format string ). for example:
PHP_FUNCTION (sample_hello_world) {char * name; int name_len; char * greeting = "Mr. /Mrs. "; int greeting_len = sizeof (" Mr. /Mrs. ")-1;/* if the second parameter is not passed during the call, greeting and greeting_len remain unchanged. */if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "s | s", & name, & name_len, & greeting, & greeting_len) = FAILURE) {RETURN_NULL ();} php_printf ("Hello"); PHPWRITE (greeting, greeting_len); php_printf (""); PHPWRITE (n Ame, name_len); php_printf ("! \ N ");}
The initial value of an optional parameter is not modified unless the value of an optional parameter is provided during the call. Therefore, it is important to set the initial default value for an optional parameter. in most cases, its initial default value is NULL/0. However, in the example above, the default value is other meaningful values.
IS_NULL Vs. NULL
Every zval, even a very simple IS_NULL type, occupies a small memory space. therefore, it requires some (CPU) clock cycles to allocate memory space, initialize the value, and finally release it when it is no longer needed.
For many functions, it is not important to use the NULL parameter in the call space to mark the parameter. Therefore, this processing is meaningless. fortunately, zend_parse_parameters () allows the parameter to be marked as "allow NULL". if a format description character is followed by an exclamation point (!), If the corresponding parameter is NULL, set zend_parse_parameters () to a true NULL pointer. consider the following two pieces of code: one with this modifier and the other:
PHP_FUNCTION(sample_arg_fullnull) { zval *val; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &val) == FAILURE) { RETURN_NULL(); } if (Z_TYPE_P(val) == IS_NULL) { val = php_sample_make_defaultval(TSRMLS_C); } ... PHP_FUNCTION(sample_arg_nullok) { zval *val; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &val) == FAILURE) { RETURN_NULL(); } if (!val) { val = php_sample_make_defaultval(TSRMLS_C); } ...
The code of these two versions is actually no different. The former seems to require more processing time on the surface. Generally, this feature is not very useful, but it is best to know that this is the case.
Forced isolation
When a variable is passed to a function, whether it is referenced or not, its refcount must be at least 2. one is the variable itself, and the other is the copy of the variable passed to the function. therefore, before zval is modified (if the zval parameter is passed in directly), it is very important to separate it from its non-reference set.
If there is no "/" format modifier, it will be a monotonous task. this format modifier automatically isolates all referenced and passed value parameters copied during write, so that you can do whatever you want in your function. like the NULL mark, this modifier is placed after the format description character to be modified. the same as the NULL flag, you may not know where you really want to use it.
Zend_get_arguments ()
If the code you are designing is scheduled to work on a very old php version, or you have a function that only requires zval *, you can consider using the zend_get_parameters () API call.
The zend_get_parameters () call is a little different from the corresponding new version. first, it does not automatically perform type conversion, but all expected parameters are zval * data types. below is the simplest use of zend_get_parameters:
PHP_FUNCTION(sample_onearg) { zval *firstarg; if (zend_get_parameters(ZEND_NUM_ARGS(), 1, &firstarg) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected at least 1 parameter."); RETURN_NULL(); } /* Do something with firstarg... */ }
Second, you may have noticed that it needs to manually process the error message. zend_get_parameters () does not output the error text when it fails. it also lags behind in processing optional parameters. if you want it to capture four parameters, it is best to provide it with at least four parameters, otherwise it may return FAILURE.
Finally, unlike parse, this get variant automatically isolates all reference sets copied during write. if you want to skip automatic isolation, you must use its sibling interface: zend_get_parameters_ex ().
In addition to not isolating the copy set during write, zend_get_parameters_ex () returns the zval ** pointer instead of the direct zval *. their differences may not be known until you use them, but they are very similar in the end:
PHP_FUNCTION(sample_onearg) { zval **firstarg; if (zend_get_parameters_ex(1, &firstarg) == FAILURE) { WRONG_PARAM_COUNT; } /* Do something with firstarg... */ }
Note that the ZEND_NUM_ARGS () parameter is not required for the _ ex version. this is because the version of _ ex is too late, and Zend engine does not need this parameter at that time.
In this example, you also use the WRONG_PARAM_COUNT Macro, which is used to handle the display of the E_WARNING error message.
Process any number of parameters
There are also two zend_get_parameters () family functions used to solve the zval * and zval * pointer sets. they are suitable for reference scenarios where many parameters or runtime know the number of parameters.
Consider the var_dump () function, which is used to display any number of variables passed to it:
PHP_FUNCTION (var_dump) {int I, argc = ZEND_NUM_ARGS (); zval *** args; args = (zval ***) safe_emalloc (argc, sizeof (zval **), 0); if (ZEND_NUM_ARGS () = 0 | zend_get_parameters_array_ex (argc, args) = FAILURE) {efree (args); WRONG_PARAM_COUNT;} for (I = 0; IHere, var_dump () pre-allocates a zval ** pointer vector of the number of parameters passed to the function. then, zend_get_parameters_array_ex () is used to spread the parameters to this vector at a time. as you may guess, there is another version of this function: zend_get_parameters_array (). They have only one difference: automatic isolation, and zval * instead of zval ** is returned **, ZEND_NUM_ARGS () must be passed in the first parameter ().
Parameter information and type suggestion
The previous chapter briefly introduced the concept of using the parameter information structure of Zend Engine 2 for type suggestion. we should remember that this feature is intended for ZE2 (Zend Engine 2) and is unavailable for ZE1 (Zend Engine 1) of php4.
We start from the parameter information structure of ZE2 again. each parameter information starts with the ZEND_BEGIN_ARG_INFO () or ZEND_BEGIN_ARG_INFO_EX () macro, followed by zero or multiple ZEND_ARG _ * INFO () rows, and ends with the call of ZEND_END_ARG_INFO.
The definition and basic usage of these macros can be found in the reference and pass-through section in the compilation phase of chapter 6th "return value.
Suppose you want to implement the count () function again, you may need to create the following function:
PHP_FUNCTION(sample_count_array) { zval *arr; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) { RETURN_NULL(); } RETURN_LONG(zend_hash_num_elements(Z_ARRVAL_P(arr))); }
Zend_parse_parameters () will do a lot of work to ensure that the function passed to you is a real array. however, if you use the zend_get_parameters () function or a sibling function, you need to perform type check in the function. of course, you can also use type hint! Define the following arg_info structure:
static ZEND_BEGIN_ARG_INFO(php_sample_array_arginfo, 0) ZEND_ARG_ARRAY_INFO(0, "arr", 0) ZEND_END_ARG_INFO()
And use it when declaring the function in your php_sample_function structure:
PHP_FE(sample_count_array, php_sample_array_arginfo)
In this way, the job of type check is handed over to the Zend Engine. at the same time, you have given your parameter a name (arr), which can be used when an error message is generated. This makes it easier to track problems when errors occur in scripts using your API.
When introducing the parameter information structure for the first time in chapter 6th, you may have noticed the object, or you can use the ARG_INFO macro to input row type hint. you only need to add an additional parameter after the parameter name to describe the type name (class name)
static ZEND_BEGIN_ARG_INFO(php_sample_class_arginfo, 0) ZEND_ARG_OBJECT_INFO(1, "obj", "stdClass", 0) ZEND_END_ARG_INFO()
Note that the first parameter (by_ref) is set to 1. generally, this parameter is not very important to objects, because all objects in ZE2 are referenced by default, and their copying must be implemented explicitly through clone. you can force clone within a function call, but it is completely different from the force reference.
Because when zend. when you Mark ze1_compatiblity_mode, you may be concerned with the by_ref setting of a row in ZEND_ARG_OBJECT_INFO. in this special case, the object may still pass a copy instead of a reference. because you may need a real reference when processing an object, you don't have to worry about the impact of setting this tag.
Do not forget that there is an allow_null option in the macro for array and object parameter information. for details about allowing NULL, see the reference to pass value in the compilation phase of the previous chapter.
Of course, using parameter information for type suggestion is only supported in ZE2. if you want to make the extension compatible with php4, you need to use zend_get_parameters (), in this way, you can only put the type verification in the function, manually test Z_TYPE_P (value) or use the convert_to_type () method shown in chapter 2nd to perform automatic type conversion.
Summary
Now you may already have a bit of dirty data at hand. the Function Code for communicating with the user space is implemented through simple input/output functions. I have a deep understanding of zval's reference counting system and learned how to pass control variables to your internal function methods and timing.
In the next chapter, we will learn about the array data type and how to map the array representation of a user space to the internal HashTable implementation. in addition, we will see a large number of optional Zend and php api functions, which are used to manipulate these complex structures.
The above is [Translation] [php extension development and embedded] Chapter 7th-content of parameters accepted. For more information, see PHP Chinese website (www.php1.cn )!