最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析PHP原理之變量分離/引用(Variables Separation)

 更新時間:2013年08月09日 09:57:58   作者:  
以下小編就為大家介紹一下PHP中變量分離和引用的概念。需要的朋友可以過來參考下

首先我們回顧一下zval的結(jié)構(gòu):

復(fù)制代碼 代碼如下:

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是一個長時間運行的服務(wù)器端的腳本解釋器。那么對于它來說,效率和資源占用率是一個很重要的衡量標準,也就是說,PHP必須盡量介紹內(nèi)存占用率,考慮下面這段代碼:
復(fù)制代碼 代碼如下:

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

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

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

第一行,創(chuàng)建了一個整形變量,變量值是1。 此時保存整形1的這個zval的refcount為1。
第二行,創(chuàng)建了一個新的整形變量,變量也指向剛才創(chuàng)建的zval,并將這個zval的refcount加1,此時這個zval的refcount為2。
PHP提供了一個函數(shù)可以幫助我們了解這個過程debug_zval_dump:
復(fù)制代碼 代碼如下:

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

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


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

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

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


但是,對于下面的代碼呢?
復(fù)制代碼 代碼如下:

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

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

<?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


現(xiàn)在我們知道,當使用變量復(fù)制的時候 ,PHP內(nèi)部并不是真正的復(fù)制,而是采用指向相同的結(jié)構(gòu)來盡量節(jié)約開銷。那么,對于PHP中的引用,那又是如何實現(xiàn)呢?
復(fù)制代碼 代碼如下:

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

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

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

但是,問題又來了,對于如下的代碼,又會怎樣呢?
復(fù)制代碼 代碼如下:

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

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

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

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


詳細原因,讀者你只要稍加分析就能得出,我就不越俎代庖了。;)
這次我們介紹了PHP的變量分離機制,下次我會繼續(xù)介紹如果在擴展中接收和傳出PHP腳本中的參數(shù)。

相關(guān)文章

  • php數(shù)組添加與刪除單元的常用函數(shù)實例分析

    php數(shù)組添加與刪除單元的常用函數(shù)實例分析

    這篇文章主要介紹了php數(shù)組添加與刪除單元的常用函數(shù),實例分析了array_push、array_pop、array_shift及array_unshift等函數(shù)的使用技巧,需要的朋友可以參考下
    2015-02-02
  • PHP COOKIE及時生效的方法介紹

    PHP COOKIE及時生效的方法介紹

    本篇文章主要是對PHP中COOKIE及時生效的方法進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-02-02
  • php利用反射實現(xiàn)插件機制的方法

    php利用反射實現(xiàn)插件機制的方法

    這篇文章主要介紹了php利用反射實現(xiàn)插件機制的方法,涉及php反射機制與插件的實現(xiàn)技巧,需要的朋友可以參考下
    2015-03-03
  • php沒有文件被上傳的實例分析及解決辦法

    php沒有文件被上傳的實例分析及解決辦法

    在本篇文章里小編給大家整理的是一篇關(guān)于php沒有文件被上傳的實例分析及解決辦法,有興趣的朋友們可以跟著學(xué)習(xí)參考下。
    2021-11-11
  • PHP學(xué)習(xí)之數(shù)組值的操作

    PHP學(xué)習(xí)之數(shù)組值的操作

    PHP中,用list來析取數(shù)組中的值,如list($a, $b) = $array。
    2011-04-04
  • php實現(xiàn)概率性隨機抽獎代碼

    php實現(xiàn)概率性隨機抽獎代碼

    本文給大家分享的是使用php根據(jù)獎品的權(quán)重來實現(xiàn)概率性隨機抽獎的代碼,非常的使用,有類似需求的小伙伴,可以拿去參考下
    2016-01-01
  • 理解PHP中的stdClass類

    理解PHP中的stdClass類

    這篇文章主要介紹了PHP中的stdClass類,用白話介紹了stdClass類,需要的朋友可以參考下
    2014-04-04
  • php編寫的抽獎程序中獎概率算法

    php編寫的抽獎程序中獎概率算法

    本文給大家分享的是php中獎概率算法,可用于刮刮卡,大轉(zhuǎn)盤等抽獎算法。用法很簡單,代碼里有詳細注釋說明,一看就懂,有需要的小伙伴參考下吧。
    2015-05-05
  • PHP類中Static方法效率測試代碼

    PHP類中Static方法效率測試代碼

    因為有好幾個項目等著做,又不是很急,再加上目前成型的那些框架多多少少用著總是有點不太如意,所以決定先自己寫一個框架,然后再做項目。既然寫框架,自然要經(jīng)常做一些執(zhí)行效率上的測試,今天做了一個static效率的測試。
    2010-10-10
  • 詳解PHP使用非對稱加密算法RSA

    詳解PHP使用非對稱加密算法RSA

    這篇文章主要介紹了PHP使用非對稱加密算法RSA,對算法感興趣的同學(xué),一定要看一下
    2021-04-04

最新評論

米林县| 喀什市| 山西省| 通城县| 米林县| 西和县| 玛沁县| 上思县| 大竹县| 巫溪县| 宜丰县| 清远市| 桦川县| 深水埗区| 温泉县| 万宁市| 大余县| 东台市| 奇台县| 西华县| 黔西| 通城县| 娱乐| 株洲县| 尚义县| 汤阴县| 银川市| 盖州市| 邓州市| 永清县| 门源| 建德市| 正阳县| 丽江市| 乌鲁木齐县| 乌审旗| 肥城市| 遵义市| 永仁县| 巫溪县| 花莲县|