Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte PHP-Kernel-Einführung in die Prinzipien statischer Variablen, Konstanten und magischer Konstanten

Detaillierte PHP-Kernel-Einführung in die Prinzipien statischer Variablen, Konstanten und magischer Konstanten

黄舟
黄舟Original
2017-03-09 09:40:561752Durchsuche

Dieser Artikel verwendet PHP-Quellcode, beginnend mit der Struktur, um statische Variablen, Konstanten und magische Konstanten zu analysieren.


1. Statische Variablen

Wir alle wissen, dass statische Variablen geladen werden, wenn das PHP-Skript geladen wird, d. h. 1. Es kann direkt aufgerufen werden, ohne sein Objekt zu erneuern, 2. Und Es handelt sich um statische Variablen, die im öffentlichen Bereich gespeichert werden. 3. Der Speicher statischer Variablen wird erst nach Beendigung des Skripts freigegeben frage, warum?

Das Folgende ist eine Beschreibung

Zur besseren Analyse und zum besseren Verständnis schauen wir uns zunächst die Struktur an.

Statische Variablen werden in der Funktionsstruktur _zend_execute_data gespeichert,

Und in dieser Struktur gibt es zwei sehr wichtige Strukturen, op_array und symbol_table

1.*symbol_table speichert verschiedene Variablen in dieser Klasse. Jedes Mal, wenn ein neues Objekt erstellt wird, wird ein neuer Umgebungsbereich geöffnet. Weitere Informationen finden Sie unter PHP Kernel – Ein kurzer Vortrag über PHP Soul HashTble Beispiel 2,

2. Der kompilierte Opcode der Funktion wird in der Struktur *op_array gespeichert wird erstellt, indem Sie eine Raumlogik teilen, Sie werden den Umgebungsraum nicht unabhängig öffnen [sehr wichtig, statische Grundursache erreichen]

Zend/zend_compiles.h Zeile 384, Struktur der Ausführungsumgebung

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 Zeilen, op_array-Strukturcode

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

Beispiel:

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

Das Ergebnis $a ist jedes Mal 1 und $b = 1, 2,3

Die Gründe sind wie folgt:

Die Symboltabelle wurde durch dreimaligen Aufruf der Funktion geöffnet [3 Kopien ]

[t_3execute_data] ---->[symbol_table_3]

[t_2execute_data] ----> [symbol_table_2]

[t_1execute_data] ---->[symbol_table_1]

*op_array->*Statische Variablentabelle [ ein Exemplar]


Fazit:

类的变量是存储在 *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__会输出空格)。 这个值在语法解析时会直接赋值给返回值。这样我们就在生成的中间代码中看到了这些常量的位置都已经赋值好了。

Denken Sie daran, dass die durch den obigen Code implementierte Funktion __FUNCTION__ zu diesem Zeitpunkt während der lexikalischen Analyse in den entsprechenden Wert konvertiert.

(Es gibt zwei Makros, CG und EG in PHP, die Compile_Global-Daten bzw. Excutor_Global-Daten erhalten. Sie haben ihre eigene Funktionstabelle bzw. Klassentabelle,
Darüber hinaus wird require in PHP als Funktion ausgeführt, daher müssen Sie zu diesem Zeitpunkt wissen, wie man zwischen EG und CG konvertiert)


Das obige ist der detaillierte Inhalt vonDetaillierte PHP-Kernel-Einführung in die Prinzipien statischer Variablen, Konstanten und magischer Konstanten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn