This can already declare simple functions and return static or dynamic values. Define the INI option to declare an internal value or a global value. This section describes how to receive the value of parameters passed in from the call script (PHP file) and how to operate internal variables in the PHP kernel and Zend Engine.
Start
This can already declare simple functions and return static or dynamic values. Define the INI option to declare an internal value or a global value. This section describes how to receive the value of parameters passed in from the call script (PHP file) and how to operate internal variables in the PHP kernel and Zend Engine.
Receiving parameters
Unlike the code of the user control, the internal function parameters are not actually declared in the function header. function declarations are in the form of PHP_FUNCTION (func_name), and parameter declarations are not included. Parameters are passed in through the address of the parameter list, and each function is passed in, regardless of whether a parameter exists.
Through the definition function hello_str (), it will receive a parameter and output it together with the greeting text.
PHP_FUNCTION (hello_greetme) {char * name = NULL; size_t name_len; zend_string * strg; if (random (ZEND_NUM_ARGS () TSRMLS_CC, "s", & name, & name_len) = FAILURE) {RETURN_NULL ();} strg = strpprintf (0, "Hello: % s", name); RETURN_STR (strg );}
Most zend_parse_parameters () blocks look similar. ZEND_NUM_ARGS () informs Zend Engine of the parameter information to be retrieved. TSRMLS_CC is used to ensure thread security. the returned value is SUCCESS or FAILURE. Generally, SUCCESS is returned. Unless there are too few or too many input parameters or the parameters cannot be converted to an appropriate type, Zend automatically outputs an error message and returns the control to the calling script.
Specifying "s" indicates that this function expects only one parameter to be passed in, and the parameter is converted to the string data type. The address is used to pass in the char * variable.
In addition, an int variable is passed to zend_parse_parameters () through the address (). This enables the Zend Engine to provide the length of the string in bytes. Therefore, binary secure functions no longer rely on strlen (name) to determine the length of the string. Because the use of strlen (name) is not even correct, because name may contain NULL characters before the end of the string.
In php7, another way to obtain parameters is provided, FAST_ZPP, to improve the performance of parameter resolution.
#ifdef FAST_ZPPZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STR(type) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_EX(value, 0, 1) ZEND_PARSE_PARAMETERS_END();#endif
Parameter type table
The last four types are zvals *. this is because in actual use of php, the zval data type stores all user space variables. Three "complex" data types: Resource, array, and object. When their data type code is used for zend_parse_parameters (), the Zend Engine performs a type check, but the type conversion is not performed because there is no data type corresponding to them in C.
Zval
In general, zval and php user space variables are difficult to understand. In PHP7, its structure is defined in Zend/zend_types.h:
struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* call info for EX(This) */ } v; uint32_t type_info; } u1; union { uint32_t next; /* hash collision chain */ uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ uint32_t access_flags; /* class constant access flags */ uint32_t property_guard; /* single property guard */ } u2;};
We can see that the variable is stored through the _ zval_struct struct, and the variable value is of the zend_value type:
typedef union _zend_value { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww;} zend_value;
Although the struct looks very large, it is actually a consortium. The value is expanded. u1 is type_info and u2 is a variety of other auxiliary fields.
Zval type
The data stored in the variable is of the data type. in php7, the following types are available, which are defined in Zend/zend_types.h:
/* regular data types */#define IS_UNDEF 0#define IS_NULL 1#define IS_FALSE 2#define IS_TRUE 3#define IS_LONG 4#define IS_DOUBLE 5#define IS_STRING 6#define IS_ARRAY 7#define IS_OBJECT 8#define IS_RESOURCE 9#define IS_REFERENCE 10/* constant expressions */#define IS_CONSTANT 11#define IS_CONSTANT_AST 12/* fake types */#define _IS_BOOL 13#define IS_CALLABLE 14#define IS_ITERABLE 19#define IS_VOID 18/* internal types */#define IS_INDIRECT 15#define IS_PTR 17#define _IS_ERROR 20
Test
Write a hello_typeof () similar to gettype () to get the variable type ():
PHP_FUNCTION(hello_typeof){ zval *userval = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &userval) == FAILURE) { RETURN_NULL(); } switch (Z_TYPE_P(userval)) { case IS_NULL: RETVAL_STRING("NULL"); break; case IS_TRUE: RETVAL_STRING("true"); break; case IS_FALSE: RETVAL_STRING("false"); break; case IS_LONG: RETVAL_STRING("integer"); break; case IS_DOUBLE: RETVAL_STRING("double"); break; case IS_STRING: RETVAL_STRING("string"); break; case IS_ARRAY: RETVAL_STRING("array"); break; case IS_OBJECT: RETVAL_STRING("object"); break; case IS_RESOURCE: RETVAL_STRING("resource"); break; default: RETVAL_STRING("unknown type"); }}
Here, RETVAL_STRING () is not much different from the previous RETURN_STRING (). They are all macros. Only RETURN_STRING contains the macro replacement of RETVAL_STRING, which is defined in Zend/zend_API.h in detail:
#define RETVAL_STRING(s) ZVAL_STRING(return_value, s)#define RETVAL_STRINGL(s, l) ZVAL_STRINGL(return_value, s, l)#define RETURN_STRING(s) { RETVAL_STRING(s); return; }#define RETURN_STRINGL(s, l) { RETVAL_STRINGL(s, l); return; }
Create zval
The zval used previously is allocated space by the Zend Engine and released in the same way. However, sometimes you need to create your own zval. you can refer to the following code:
{ zval temp; ZVAL_LONG(&temp, 1234);}
Array
Array is used as a variable to carry other variables. The well-known HashTable is used in internal implementation. to create an array that will be returned to PPHP, the simplest method is as follows:
Perform a test:
PHP_FUNCTION(hello_get_arr){ array_init(return_value); add_next_index_null(return_value); add_next_index_long(return_value, 42); add_next_index_bool(return_value, 1); add_next_index_double(return_value, 3.14); add_next_index_string(return_value, "foo"); add_assoc_string(return_value, "mno", "baz"); add_assoc_bool(return_value, "ghi", 1);}
The add _ * _ string () function parameter is changed from four to three.
Array traversal
Suppose we need an extension that replaces the following features:
PHP 7's traversal array is much different from php5, and 7 provides some specialized macros to traverse elements (or keys ). The first parameter of the macro is HashTable. other variables are allocated to each iteration:
ZEND_HASH_FOREACH_VAL (ht, val)
ZEND_HASH_FOREACH_KEY (ht, h, key)
ZEND_HASH_FOREACH_PTR (ht, ptr)
ZEND_HASH_FOREACH_NUM_KEY (ht, h)
ZEND_HASH_FOREACH_STR_KEY (ht, key)
ZEND_HASH_FOREACH_STR_KEY_VAL (ht, key, val)
ZEND_HASH_FOREACH_KEY_VAL (ht, h, key, val)
Therefore, its function implementation is as follows:
PHP_FUNCTION(hello_array_strings){ ulong num_key; zend_string *key; zval *val, *arr; HashTable *arr_hash; int array_count; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) { RETURN_NULL(); } arr_hash = Z_ARRVAL_P(arr); array_count = zend_hash_num_elements(arr_hash); php_printf("The array passed contains %d elements\n", array_count); ZEND_HASH_FOREACH_KEY_VAL(arr_hash, num_key, key, val) { //if (key) { //HASH_KEY_IS_STRING //} PHPWRITE(Z_STRVAL_P(val), Z_STRLEN_P(val)); php_printf("\n"); }ZEND_HASH_FOREACH_END();}Because this is a new traversal method, but I still look at the PHP 5 processing method. it took a lot of effort to debug the above code. In general, the macro traversal method greatly reduces the encoding volume. Hash table is an important part of php. you have time to study it.