<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 2.3 靜態變量 PHP中局部變量分配在zend_execute_data結構上,每次執行zend_op_array都會生成一個新的zend_execute_data,局部變量在執行之初分配,然后在執行結束時釋放,這是局部變量的生命周期,而局部變量中有一種特殊的類型:靜態變量,它們不會在函數執行完后釋放,當程序執行離開函數域時靜態變量的值被保留下來,下次執行時仍然可以使用之前的值。 PHP中的靜態變量通過`static`關鍵詞創建: ```php function my_func(){ static $count = 4; $count++; echo $count,"\n"; } my_func(); my_func(); =========================== 5 6 ``` ### 2.3.1 靜態變量的存儲 靜態變量既然不會隨執行的結束而釋放,那么很容易想到它的保存位置:`zend_op_array->static_variables`,這是一個哈希表,所以PHP中的靜態變量與普通局部變量不同,它們沒有分配在執行空間zend_execute_data上,而是以哈希表的形式保存在zend_op_array中。 > 靜態變量只會初始化一次,注意:它的初始化發生在編譯階段而不是執行階段,上面這個例子中:`static $count = 4;`是在編譯階段發現定義了一個靜態變量,然后插進了zend_op_array->static_variables中,并不是執行的時候把static_variables中的值修改為4,所以上面執行的時候會輸出5、6,再次執行并沒有重置靜態變量的值。 > > 這個特性也意味著靜態變量初始的值不能是變量,比如:`static $count = $xxx;`這樣定義將會報錯。 ### 2.3.2 靜態變量的訪問 局部變量通過編譯時確定的編號進行讀寫操作,而靜態變量通過哈希表保存,這就使得其不能像普通變量那樣有一個固定的編號,有一種可能是通過變量名索引的,那么究竟是否如此呢?我們分析下其編譯過程。 靜態變量編譯的語法規則: ```c statement: ... | T_STATIC static_var_list ';' { $$ = $2; } ... ; static_var_list: static_var_list ',' static_var { $$ = zend_ast_list_add($1, $3); } | static_var { $$ = zend_ast_create_list(1, ZEND_AST_STMT_LIST, $1); } ; static_var: T_VARIABLE { $$ = zend_ast_create(ZEND_AST_STATIC, $1, NULL); } | T_VARIABLE '=' expr { $$ = zend_ast_create(ZEND_AST_STATIC, $1, $3); } ; ``` 語法解析后生成了一個`ZEND_AST_STATIC`語法樹節點,接著再看下這個節點編譯為opcode的過程:zend_compile_static_var。 ```c void zend_compile_static_var(zend_ast *ast) { zend_ast *var_ast = ast->child[0]; zend_ast *value_ast = ast->child[1]; zval value_zv; if (value_ast) { //定義了初始值 zend_const_expr_to_zval(&value_zv, value_ast); } else { //無初始值 ZVAL_NULL(&value_zv); } zend_compile_static_var_common(var_ast, &value_zv, 1); } ``` 這里首先對初始化值進行編譯,最終得到一個固定值,然后調用:`zend_compile_static_var_common()`處理,首先判斷當前編譯的`zend_op_array->static_variables`是否已創建,未創建則分配一個HashTable,接著將定義的靜態變量插入: ```c //zend_compile_static_var_common(): if (!CG(active_op_array)->static_variables) { ALLOC_HASHTABLE(CG(active_op_array)->static_variables); zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0); } //插入靜態變量 zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value); ``` 插入靜態變量哈希表后并沒有完成,接下來還有一個重要操作: ```c //生成一條ZEND_FETCH_W的opcode opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL); opline->extended_value = ZEND_FETCH_STATIC; if (by_ref) { zend_ast *fetch_ast = zend_ast_create(ZEND_AST_VAR, var_ast); //生成一條ZEND_ASSIGN_REF的opcode zend_emit_assign_ref_znode(fetch_ast, &result); } ``` 后面生成了兩條opcode: * __ZEND_FETCH_W:__ 這條opcode對應的操作是創建一個IS_INDIRECT類型的zval,指向static_variables中對應靜態變量的zval * __ZEND_ASSIGN_REF:__ 它的操作是引用賦值,即將一個引用賦值給CV變量 通過上面兩條opcode可以確定靜態變量的讀寫過程:首先根據變量名在static_variables中取出對應的zval,然后將它修改為引用類型并賦值給局部變量,也就是說`static $count = 4;`包含了兩個操作,嚴格的說`$count`并不是真正的靜態變量,它只是一個指向靜態變量的局部變量,執行時實際操作是:`$count = & static_variables["count"];`。上面例子$count與static_variables["count"]間的關系如圖所示。 ![](https://box.kancloud.cn/c9ea31730e2b35f23b294d65ea252776_507x282.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看