91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是PHP變量分離

發布時間:2021-10-11 22:44:45 來源:億速云 閱讀:109 作者:iii 欄目:開發技術

本篇內容主要講解“什么是PHP變量分離”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“什么是PHP變量分離”吧!

首先我們回顧一下zval的結構:

復制代碼 代碼如下:

struct _zval_struct {
        /* Variable information */
        zvalue_value value; /* value */
        zend_uint refcount;
        zend_uchar type; /* active type */
        zend_uchar is_ref;
};


其中的refcount和is_ref字段我們一直都沒有介紹過,我們知道PHP是一個長時間運行的服務器端的腳本解釋器。那么對于它來說,效率和資源占用率是一個很重要的衡量標準,也就是說,PHP必須盡量介紹內存占用率,考慮下面這段代碼:

復制代碼 代碼如下:

<?php
   $var = "laruence";
   $var_dup = $var;
   unset($var);
?>


第一行代碼創建了一個字符串變量,申請了一個大小為9字節的內存,保存了字符串”laruence”和一個NULL(/0)的結尾。
第二行定義了一個新的字符串變量,并將變量var的值”復制”給這個新的變量。
第三行unset了變量var
這樣的代碼在我們平時的腳本中是很常見的,如果PHP對于每一個變量賦值都重新分配內存,copy數據的話,那么上面的這段代碼公要申請18個字節的內存空間,而我們也很容易的看出來,上面的代碼其實根本沒有必要申請倆份空間,呵呵,PHP的開發者也看出來了:
我們之前講過,PHP中的變量是用一個存儲在symbol_table中的符號名,對應一個zval來實現的,比如對于上面的第一行代碼,會在symbol_table中存儲一個值”var”, 對應的有一個指針指向一個zval結構,變量值”laruence”保存在這個zval中,所以不難想象,對于上面的代碼來說,我們完全可以讓”var”和”var_dup”對應的指針都指向同一個zval就可以了。
PHP也是這樣做的,這個時候就需要介紹我們之前一直沒有介紹過的zval結構中的refcount字段了。
refcount,顧名思義,記錄了當前的zval被引用的計數。
比如對于代碼:

復制代碼 代碼如下:

<?php
   $var = 1;
   $var_dup = $var;
?>


第一行,創建了一個整形變量,變量值是1。 此時保存整形1的這個zval的refcount為1。
第二行,創建了一個新的整形變量,變量也指向剛才創建的zval,并將這個zval的refcount加1,此時這個zval的refcount為2。
PHP提供了一個函數可以幫助我們了解這個過程debug_zval_dump:

復制代碼 代碼如下:

<?php
 $var = 1;
 debug_zval_dump($var);
 $var_dup = $var;
 debug_zval_dump($var);
?>

輸出:
long(1) refcount(2)
long(1) refcount(3

如果你奇怪 ,var的refcount應該是1啊?
我們知道,對于簡單變量,PHP是以傳值的形式穿參數的。也就是說,當執行debug_zval_dump($var)的時候,$var會以傳值的方式傳遞給debug_zval_dump,也就是會導致var的refcount加1,所以我們只要能看到,當變量賦值給一個變量以后,能導致zval的refcount加1這個事實即可。
現在我們回頭看文章開頭的代碼, 當執行了最后一行unset($var)以后,會發生什么呢? 對,既是refcount減1,上代碼:

復制代碼 代碼如下:

<?php
   $var = "laruence";
   $var_dup = $var;
   unset($var);
   debug_zval_dump($var_dup);
?>

輸出:
string(8) "laruence" refcount(2

但是,對于下面的代碼呢?

復制代碼 代碼如下:

<?php
   $var = "laruence";
   $var_dup = $var;
   $var = 1;
?>


很明顯在這段代碼執行以后,$var_dup的值應該還是”laruence”, 那么這又是怎么實現的呢?
這就是PHP的copy on write機制:
PHP在修改一個變量以前,會首先查看這個變量的refcount,如果refcount大于1,PHP就會執行一個分離的例程, 對于上面的代碼,當執行到第三行的時候,PHP發現$var指向的zval的refcount大于1,那么PHP就會復制一個新的zval出來,將原zval的refcount減1,并修改symbol_table,使得$var和$var_dup分離(Separation)。這個機制就是所謂的copy on write(寫時復制)。
上代碼測試:

復制代碼 代碼如下:

<?php
   $var = "laruence";
   $var_dup = $var;
   $var = 1;
   debug_zval_dump($var);
   debug_zval_dump($var_dup);
?>

輸出:
long(1) refcount(2)
string(8) "laruence" refcount(2

現在我們知道,當使用變量復制的時候 ,PHP內部并不是真正的復制,而是采用指向相同的結構來盡量節約開銷。那么,對于PHP中的引用,那又是如何實現呢?

復制代碼 代碼如下:

<?php
   $var = "laruence";
   $var_ref = &$var;
   $var_ref = 1;
?>


這段代碼結束以后,$var也會被間接的修改為1,這個過程稱作(change on write:寫時改變)。那么ZE是怎么知道,這次的復制是不需要Separation的呢?
這個時候就要用到zval中的is_ref字段了:
對于上面的代碼,當第二行執行以后,$var所代表的zval的refcount變為2,并且同時置is_ref為1。
到第三行的時候,PHP先檢查var_ref代表的zval的is_ref字段,如果為1,則不分離,大體邏輯示意如下:

復制代碼 代碼如下:

 if((*val)->is_ref || (*val)->refcount<2){
          //不執行Separation
        ... ;//process
  }


但是,問題又來了,對于如下的代碼,又會怎樣呢?

復制代碼 代碼如下:

<?php
   $var = "laruence";
   $var_dup = $var;
   $var_ref = &$var;
?>


對于上面的代碼,存在一對copy on write的變量$var和$var_dup, 又有一對change on write機制的變量對$var和$var_ref,這個情況又是如何運作的呢?
當第二行執行的時候,和前面講過的一樣,$var_dup 和 $var 指向相同的zval, refcount為2.
當執行第三行的時候,PHP發現要操作的zval的refcount大于1,則,PHP會執行Separation, 將$var_dup分離出去,并將$var和$var_ref做change on write關聯。也就是,refcount=2, is_ref=1;
基于這樣的分析,我們就可以讓debug_zval_dump出refcount為1的結果來:

復制代碼 代碼如下:

<?php
     $var = "laruence";
    $var_dup = &$var;
     debug_zval_dump($var);
?>

輸出:
string(8) "laruence" refcount(1

到此,相信大家對“什么是PHP變量分離”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

江津市| 洪洞县| 瓮安县| 宁阳县| 沧源| 隆化县| 雅江县| 花垣县| 晋中市| 海口市| 凉城县| 广安市| 新沂市| 颍上县| 彝良县| 义乌市| 行唐县| 江北区| 晋城| 偏关县| 祁东县| 施秉县| 玉门市| 星子县| 民县| 呼和浩特市| 武平县| 浙江省| 辽阳市| 阜康市| 龙陵县| 华安县| 乌拉特前旗| 彩票| 松潘县| 全椒县| 若羌县| 南充市| 宁晋县| 家居| 开平市|