Cet article utilise le code source PHP, à partir de la structure pour analyser les variables statiques, les constantes et les constantes magiques.
1. Variables statiques
Nous savons tous que les variables statiques sont chargées lorsque le script PHP est chargé, c'est-à-dire 1. Il peut être appelé directement sans renouveler son objet, 2. Et c'est statique Les variables sont stockées dans la zone publique. Plusieurs objets de la même classe fonctionnent ensemble pour faire fonctionner une variable statique 3. La mémoire des variables statiques ne sera libérée qu'après la fin du script. Concernant ces trois questions, je voudrais. demander, pourquoi ?
Ce qui suit est une description
Examinons d'abord sa structure pour une meilleure analyse et compréhension.
Les variables statiques sont stockées dans la structure de fonctions _zend_execute_data,
Dans cette structure, il y a deux structures clés, op_array et symbol_table
1.*symbol_table stocke diverses variables dans cette classe. Chaque fois qu'un nouvel objet est créé, un nouvel espace d'environnement sera ouvert pour plus de détails, voir PHP Kernel--A Brief Talk sur PHP Soul HashTble Exemple 2. ,
2. L'opcode compilé de la fonction est stocké dans la structure *op_array ; ce qui est stocké est la logique de cette fonction. , Partageant une logique spatiale, vous n'ouvrirez pas l'espace environnemental de manière indépendante [très important, atteignant une cause racine statique]
Zend/zend_compiles.h ligne 384, structure de l'environnement d'exécution
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 lignes, code de structure op_array
struct _zend_op_array { /* Common elements */ zend_uchar type; ... /* static variables support */ HashTable *static_variables;//294行 ,静态变量 ... }
Exemple :
t1() { $a +=1 ; static $b +=1; t1(); t1(); } //加自身共调用3次
Le résultat $a vaut 1 à chaque fois, et $b = 1,2, 3
Les raisons sont les suivantes :
La table des symboles s'est ouverte en appelant la fonction trois fois [3 copies ]
[t_3 exécuter_data] ---->[symbol_table_3]
[t_2 exécuter_data] ---->[symbol_table_2 ]
[t_1 execute_data] ---->[symbol_table_1]
*op_array->*Table de variables statiques [une copie ]
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内核的存储机制(分离/改变))
主要解释下flag与module_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__会输出空格)。 这个值在语法解析时会直接赋值给返回值。这样我们就在生成的中间代码中看到了这些常量的位置都已经赋值好了。
N'oubliez pas que la fonction implémentée par le code ci-dessus convertit __FUNCTION__ en la valeur correspondante à ce moment-là lors de l'analyse lexicale.
(Il existe deux macros, CG et EG en php, qui obtiennent respectivement les données compile_global et excutor_global. Elles ont respectivement leur propre function_table et class_table,
De plus, require en php est exécuté comme une fonction, vous devez donc savoir comment convertir entre EG et CG à ce moment)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!