Heim  >  Artikel  >  Backend-Entwicklung  >  So implementieren Sie leere Isset-Funktionen im PHP-Kernel

So implementieren Sie leere Isset-Funktionen im PHP-Kernel

巴扎黑
巴扎黑Original
2016-11-08 09:37:151266Durchsuche

$TOC$

#### Ein paar Worte

Ursprünglich wurde diese Frage auf Oschina gestellt:


Aber so war es noch nie Ich habe akzeptiert, dass ich eine passende Antwort gefunden habe, also habe ich hart daran gearbeitet, sie selbst zu klären. Wenn es Fehler gibt, teilen Sie diese bitte mit.

Übliche Funktionen werden durch Makrodefinitionen wie ZEND_FUNCTION(xxx) implementiert. Diese Spezifikation ist leicht zu verstehen und der Quellcode ist leicht zu lesen.

Aber die Verarbeitung von empty() und isset() ist etwas Besonderes, ähnlich wie echo, eval usw.

#### Vorbereitungsarbeiten

Erweitertes VLD zum Anzeigen von PHP-Opcode, Download:


PHP-Quellcode, Zweig => remotes/origin / PHP-5.6.14

git clone http://git.php.net/repository/php-src.git -b PHP-5.6.14

PHP-Opcode entsprechende Referenz:


> Die PHP-Executor-Version ist 5.6.14, andere Versionen des Opcodes können geringfügige Unterschiede aufweisen.

PHP-Kernel-Quellcode-Analyse:


#### Analyse starten

Beispielcode vld.php:

php $a = 0;
empty($a);
isset($a);

Opcode über vld anzeigen, `php -d vld.active=1 vld.php `

Anzahl der Operationen: 10
kompilierte Variablen: !0 = $a
Zeile #* E I O op fetch ext return operands
------------ - ------------------------------------------------- - ----------------------
2 0 E > EXT_STMT
1 ASSIGN                             EXT_STMT
3 ISSET_ISEMPTY_VAR 293601280 ~ 1!
4 Frei ~ 1
4 5 EXT_STMT
6 isset_isempty_var 310378496 ~ 2! 0
7 frei ~ 2
6 8 EXT_STMT
9> Rückgabe 1

Zweig: # 0; Zeile: 2- 6; sop: 9;

Beim Ausführen des PHP-Quellcodes wird zuerst die Syntaxanalyse durchgeführt. Der Yacc von empty und isset lautet wie folgt:

vim Zend/zend_lingual_parser.y 1265

1265 internal_functions_in_yacc :
1266 › › T_ISSET '(' isset_variables ')' { $$ = $3; }
1267 › |› T_EMPTY '(' variable ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC ); }
1275
1276 isset_variables: 
1277 ›   ›   isset_variable› ›   ›   { $$ = $1; } 
1280 
1281 isset_variable: 
1282 ›   ›   Variable›   ›   ›   ›   { zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); } 

Zend_do_isset_or_isempty , t_or_isempty(int type, znode *result, znode *variable TSRMLS_DC) /* {:{:{ */ 

vi Zend/zend_compile.c 6287 

6287 void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC) / * {{{ */ 
6288 { 
6289 ›   zend_op *last_op; 
6290 
6291 ›   zend_do_end_variable_parse(variable, BP_VAR_IS, 0 TSRMLS_CC); 
6292 
6293 ›   if (zend_is_function_or_method_call(variable)) { 
6294 ›   ›   if (type == ZEND_ISEMPTY) { 
6295 ›   ›   ›   /* empty(func()) kann umgewandelt werden in !func() */ 
6296 ›   ›   ›   zend_do_unary_op(ZEND_BOOL_NOT, result, variable TSRMLS_CC); 
6297 ›   ›   } else { 
6298 ›   ›   ›   zend_error_noreturn(E_COMPILE_ERROR, „Isset() kann nicht für das Ergebnis eines Funktionsaufrufs verwendet werden (Sie können stattdessen „null !== func()“ verwenden)“) ; 
6299 ›   ›   } 
6300 
6301 ›   ›   zurückgeben; 
6302 ›   } 
6303 
6304 ›   if (variable->op_type == IS_CV) { 
6305 ›   ›   last_op = get_next_op(CG(active_op_array) TSRMLS_CC); 
6306 ›   ›   last_op->opcode = ZEND_ISSET_ISEMPTY_VAR; 

最后一行 6306, ZEND_ISSET_ISEMPTY_VAR 这个opcode 出来了,IS_CV. 判断参数是否为变量able), 当isset(fun($a)), 函数参数写法会报错, empty 5.5 版本开始支持函数参数,低版本不支持。 

opcode 是由 zend_execute. 最终会对应处理函数的查找,这个是核心,请参阅:  

 

opcode 对应处理函数的命名规律: 
ZEND_[opcode]_SPEC_(变量类型1)_(变量类型2)_HANDLER 

变量类型1和变量类型2是可选的Sie können dies auch tun, indem Sie VAR TMP CV UNUSED CONST verwenden定。 

所以 ZEND_ISSET_ISEMPTY_VAR 对应的handler如下: 

Zend/zend_vm_execute.h:44233:   ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_CONST_HANDLER, 
Zend/zend_vm_execute.h:44235:   ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_VAR_HANDLER, 
Zend/zend_v m_execute.h:44236:   ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_UNUSED_HANDLER, 
Zend/zend_vm_execute.h:44238: ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_CONST_HANDLER, 
Zend/zend_vm_execute.h:44240:   ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_VAR_HANDLER, 
Zend/zend_vm_execute.h:44241:   ZEND_ISSET_ISEMPTY_VAR_ SPEC_TMP_UNUSED_HANDLER, 
Zend/zend_vm_execute.h:44243:   ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_CONST_HANDLER, 
Zend/zend_vm_execute.h: 44245:   ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_VAR_HANDLER, 
Zend/zend_vm_execute.h:44246:   ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_UNUSED_HANDLER, 
Zend/zend_vm_execute.h:44253:   ZEND_ ISSET_ISEMPTY_VAR_SPEC_CV_CONST_HANDLER, 
Zend/zend_vm_execute.h:44255:   ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_VAR_HANDLER, 
Zend/zend_vm_execute. h:44256:   ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_UNUSED_Handler, execute.h 37946 

38013 ›   if (opline->extended_value & ZEND_ISSET) { 
38014 ›   ›   if (isset && Z_TYPE_PP(value) != IS_NULL) { 
38015 ›   ›   ›   ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 1); 
38016 ›   ›   } else { 
38017 ›   ›   ›   ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 0); 
38018 ›   ›   } 
38019 ›   } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { 
38020 ›   ›   if (!isset || !i_zend_is_true(*value)) { 
38021 › › › ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 1);
38022 › › } else {
38023 › › › ZVAL_BOOL(&EX_T(opline->result.var). tmp_var , 0);
38024 › › }

Das obige if ... dient dazu, zu beurteilen, ob es isset oder leer ist, und dann eine unterschiedliche Verarbeitung durchzuführen. Z_TYPE_PP, i_zend_is_true sind unterschiedliche Beurteilungen.
Das Echo und andere Verarbeitungen sind ähnlich, Sie können sie entsprechend dem Prozess im Detail analysieren. Der Schlüssel besteht darin, die entsprechende Handler-Verarbeitungsfunktion gemäß der Zuordnungstabelle zu finden.

Nachdem Sie diese Verarbeitungsabläufe verstanden haben, werden Sie meiner Meinung nach mit der Leistungsanalyse von PHP-Anweisungen besser vertraut sein.

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