Home  >  Article  >  Backend Development  >  PHP kernel-detailed introduction to the principles of static variables, constants, and magic constants

PHP kernel-detailed introduction to the principles of static variables, constants, and magic constants

黄舟
黄舟Original
2017-03-09 09:40:561759browse

This article uses PHP source code, starting from the structure to analyze static variables, constants, and magic constants.


1. Static variables

We all know that static variables are loaded when the PHP script is loaded, that is, 1. They can be called directly without using new objects, 2. And they are static Variables are stored in the public area. Multiple objects of the same class work together to operate a static variable. 3. The memory of static variables will only be released after the script ends. Regarding these three questions, I would like to ask, why?

Let’s start the description below

Let’s first look at its structure for better analysis and understanding.

Static variables are stored in the function structure _zend_execute_data,

In this structure, there are two very critical structures, op_array and symbol_table

1.*symbol_table stores various variables in this class. Every time a new object is created, a new environment space will be opened. For details, see PHP Kernel--A Brief Talk on PHP Soul HashTble Example 2,

##2. The compiled opcode of the function is stored in the *op_array; structure. What is stored is the logic of this function. Every time a new object is created, Sharing a space logic, you will not open up the environment space independently [very critical, achieving static root cause]

#Zend/zend_compiles.h line 384, execution environment structure

struct _zend_execute_data {
	struct _zend_op *opline;
	zend_function_state function_state;
	zend_op_array *op_array;//!!!!!函数编译后的执行逻辑,编译后的opcode二进制代码,称为op_array,公用一个逻辑
	zval *object;
	HashTable *symbol_table;//!!!!!此函数的符号表地址,每次new会开辟一个新的空间《---------
	struct _zend_execute_data *prev_execute_data;
	zval *old_error_reporting;
	zend_bool nested;
	zval **original_return_value;
	zend_class_entry *current_scope;
	zend_class_entry *current_called_scope;
	zval *current_this;  
	struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
	call_slot *call_slots;
	call_slot *call;
};

Zend/zend_compiles.h 261 lines, op_array structure code##

struct _zend_op_array {
	/* Common elements */
	zend_uchar type;
...
/* static variables support */
	HashTable *static_variables;//294行 ,静态变量
...
}

Example:

t1() {
$a +=1 ;
static $b +=1;
t1();
t1();
} //加自身共调用3次

The result $a is 1 every time, and $b = 1,2,3

The reasons are as follows:

The symbol table opened by calling the function three times [3 copies

]

[t_3 execute_data] ---->[symbol_table_3]

[t_2 execute_data] ---->[symbol_table_2]

[t_1 execute_data] ---->[symbol_table_1]

*op_array->*Static variable table [one copy

]


in conclusion

:

类的变量是存储在 *symbol_table中的,每个都有其作用域,每次实例化都会在开辟一个环境空间(详见Hashtable第二部分的举例);而静态变量不同,如代码所示,它存储在op_array里边,op_array是什么,编译生成的opcode代码,存储的是函数的逻辑,不管new多少个对象,这个逻辑是公用的,而静态变量也存储在这个结构中,所以实现了同一类的不同对象可以公用一个静态变量,也解释了在PHP层面,静态变量为什么不用new就直接调用。解释了问题一二,

因为静态变量存储在op_array里边,op_array是在脚本执行结束后释放,所以其也在这个时候释放.,解释问题三。


2.常量


首先看下常量与变量的区别,常量是在变量的zval结构的基础上添加了一额外的元素。如下所示为PHP中常量的内部结构。

常量的结构 (Zend/zend_constants.h文件的33行)

typedef struct _zend_constant {
    zval value; /* zval结构,PHP内部变量的存储结构 */
    char *name; /* 常量名称 */
    uint name_len;  
    int flags;  /* 常量的标记如 CONST_PERSISTENT | CONST_CS */
    int module_number;  /* 模块号 */
} zend_constant;

结构体如上,name,name_len一目了然,值得一提的是zval与变量中存储的zval结构一模一样,(详见PHP内核的存储机制(分离/改变))

主要解释下flagmodule_number

1.flags:
c.flags = case_sensitive / case insensitive ; //    1,0
  赋值给结构体字段是否开启大小写敏感

2.module_number:
1.PHP_USER_CONSTANT:用户定义的常量
(define函数定义的常量的模块编号都是)
2.REGISTER_MAIN_LONG_CONSTANT:PHP内置定义常量
  比如错误报告级别E_ALL, E_WARNING,PHP_VERSION等常量,都是持久化常量,最后才销毁


3.魔术常量

 说是常量,其实每次值在不同位置,可能是不相同的,原因是为什么呢?

PHP内核会在词法解析时将这些常量的内容赋值进行替换,而不是在运行时进行分析。 如下PHP代码:


以__FUNCTION__为例, 在Zend/zend_language_scanner.l文件中,__FUNCTION__是一个需要分析的元标记(token):


就是这里,当当前中间代码处于一个函数中时,则将当前函数名赋值给zendlval(也就是token T_FUNC_C的值内容), 如果没有,则将空字符串赋值给zendlval(因此在顶级作用域名中直接打印__FUNCTION__会输出空格)。 这个值在语法解析时会直接赋值给返回值。这样我们就在生成的中间代码中看到了这些常量的位置都已经赋值好了。

Just remember that the function implemented by the above code converts __FUNCTION__ into the corresponding value at that time during lexical analysis.

(There are two macros, CG and EG in php, which obtain compile_global data and excutor_global data respectively. They have their own function_table and class_table respectively,
In addition, require in php is executed as a function, so you need to know how to convert between EG and CG at this time)


##.

The above is the detailed content of PHP kernel-detailed introduction to the principles of static variables, constants, and magic constants. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn