目錄
1. php設計的原理和特點
HashTable是Zend的核心資料結構,在php裡面幾乎用來實現所有功能,php的資料array()就是典型的應用。此外在Zend內部,如函數符號表、全景變數都是透過HashTable來實現的。
5.2.1 整數、浮點數變數
5.2.2 字元變數
5.2.3 陣列變數
5.3 PHP變數管理-引用計數和寫時拷貝
5.4 PHP局部變數和全域變數的實作:
首頁 後端開發 php教程 PHP執行原理

PHP執行原理

Feb 09, 2017 am 10:19 AM

PHP執行原理

php是一門應用非常簡單,開發效率極高的一門語言,其弱類型的變數能省去程式設計師大量的定義變數、類型轉換等的時間和精力。它是一種適用於web開發的動態語言。

1. php設計的原理和特點

  • 多進程模型:這樣能做到進程間互相不受影響,對於進程的資源利用更快速、便捷

  • 弱類型語言:和強類型語言C、C++、java等語言不同,php中變數的類型並不是一開始就確定的,他是在運行時才確定的,可以隱式或顯式的對其進行類型轉換,這就使其在開發中非常的靈活,程式設計師不需要關注變數類型的問題

  • Zend引擎+ 元件(ext)的模式降低內部的耦合

  • 中間層(sapi)隔絕web server 和php

  • 中間層(sapi)隔絕web server 和php

  • 中間層(sapi)簡單
語法靈活,規範少。這一點就有利有弊了。 。 。

PHP执行原理 2. php的四層體系

  • php從上到下一共四層體系:

  • Zend引擎的程式碼翻譯成可執行的opcode的,處理並實現相應的處理方法(原理:鳥哥的博客)、實現了基本的數據結構、內存分配及管理、提供了相應api方法供外部使用,是一切的核心。
  • Extensions
  • :圍繞著Zend引擎,extensions透過元件的方式提供各種基礎服務,常用的內建函數array、標準函式庫等都是透過extension來實現的,使用者也可以根據需要實現自己的extension以達到功能擴充等目的如貼吧正在使用的PHP中間層、富文本解析就是extension的典型應用)。
  • Sapi
  • :Sapi全稱Server Application Programing Interface, 也就是服務端應用程式接口,Sapi透過一些列鉤子函數,使php可以和外圍交互數據,這是PHP非常優雅和成功的一個設計,透過sapi成功的將PHP本身和上層應用解耦隔離,PHP可以不再考慮如何針對不同應用進行相容,而應用程式本身也可以針對自己的特點實現不同的處理方式。
  • 上層應用
  • :這就是程式設計師編寫的應用程序,透過不同的sapi方式得到各種各樣的應用模式,如透過webserver實現web應用,在命令列下以腳本的方式運行等等

3. Sapi

    如前所屬,Sapi通過一些列的接口,使外部應用可以和php交換數據並可以根據不同的應用特點實現特定的處理方法,常見的sapi有:
  • apache2handler:以apache作為webserver,採用MOD_PHP模式運行時的處理方式,也是現在應用最廣泛的一種
  • cgi:這是webserver和php的另外一種互動方式,也就是fastcgi協定
  • cli:指令調試應用模式

4. php程式碼的執行流程PHP执行原理

從圖中可以看出,php透過Zend引擎實現了一個典型的動態語言的執行過程:取得一段程式碼片段,經過詞法解析、語法解析等階段,原始程式被翻譯成一個個指令(opcodes),然後Zend虛擬機器順序執行這些指令。 PHP本身是用C語言實現的,因此最終呼叫的也是C語言的函數。 PHP的執行的核心是翻譯出來的一條一條指令,也即

opcode

Opcode是PHP程式執行的最基本單位

。一個opcode由兩個參數(op1,op2)、傳回值和處理函數組成。 PHP程式最終被翻譯為一組opcode處理函數的順序執行。

    常用的幾個函數:
  • END_ASSIGN_SPEC_CV_CV_HANDLER : 變數分配( a=b)
  • ZEND_DO_CV_BY_ND_ND獎_NHA_NDLD:Pat%SDun​​DDobD​​DDHDHunun_M感興趣_SD發展點DLER:字串拼接a.b
  • ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法運算a+2
  • ZEND_IS_EQUAL_SPEC_CV_CONST:判斷相等a==1
  • ZEND_IS_IDENTICAL_SPEC_CV_CONST:判斷相等a=1
  • ZEND_IS_IDENTICAL_SPEC_CV_CONST:判斷相等a=1

  • 5.1  實作HashTable資料結構

HashTable是Zend的核心資料結構,在php裡面幾乎用來實現所有功能,php的資料array()就是典型的應用。此外在Zend內部,如函數符號表、全景變數都是透過HashTable來實現的。

Zend hash table 實現了典型的hash表散列結構,同時透過附加一個雙向鍊錶,提供了正向、反向、遍歷數組的功能,結構如圖:

PHP执行原理

可以看到,在hash table中既有key->value形式的雜湊結構,也有雙向鍊錶模式,使得它能夠非常方便的支援快速查找和線性遍歷。 
雜湊結構:Zend的雜湊結構是典型的hash表模型,透過鍊錶的方式來解決衝突。需要注意的是zend的hash table是一個自增長的資料結構,當hash表數目滿了之後,其本身會動態以2倍的方式擴容並重新元素位置。初始大小均為8。另外,在進行 key->value快速查找時候,zend本身也做了一些優化,透過空間換時間的方式加快速度。例如在每個元素中都會用一個變數 nKeyLength來標識key的長度以作快速判定。 
雙向鍊錶:Zend hash table透過一個鍊錶結構,實現了元素的線性遍歷。理論上,做遍歷使用單向鍊錶就夠了,之所以使用雙向鍊錶,主要目的是為了快速刪除,避免遍歷。 Zend hash table是一種複合型的結構,作為數組使用時,即支援常見的關聯數組也能夠作為順序索引數字來使用,甚至允許2者的混合。 
PHP關聯陣列:關聯陣列是典型的hash_table應用。一個查詢過程經過以下幾步(從程式碼可以看出,這是一個常見的hash查詢過程並增加一些快速判定加速查找):

01  getKeyHashValue h;
02  index = n & nTableMask;
03  Bucket *p = arBucket[index];
04  while (p) {
05      if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
06          RETURN p->data;   
07      }
08      p=p->next;
09  }
10  RETURN FALTURE;
登入後複製
登入後複製

PHP索引數組:索引數組就是我們常見的數組,透過下標訪問。例如 arr[0],Zend HashTable內部進行了歸一化處理,對於index類型key同樣分配了hash值和nKeyLength(為0)。內部成員變數 nNextFreeElement就是目前被指派的最大id,每次push後自動加一。正是這種歸一化處理,PHP才能夠實現關聯和非關聯的混合。 由於 push運算的特殊性,索引key在PHP數組中先後順序並不是透過下標大小來決定,而是由push的先後決定。 例如arr[1] = 2; arr[2] = 3;對於double類型的key,Zend HashTable會將他當做索引key處理

5.2 PHP變數的實作原理

PHP是一門弱型別語言,不嚴格區分變數的類型。 PHP的變數可以分為簡單型別(int、sting、bool)、集合型別(array, resource, object) 和常數(const),所有的變數在底層都所以同一種結構zval

zval是zend中非常重要的資料結構,用來標示並實作php的變量,其資料結構如下:

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;  /* variable ref count */
    zend_uchar type;          /* active type */
    zend_uchar is_ref__gc;    /* if it is a ref variable */
};
typedef struct _zval_struct zval;
登入後複製
登入後複製

其中,

  • zval_value value是變數的實際值,具體來說是一個zvalue_value

    typedef union _zvalue_value {
        long lval;                  /* long value */
        double dval;                /* double value */
        struct {                    /* string */
            char *val;
            int len;
        } str;
        HashTable *ht;              /* hash table value,used for array */
        zend_object_value obj;      /* object */
    } zvalue_value;
    登入後複製
    登入後複製
  • zend_uint refcount__gc

    是一個計數器,用來保存多少變數(或符號,symbols )指向了該zval。在變數生成時,其refcount=1,典型的賦值運算如$a = $b會令zval的refcount加1,而unset操作會對應的減1。在PHP5.3之前,使用引用計數的機制來實作GC,如果一個zval的refcount較少到0,那麼Zend引擎會認為沒有任何變數指向該zval,因此會釋放該zval所佔的記憶體空間。但,事情有時並不會那麼簡單。後面我們會看到,單純的引用計數機制無法GC掉循環引用的zval,即使指向該zval的變數已經被unset,從而導致了記憶體洩漏(Memory Leak)。

  • zend_uchar type

    此欄位用來表示變數的實際型別。 PHP中的變數包括四種標量類型(bool,int,float,string),兩種複合類型(array, object)和兩種特殊的類型(resource 和NULL)。在zend內部,這些型別對應到下面的巨集(程式碼位置 phpsrc/Zend/zend.h)

    #define IS_NULL     0
    #define IS_LONG     1
    #define IS_DOUBLE   2
    #define IS_BOOL     3
    #define IS_ARRAY    4
    #define IS_OBJECT   5
    #define IS_STRING   6
    #define IS_RESOURCE 7
    #define IS_CONSTANT 8
    #define IS_CONSTANT_ARRAY   9
    #define IS_CALLABLE 10
    登入後複製
    登入後複製
  • is_ref__gc

    這個欄位用來標記變數是否是引用變數。對於普通的變量,該值為0,而對於引用型的變量,該值為1。這個變數會影響zval的共享、分離等

5.2.1 整數、浮點數變數

整數、浮點數是PHP中的基礎型之一,也是一個簡單型變數。對於整數和浮點數,在zvalue中直接儲存對應的值。其型別分別是long和double。
從zvalue結構可以看出,對於整數型,和c等強型別語言不同,PHP是不區分int、unsigned int、long、long long等型式的,對它來說,整數只有一種型別也就是long。由此,可以看出,在PHP裡面,整數的值範圍是由編譯器位數來決定而不是固定不變的。在php中如果整數越界了會發生什麼事? php會自動將整數轉換成浮點數型別

對於浮點數,類似整數,它也不區分float和double而是統一隻有double一種型別

5.2.2 字元變數

和整數一樣,字元變數也是PHP中的基礎型別和簡單型變數。透過zvalue結構可以看出,在PHP中,字串是由指向實際資料的指標和長度結 構體組成,這點和c++中的string比較類似。由於透過一個實際變數表示長度,和c不同,它的字串可以是2進位資料(包含0),同時在PHP中, 求字串長度strlen是O(1)運算

常見的字串拼接方式及速度比較:

假設有以下4個變數:strA='123'; strB = '456'; intA=123; intB=456; 
現在對如下的幾種字串拼接方式做一個比較和說明: 
1 res = strA.strB和res = “strAstrB” 
這種情況下,zend會重新malloc一塊記憶體並進行對應處理,其速度一般。
2 strA = strA.strB 
這種是速度最快的,zend會在當前strA基礎上直接relloc,避免重複拷貝 
3 res = intA.intB 
這種速度較慢,因為需要做式的格式轉換,實際編寫程式中也應該注意盡量避免 
4 strA = sprintf (“%s%s”,strA,strB); 
這會是最慢的一種方式,因為sprintf在PHP中並不是語言結構,本身對於格式辨識與處理就需要耗費比較多時間,另外本身機制也是malloc。不過sprintf的方式最具可讀性,實際中可以根據具體情況靈活選擇。

5.2.3 陣列變數

PHP的陣列是透過Zend Hash Table來天然實作。

foreach操作如何實現? 對一個陣列的foreach就是透過遍歷hashtable中的雙向鍊錶完成。對於索引數組,通過foreach遍 歷效率比for高很多,省去了key->value的查找。 count操作直接呼叫 HashTable->NumOfElements,O(1)操作。對於’123’這樣的字串,zend會轉換為其整數形 式。 arr[‘123’]和arr[123]

5.3 PHP變數管理-引用計數和寫時拷貝

引用計數在記憶體回收、字串操作等地方使用非常廣泛。 Zval的引用計數透過成員變數is_ref和ref_count實現,透過引用計數,多個變數可以共享同一份資料。避免頻繁拷貝帶來的大量消耗。當進行賦值操作時,zend將變數指向相同的zval同時ref_count++,在unset操作時,對應的ref_count-1。只有ref_count減為0時才會真正執行銷毀操作。 如果是引用賦值,則zend會修改is_ref為1。

PHP變數透過引用計數實現變數共享數據,那如果改變其中一個變數值呢?當試圖寫入一個變數時,Zend若發現該變數指向的zval被多個變數共享,則為其複製一份ref_count為1的zval,並遞減原zval的refcount,這個過程稱為「zval分離」。可見,只有在有寫操作發生時zend才進行拷貝操作,因此也叫copy-on-write(寫時拷貝)

對於引用型變量,其要求和非引用型相反,引用賦值的變量間必須是捆綁的,修改一個變數就修改了所有捆綁變數。

5.4 PHP局部變數和全域變數的實作:

PHP中的局部變數和全域變數是如何實現的?對於一個請求,任意時刻PHP都可以看到兩個符號表(symbol_table和 active_symbol_table),前者用來維護全域變數。後者是指針,指向目前活動的變數符號表,當程式進入某個函數時,zend 就會為它指派一個符號表x同時將active_symbol_table指向a。透過這樣的方式實現全域、局部變數的區分。

取得變數值:PHP的符號表是透過hash_table實現的,對於每個變數都分配唯一標識,取得的時候根據標識從表中找到對應zval返回。

函數中使用全域變數:在函數中,我們可以透過明確申明global來使用全域變數。 在active_symbol_table中建立symbol_table中同名變數的引用(引用變數的值要更新大家會一起更新),如果symbol_table中沒有同名變數則會先建立。

參考:

  • http://www.php.cn/

  • http://www.php.cn/

  • [http://www.php.cn/


PHP執行原理

php是一門應用非常簡單,開發效率極高的一門語言,其弱類型的變數能省去程式設計師大量的定義變數、類型轉換等的時間和精力。它是一種適用於web開發的動態語言。

1. php設計的原理和特點

  • 多進程模型:這樣能做到進程間互相不受影響,對於進程的資源利用更快速、便捷

  • 弱類型語言:和強類型語言C、C++、java等語言不同,php中變數的類型並不是一開始就確定的,他是在運行時才確定的,可以隱式或顯式的對其進行類型轉換,這就使其在開發中非常的靈活,程式設計師不需要關注變數類型的問題

  • Zend引擎+ 元件(ext)的模式降低內部的耦合

  • 中間層(sapi)隔絕web server 和php

  • 中間層(sapi)隔絕web server 和php

  • 中間層(sapi)簡單
語法靈活,規範少。這一點就有利有弊了。 。 。

PHP执行原理 2. php的四層體系

  • php從上到下一共四層體系:

  • Zend引擎的程式碼翻譯成可執行的opcode的,處理並實現相應的處理方法(原理:鳥哥的博客)、實現了基本的數據結構、內存分配及管理、提供了相應api方法供外部使用,是一切的核心。
  • Extensions
  • :圍繞著Zend引擎,extensions透過元件的方式提供各種基礎服務,常用的內建函數array、標準函式庫等都是透過extension來實現的,使用者也可以根據需要實現自己的extension以達到功能擴充等目的如貼吧正在使用的PHP中間層、富文本解析就是extension的典型應用)。
  • Sapi
  • :Sapi全稱Server Application Programing Interface, 也就是服務端應用程式接口,Sapi透過一些列鉤子函數,使php可以和外圍交互數據,這是PHP非常優雅和成功的一個設計,透過sapi成功的將PHP本身和上層應用解耦隔離,PHP可以不再考慮如何針對不同應用進行相容,而應用程式本身也可以針對自己的特點實現不同的處理方式。
  • 上層應用
  • :這就是程式設計師編寫的應用程序,透過不同的sapi方式得到各種各樣的應用模式,如透過webserver實現web應用,在命令列下以腳本的方式運行等等

3. Sapi

    如前所屬,Sapi通過一些列的接口,使外部應用可以和php交換數據並可以根據不同的應用特點實現特定的處理方法,常見的sapi有:
  • apache2handler:以apache作為webserver,採用MOD_PHP模式運行時的處理方式,也是現在應用最廣泛的一種
  • cgi:這是webserver和php的另外一種互動方式,也就是fastcgi協定
  • cli:指令調試應用模式

4. php程式碼的執行流程PHP执行原理

從圖中可以看出,php透過Zend引擎實現了一個典型的動態語言的執行過程:取得一段程式碼片段,經過詞法解析、語法解析等階段,原始程式被翻譯成一個個指令(opcodes),然後Zend虛擬機器順序執行這些指令。 PHP本身是用C語言實現的,因此最終呼叫的也是C語言的函數。 PHP的執行的核心是翻譯出來的一條一條指令,也即

opcode

Opcode是PHP程式執行的最基本單位

。一個opcode由兩個參數(op1,op2)、傳回值和處理函數組成。 PHP程式最終被翻譯為一組opcode處理函數的順序執行。

    常用的幾個函數:
  • END_ASSIGN_SPEC_CV_CV_HANDLER : 變數分配( a=b)
  • ZEND_DO_CV_BY_ND_ND獎_NHA_NDLD:Pat%SDun​​DDobD​​DDHDHunun_M感興趣_SD發展點DLER:字串拼接a.b
  • ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法運算a+2
  • ZEND_IS_EQUAL_SPEC_CV_CONST:判斷相等a==1
  • ZEND_IS_IDENTICAL_SPEC_CV_CONST:判斷相等a=1
  • ZEND_IS_IDENTICAL_SPEC_CV_CONST:判斷相等a=1

  • 5.1  實作HashTable資料結構

HashTable是Zend的核心資料結構,在php裡面幾乎用來實現所有功能,php的資料array()就是典型的應用。此外在Zend內部,如函數符號表、全景變數都是透過HashTable來實現的。

Zend hash table 實現了典型的hash表散列結構,同時透過附加一個雙向鍊錶,提供了正向、反向、遍歷數組的功能,結構如圖:

PHP执行原理

可以看到,在hash table中既有key->value形式的雜湊結構,也有雙向鍊錶模式,使得它能夠非常方便的支援快速查找和線性遍歷。 
雜湊結構:Zend的雜湊結構是典型的hash表模型,透過鍊錶的方式來解決衝突。需要注意的是zend的hash table是一個自增長的資料結構,當hash表數目滿了之後,其本身會動態以2倍的方式擴容並重新元素位置。初始大小均為8。另外,在進行 key->value快速查找時候,zend本身也做了一些優化,透過空間換時間的方式加快速度。例如在每個元素中都會用一個變數 nKeyLength來標識key的長度以作快速判定。 
雙向鍊錶:Zend hash table透過一個鍊錶結構,實現了元素的線性遍歷。理論上,做遍歷使用單向鍊錶就夠了,之所以使用雙向鍊錶,主要目的是為了快速刪除,避免遍歷。 Zend hash table是一種複合型的結構,作為數組使用時,即支援常見的關聯數組也能夠作為順序索引數字來使用,甚至允許2者的混合。 
PHP關聯陣列:關聯陣列是典型的hash_table應用。一個查詢過程經過以下幾步(從程式碼可以看出,這是一個常見的hash查詢過程並增加一些快速判定加速查找):

01  getKeyHashValue h;
02  index = n & nTableMask;
03  Bucket *p = arBucket[index];
04  while (p) {
05      if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
06          RETURN p->data;   
07      }
08      p=p->next;
09  }
10  RETURN FALTURE;
登入後複製
登入後複製

PHP索引數組:索引數組就是我們常見的數組,透過下標訪問。例如 arr[0],Zend HashTable內部進行了歸一化處理,對於index類型key同樣分配了hash值和nKeyLength(為0)。內部成員變數 nNextFreeElement就是目前被指派的最大id,每次push後自動加一。正是這種歸一化處理,PHP才能夠實現關聯和非關聯的混合。 由於 push運算的特殊性,索引key在PHP數組中先後順序並不是透過下標大小來決定,而是由push的先後決定。 例如arr[1] = 2; arr[2] = 3;對於double類型的key,Zend HashTable會將他當做索引key處理

5.2 PHP變數的實作原理

PHP是一門弱型別語言,不嚴格區分變數的類型。 PHP的變數可以分為簡單型別(int、sting、bool)、集合型別(array, resource, object) 和常數(const),所有的變數在底層都所以同一種結構zval

zval是zend中非常重要的資料結構,用來標示並實作php的變量,其資料結構如下:

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;  /* variable ref count */
    zend_uchar type;          /* active type */
    zend_uchar is_ref__gc;    /* if it is a ref variable */
};
typedef struct _zval_struct zval;
登入後複製
登入後複製

其中,

  • zval_value value是變數的實際值,具體來說是一個zvalue_value

    typedef union _zvalue_value {
        long lval;                  /* long value */
        double dval;                /* double value */
        struct {                    /* string */
            char *val;
            int len;
        } str;
        HashTable *ht;              /* hash table value,used for array */
        zend_object_value obj;      /* object */
    } zvalue_value;
    登入後複製
    登入後複製
  • zend_uint refcount__gc

    是一個計數器,用來保存多少變數(或符號,symbols )指向了該zval。在變數生成時,其refcount=1,典型的賦值運算如$a = $b會令zval的refcount加1,而unset操作會對應的減1。在PHP5.3之前,使用引用計數的機制來實作GC,如果一個zval的refcount較少到0,那麼Zend引擎會認為沒有任何變數指向該zval,因此會釋放該zval所佔的記憶體空間。但,事情有時並不會那麼簡單。後面我們會看到,單純的引用計數機制無法GC掉循環引用的zval,即使指向該zval的變數已經被unset,從而導致了記憶體洩漏(Memory Leak)。

  • zend_uchar type

    此欄位用來表示變數的實際型別。 PHP中的變數包括四種標量類型(bool,int,float,string),兩種複合類型(array, object)和兩種特殊的類型(resource 和NULL)。在zend內部,這些型別對應到下面的巨集(程式碼位置 phpsrc/Zend/zend.h)

    #define IS_NULL     0
    #define IS_LONG     1
    #define IS_DOUBLE   2
    #define IS_BOOL     3
    #define IS_ARRAY    4
    #define IS_OBJECT   5
    #define IS_STRING   6
    #define IS_RESOURCE 7
    #define IS_CONSTANT 8
    #define IS_CONSTANT_ARRAY   9
    #define IS_CALLABLE 10
    登入後複製
    登入後複製
  • is_ref__gc

    這個欄位用來標記變數是否是引用變數。對於普通的變量,該值為0,而對於引用型的變量,該值為1。這個變數會影響zval的共享、分離等

5.2.1 整數、浮點數變數

整數、浮點數是PHP中的基礎型之一,也是一個簡單型變數。對於整數和浮點數,在zvalue中直接儲存對應的值。其型別分別是long和double。
從zvalue結構可以看出,對於整數型,和c等強型別語言不同,PHP是不區分int、unsigned int、long、long long等型式的,對它來說,整數只有一種型別也就是long。由此,可以看出,在PHP裡面,整數的值範圍是由編譯器位數來決定而不是固定不變的。在php中如果整數越界了會發生什麼事? php會自動將整數轉換成浮點數型別

對於浮點數,類似整數,它也不區分float和double而是統一隻有double一種型別

5.2.2 字元變數

和整數一樣,字元變數也是PHP中的基礎型別和簡單型變數。透過zvalue結構可以看出,在PHP中,字串是由指向實際資料的指標和長度結 構體組成,這點和c++中的string比較類似。由於透過一個實際變數表示長度,和c不同,它的字串可以是2進位資料(包含0),同時在PHP中, 求字串長度strlen是O(1)運算

常見的字串拼接方式及速度比較:

假設有以下4個變數:strA='123'; strB = '456'; intA=123; intB=456; 
現在對如下的幾種字串拼接方式做一個比較和說明: 
1 res = strA.strB和res = “strAstrB” 
這種情況下,zend會重新malloc一塊記憶體並進行對應處理,其速度一般。
2 strA = strA.strB 
這種是速度最快的,zend會在當前strA基礎上直接relloc,避免重複拷貝 
3 res = intA.intB 
這種速度較慢,因為需要做式的格式轉換,實際編寫程式中也應該注意盡量避免 
4 strA = sprintf (“%s%s”,strA,strB); 
這會是最慢的一種方式,因為sprintf在PHP中並不是語言結構,本身對於格式辨識與處理就需要耗費比較多時間,另外本身機制也是malloc。不過sprintf的方式最具可讀性,實際中可以根據具體情況靈活選擇。

5.2.3 陣列變數

PHP的陣列是透過Zend Hash Table來天然實作。

foreach操作如何實現? 對一個陣列的foreach就是透過遍歷hashtable中的雙向鍊錶完成。對於索引數組,通過foreach遍 歷效率比for高很多,省去了key->value的查找。 count操作直接呼叫 HashTable->NumOfElements,O(1)操作。對於’123’這樣的字串,zend會轉換為其整數形 式。 arr[‘123’]和arr[123]

5.3 PHP變數管理-引用計數和寫時拷貝

引用計數在記憶體回收、字串操作等地方使用非常廣泛。 Zval的引用計數透過成員變數is_ref和ref_count實現,透過引用計數,多個變數可以共享同一份資料。避免頻繁拷貝帶來的大量消耗。當進行賦值操作時,zend將變數指向相同的zval同時ref_count++,在unset操作時,對應的ref_count-1。只有ref_count減為0時才會真正執行銷毀操作。 如果是引用賦值,則zend會修改is_ref為1。

PHP變數透過引用計數實現變數共享數據,那如果改變其中一個變數值呢?當試圖寫入一個變數時,Zend若發現該變數指向的zval被多個變數共享,則為其複製一份ref_count為1的zval,並遞減原zval的refcount,這個過程稱為「zval分離」。可見,只有在有寫操作發生時zend才進行拷貝操作,因此也叫copy-on-write(寫時拷貝)

對於引用型變量,其要求和非引用型相反,引用賦值的變量間必須是捆綁的,修改一個變數就修改了所有捆綁變數。

5.4 PHP局部變數和全域變數的實作:

PHP中的局部變數和全域變數是如何實現的?對於一個請求,任意時刻PHP都可以看到兩個符號表(symbol_table和 active_symbol_table),前者用來維護全域變數。後者是指針,指向目前活動的變數符號表,當程式進入某個函數時,zend 就會為它指派一個符號表x同時將active_symbol_table指向a。透過這樣的方式實現全域、局部變數的區分。

取得變數值:PHP的符號表是透過hash_table實現的,對於每個變數都分配唯一標識,取得的時候根據標識從表中找到對應zval返回。

函數中使用全域變數:在函數中,我們可以透過明確申明global來使用全域變數。 在active_symbol_table中建立symbol_table中同名變數的引用(引用變數的值要更新大家會一起更新),如果symbol_table中沒有同名變數則會先建立。

更多PHP執行原理 相關文章請關注PHP中文網!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

11個最佳PHP URL縮短腳本(免費和高級) 11個最佳PHP URL縮短腳本(免費和高級) Mar 03, 2025 am 10:49 AM

11個最佳PHP URL縮短腳本(免費和高級)

Instagram API簡介 Instagram API簡介 Mar 02, 2025 am 09:32 AM

Instagram API簡介

在Laravel中使用Flash會話數據 在Laravel中使用Flash會話數據 Mar 12, 2025 pm 05:08 PM

在Laravel中使用Flash會話數據

構建具有Laravel後端的React應用程序:第2部分,React 構建具有Laravel後端的React應用程序:第2部分,React Mar 04, 2025 am 09:33 AM

構建具有Laravel後端的React應用程序:第2部分,React

簡化的HTTP響應在Laravel測試中模擬了 簡化的HTTP響應在Laravel測試中模擬了 Mar 12, 2025 pm 05:09 PM

簡化的HTTP響應在Laravel測試中模擬了

php中的捲曲:如何在REST API中使用PHP捲曲擴展 php中的捲曲:如何在REST API中使用PHP捲曲擴展 Mar 14, 2025 am 11:42 AM

php中的捲曲:如何在REST API中使用PHP捲曲擴展

在Codecanyon上的12個最佳PHP聊天腳本 在Codecanyon上的12個最佳PHP聊天腳本 Mar 13, 2025 pm 12:08 PM

在Codecanyon上的12個最佳PHP聊天腳本

宣布 2025 年 PHP 形勢調查 宣布 2025 年 PHP 形勢調查 Mar 03, 2025 pm 04:20 PM

宣布 2025 年 PHP 形勢調查

See all articles