: This article mainly introduces Wang Shuai: go deep into the PHP kernel (1)-exploring the principle of weak type variables. if you are interested in PHP tutorials, refer to it. PHP is a simple and powerful language that provides many language features applicable to the Web, including weak variable types. under the weak type mechanism, you can assign any type of value to a variable.
PHP is executed through Zend Engine (ZE). ZE is written in C and implements a weak type mechanism at the underlying layer. ZE memory management uses optimization policies such as copy at write time and reference count to reduce the memory copy during variable assignment.
The following describes how to operate PHP variables from the perspective of PHP extension.
1. PHP variable type
PHP has eight types of variables:
- Standard type: Boolean boolen, integer, floating point float, string
- Complex type: array, object
- Special type: resource
PHP does not strictly check the variable type. variables can declare their types without displaying them, but assign values directly during running. You can also convert the variable type freely. In the following example, $ I can assign any type of value without implementation declaration.
[Php] view plaincopy
-
If you do not have a deep understanding of the weak type principle, you will be pleasantly surprised when comparing variables.
[Php] view plaincopy
-
All the above three results are equal, because variable conversion is performed in PHP during variable comparison. If you want to determine the value and type at the same time, use three = (for example, $ a = 0. Maybe you will think it is common, maybe you will think it is amazing, so please go deep into the PHP kernel with me and explore the principles of PHP variables.
2. Introduction to variable storage and standard types
All PHP variables are implemented using the zval struct. we can see the definition of zval in Zend/zend. h:
[Php] view plaincopy
- Typedef union _ zvalue_value {long lval;/* long value */double dval;/* double value */struct {char * val; int len; /* this will always be set for strings */} str;/* string (always has length) */HashTable * ht;/* an array */zend_object_value obj; /* stores an object store handle, and handlers */} zvalue_value;
Attribute name |
Description |
Default value |
Refcount _ gc |
Reference count |
1 |
Is_ref _ gc |
Indicates whether it is a reference. |
0 |
Value |
Store variable values |
|
Type |
Variable type |
|
Refcount _ gc and is_ref _ gc indicate whether the variable is a reference. The type field identifies the type of the variable. The value of type can be IS_NULL, IS_BOOL, IS_LONG, IS_FLOAT, IS_STRING, IS_ARRAY, IS_OBJECT, and IS_RESOURCE. PHP selects how to store zvalue_value based on the type.
Zvalue_value can realize the core of weak variable types, which are defined as follows:
[Php] view plaincopy
- Typedef union _ zvalue_value {long lval;/* long value */double dval;/* double value */struct {char * val; int len; /* this will always be set for strings */} str;/* string (always has length) */HashTable * ht;/* an array */zend_object_value obj; /* stores an object store handle, and handlers */} zvalue_value;
Boolean, zval. type = IS_BOOL. the zval. value. lval field is read and the value is 1/0. If it is a string, zval. type = IS_STRING, it will read zval. value. str, which is a struct and stores the string pointer and length.
In C, "\ 0" is used as the string terminator. That is to say, if a string "Hello \ 0 World" is output in C language using printf, it can only output hello, because "\ 0" will think that the character has ended. In PHP, the _ zval_value.str.len of The struct is used to control the length of the string. related functions will not end with "\ 0. Therefore, PHP strings are binary safe.
If it is NULL, you only need zval. type = IS_NULL and do not need to read the value.
Through zval encapsulation, PHP implements weak types. For ZE, zval can be used to access any types.
3. Array and Object Array of the advanced type
An array is a very powerful data structure in PHP. it can be divided into an index array and an associated array. zval. type = IS_ARRAY. Each key in the associated array can store any type of data. PHP arrays are implemented using Hash tables. the values of the arrays are stored in zval. value. ht.
The implementation of PHP hash tables will be discussed later.
Zval. type = IS_OBJECT of the object type. The value exists in zval. value. obj.
4. Introduction to special types -- Resource
The resource type is a special type, zval. type = IS_RESOURCE, which has some data structures that are difficult to describe with common types in PHP, such as file handle. it is a pointer for C language, but PHP does not have the pointer concept, it cannot be constrained by conventional types. Therefore, PHP uses the resource type concept to encapsulate variables similar to file pointers in C language in the zval structure. The resource type value is an integer. ZE obtains the value from the resource hash table.
Definition of resource type:
[Php] view plaincopy
- Typedefstruct_zend_rsrc_list_entry {void * ptr; int type; int refcount;} zend_rsrc_list_entry;
Ptr is a pointer to the final implementation of the resource, such as a file handle or a database connection structure. Type is a type tag used to distinguish different resource types. Refcount indicates the reference count of a resource.
In the kernel, the resource type is obtained through the ZEND_FETCH_RESOURCE function.
[Php] view plaincopy
- ZEND_FETCH_RESOURCE (con, type, zval *, default, resource_name, resource_type );
5. variable type conversion
According to our understanding of the PHP language, the type of the variable depends on the zval. type field, and the content of the variable is stored in zval. value according to zval. type. When a variable is required in PHP, only two steps are required: change the value or pointer of zval. value, and then change the type of zval. type. However, for some PHP advanced variables Array/Object/Resource, variable conversion requires more operations.
There are three types of variable conversion principles:
5.1 Standard type conversion
It is relatively simple, just follow the steps above to convert.
5.2 Conversion of standard and resource types
The resource type can be understood as int, which facilitates the conversion of standard types. After conversion, the resource will be closed or recycled.
[Php] view plaincopy
-
5.3 Standard type and complex type conversion
If the Array is converted to an int or float type, the number of elements is returned. if The bool is converted to an Array, the system returns whether there are elements in the Array. If the Array is converted to a string, the system returns 'array' and throws a warning.
Detailed content depends on experience, please read the PHP Manual: http://php.net/manual/en/language.types.type-juggling.php
5.4 complex type conversion
Array and object can be converted. If any other type of value is converted to an object, a built-in class is created.StdClass.
When writing PHP extensions, the PHP kernel provides a set of functions for type conversion:
Void convert_to_long (zval * pzval) |
Void convert_to_double (zval * pzval) |
Void convert_to_long_base (zval * pzval, int base) |
Void convert_to_null (zval * pzval) |
Void convert_to_boolean (zval * pzval) |
Void convert_to_array (zval * pzval) |
Void convert_to_object (zval * pzval) |
Void convert_object_to_type (zval * pzval, convert_func_t converter) |
The PHP kernel provides a set of macros to easily access zval, which is used to obtain zval values in a finer granularity:
The kernel accesses the zval container API |
Macro |
Access variable |
Z_LVAL (zval) |
(Zval). value. lval |
Z_DVAL (zval) |
(Zval). value. dval |
Z_STRVAL (zval) |
(Zval). value. str. val |
Z_STRLEN (zval) |
(Zval). value. str. len |
Z_ARRVAL (zval) |
(Zval). value. ht |
Z_TYPE (zval) |
(Zval). type |
Z_LVAL_P (zval) |
(* Zval). value. lval |
Z_DVAL_P (zval) |
(* Zval). value. dval |
Z_STRVAL_P (zval_p) |
(* Zval). value. str. val |
Z_STRLEN_P (zval_p) |
(* Zval). value. str. len |
Z_ARRVAL_P (zval_p) |
(* Zval). value. ht |
Z_OBJ_HT_P (zval_p) |
(* Zval). value. obj. handlers |
Z_LVAL_PP (zval_pp) |
(** Zval). value. lval |
Z_DVAL_PP (zval_pp) |
(** Zval). value. dval |
Z_STRVAL_PP (zval_pp) |
(** Zval). value. str. val |
Z_STRLEN_PP (zval_pp) |
(** Zval). value. str. len |
Z_ARRVAL_PP (zval_pp) |
(** Zval). value. ht |
6. symbol table and scope of variables
The ing between the variable symbol table of PHP and the zval value is through HashTable (hash table, also called hash table, HT). HashTable is widely used in ZE, language features such as constants, variables, and functions are all organized by HT. the array type in PHP is also implemented by HashTable.
For example:
[Php] view plaincopy
-
$ Var variable names are stored in the variable symbol table, and the zval structure representing the $ var type and value is stored in the hash table. The kernel uses the hash ing between the variable symbol table and the zval address to access PHP variables.
Why do we need to raise the scope? This is because of variable protection in the function. PHP variables in the scope are divided into global variables and local variables. Each scope of PHP maintains a HashTable symbol table. When you create a function or class in PHP, ZE creates a new symbol table, indicating that the variable in the function or class is a local variable, in this way, local variables are protected-external variables cannot be accessed within the function. When you create a PHP variable, ZE assigns a zval, sets the corresponding type and initial value, and adds the variable to the symbol table in the current scope so that you can use the variable.
Use ZEND_SET_SYMBOL in the kernel to set the variable:
[Php] view plaincopy
- ZEND_SET_SYMBOL (EG (active_symbol_table), "foo", foo );
View the _ zend_executor_globals structure
[Php] view plaincopy
- Zend/zend_globals.h
- Struct _ zend_executor_globals {// slightly HashTable symbol_table; // symbol table of global variables HashTable * active_symbol_table; // symbol table of local variables // omitted };
When writing PHP extensions, you can use the EG macro to access the variable symbol table of PHP. EG (symbol_table) accesses the variable symbol table in the global scope, EG (active_symbol_table) accesses the variable symbol table in the current scope, and partial variables store pointers, it is passed to the corresponding function when performing operations on HashTable.
To better understand the hash table and scope of variables, a simple example is given:
[Php] view plaincopy
-
Create the variable $ temp outside the function and add it to the global symbol table. at the same time, assign a character type zval in the HashTable of the global symbol table with the value 'global '. Create the variable $ temp in the test function and add it to the symbol table belonging to the test function. assign the variable type zval with the value 'activity '.
7. variable operations in PHP extension
Create PHP variables
We can call the MAKE_STD_ZVAL (pzv) function in the extension to create a PHP callable variable. The Macros applied by MAKE_STD_ZVAL include:
[Php] view plaincopy
- # Define MAKE_STD_ZVAL (zv) ALLOC_ZVAL (zv); INIT_PZVAL (zv) # define ALLOC_ZVAL (z) values (z, zval, values) # define ZEND_FAST_ALLOC (p, type, fc_type) (p) = (type *) emalloc (sizeof (type) # define INIT_PZVAL (z)-> refcount _ gc = 1; (z) -> is_ref _ gc = 0;
MAKE_STD_ZVAL (foo:
[Php] view plaincopy
- (Foo) = (zval *) emalloc (sizeof (zval); (foo)-> refcount _ gc = 1; (foo)-> is_ref _ gc = 0;
As you can see, MAKE_STD_ZVAL does three things: allocating memory, initializing refcount and is_ref in the zval structure.
The kernel provides some macros to simplify our operations. you can set the zval type and value in only one step.
API Macros for Accessing zval |
Macro |
Implementation method |
ZVAL_NULL (pvz) |
Z_TYPE_P (pzv) = IS_NULL |
ZVAL_BOOL (pvz) |
Z_TYPE_P (pzv) = IS_BOOL; Z_BVAL_P (pzv) = B? 1: 0; |
ZVAL_TRUE (pvz) |
ZVAL_BOOL (pzv, 1 ); |
ZVAL_FALSE (pvz) |
ZVAL_BOOL (pzv, 0 ); |
ZVAL_LONG (pvz, l) (l is the value) |
Z_TYPE_P (pzv) = IS_LONG; Z_LVAL_P (pzv) = l; |
ZVAL_DOUBLE (pvz, d) |
Z_TYPE_P (pzv) = IS_DOUBLE; Z_LVAL_P (pzv) = d; |
ZVAL_STRINGL (pvz, str, len, dup) |
Z_TYPE_P (pzv) = IS_STRING; Z_STRLEN_P (pzv) = len; If (dup ){ {Z_STRVAL_P (pzv) = estrndup (str, len + 1 );} } Else { {Z_STRVAL_P (pzv) = str ;} } |
ZVAL_STRING (pvz, str, len) |
ZVAL_STRINGL (pzv, str, strlen (str), dup ); |
ZVAL_RESOURCE (pvz, res) |
Z_TYPE_P (pzv) = IS_RESOURCE; Z_RESVAL_P (pzv) = res; |
Dup parameter in ZVAL_STRINGL (pzv, str, len, dup)
Describe the ZVAL_STRINGL (pzv, str, len, dup); str and len parameters, because we know that the kernel stores the string address and its length, the meaning of the following dup is actually very simple. it specifies whether the string needs to be copied. If the value is 1, a new memory is applied for and the string is assigned. then, the address of the new memory is copied to pzv. if the value is 0, the str address is directly assigned to zval.
Differences between ZVAL_STRINGL and ZVAL_STRING
If you want to intercept the string at a certain position or you already know the length of the string, you can use the macro ZVAL_STRINGL (zval, string, length, duplicate ), it explicitly specifies the string length, instead of strlen (). This macro uses the string length as a parameter. However, it is binary secure and faster than ZVAL_STRING because strlen is missing.
ZVAL_RESOURCE is equal to ZVAL_LONG.
As we mentioned in chapter 4, the value of the resource type in PHP is an integer, so ZVAL_RESOURCE and ZVAL_LONG work almost, but it sets the zval type to IS_RESOURCE.
8. Summary
The weak type of PHP is converted by zval container of ZE. the variable name and zval data are stored in the hash table, which is at a certain cost in terms of running efficiency. In addition, due to implicit conversion of variable types, insufficient variable types are detected during development, which may cause problems.
However, the language features of PHP, such as weak types, arrays, memory hosting, and extensions, are very suitable for Web development scenarios. The development efficiency is very high and the product iteration cycle can be accelerated. In massive Services, the bottleneck usually exists at the data access layer, rather than the language itself. In practice, PHP serves not only the logic layer and presentation layer, but also the UDPServer/TCPServer developed by PHP as the middle layer of data and cache.
The above introduces Wang Shuai: go deep into the PHP kernel (1)-exploring the principle of weak type variables, including some content, and hope to help those who are interested in PHP tutorials.