深入淺出PHP Exploring PHP

2021-06-01 20:19:32 字數 2944 閱讀 3190

一直以來,橫觀國內的php現狀,很少有專門介紹php內部機制的書。呵呵,我會隨時記錄下研究的心得,有機會的時候,彙總成書。:)

今天這篇,我內心是想打算做為乙個導論:

php是乙個被廣泛應用的指令碼語言,因為它的成功,所以很多時候,我們應用php的時候是更不不需要考慮底層到底是怎麼實現的。我相信大多數的 php程式 員是不會去考慮這一點的。從我接觸php開始,到今天也就是3年,這三年裡,前倆年我一直都是在」用」php,每次寫出來一段指令碼,我就會想「恩,不用擔 心,php直譯器會知道我想做什麼的」,直到去年來到雅虎,接受了乙個工作,是做乙個php的extension,從這個時候開始,我就好奇於新接觸的一 大堆的新鮮事物,zend, tsrm, zval, hashtable, op_array…

於是我到處查閱資料,每次獲得一篇好的文章,或者一段好的文字我就會如獲珍寶,列印儲存起來,細細研讀。我發現,國內關於php內部的資料真是少的 可憐, 不知道是因為懂得的人多但是不願意分享,還是懂得的人本來就少,所以,這條路,我走的很辛苦。於是,就會有了這篇文章。

在這篇文章中,我會從整個php的執行期入手,大致的介紹下各個階段,詞法分析,語法分析,op code等等,以後的文章我會再詳細介紹每個階(當然,如果你急不可耐的想知道詳細,呵呵,那麼可以直接聯絡我)。

從最初我們編寫的php指令碼->到最後指令碼被執行->得到執行結果,這個過程,其實可以分為如下幾個階段(鄙視:csdn不能上圖):

首先,zend engine(ze),呼叫詞法分析器(lex生成的,原始檔在 zend/zend_language_sanner.l), 將我們要執行的php原始檔,去掉空格 ,注釋,分割成乙個乙個的token。

然後,ze會將得到的token forward給語法分析器(yacc生成, 原始檔在 zend/zend_language_parser.y),生成乙個乙個的op code,opcode一般會以op array的形式存在,它是php執行的中間語言。

最後,ze呼叫zend_executor來執行op array,輸出結果。

ze是乙個虛擬機器,正是由於它的存在,所以才能使得我們寫php指令碼,完全不需要考慮所在的作業系統型別是什麼。ze是乙個cisc(複雜指令處理器), 它支援150條指令(具體指令在 zend/zend_vm_opcodes.h),包括從最簡單的zend_echo(echo)到複雜的 zend_include_or_eval(include,require),所有我們編寫的php都會最終被處理為這150條指令(op code)的序列,從而最終被執行。

接下來,讓我們嘗試用vld來檢視一段簡單的php指令碼的中間語言。

原始**:

<?php

$i=

「this is a string「;

//i am comments

echo$i.

『that has been echoed to screen『;

?>

採用vld得到的op codes:

filename

:/home

/desktop

/vldoutone

.php

function

name: (

null

)number

ofops: 7

line

#  op                 fetch       ext  operands20

fetch_w

local$0

, 『i『

1assign$0

, 『this+is+a+string『4

2fetch_r

local$2

, 『i『

3concat~3

, $2,『

+that+has+been+echoed+to+screen『4

echo~3

65return16

zend_handle_exception

我們可以看到,原始檔中的注釋,在op code中,已經沒有了,所以不用擔心注釋太多會影響你的指令碼執行時間(實際上,它是會影響ze的詞法處理階段的用時而已)。

現在我們來一條一條的分析這段op codes,每一條op code 又叫做一條op_line,都由如下7個部分,在zend_compile.h中,我們可以看到如下定義:

struct

_zend_op

;其中,opcode欄位指明了這操作型別,handler指明了處理器,然後有倆個運算元,和乙個操作結果。

fetch_w, 是以寫的方式獲取乙個變數,此處是獲取變數名」i」的變數於$0(*zval)。

將字串」this+is+a+string」賦值(assign)給$0

字串連線

顯示可以看出,這個很類似於很多同學大學學習編譯原理時候的三元式,不同的是,這些中間**會被zend vm(zend虛擬機器)直接執行。

真正負責執行的函式是,zend_execute, 檢視zend_execute.h:

zend_api extern

void

(*zend_execute)(

zend_op_array

*op_array

tsrmls_dc);

可以看出, zend_execute接受zend_op_array*作為引數。

struct _zend_op_array 

;

可以看到,zend_op_array的結構和zend_function的結構很像(參看我的其他文章), 對於在全域性作用域的**,就是不包含在任何function內的op_array,它的function_name為null。結構中的opcodes保 存了屬於這個op_array的op code陣列,zend_execute會從start_op開始,逐條解釋執行傳入的每條op code, 從而實現我們php指令碼想要的結果。

下一次,我將介紹php變數的靈魂 – zval, 你將會看到php是如何實現它的變數傳遞,型別戲法,等等。

深入淺出sizeof

int佔 位元組,short佔 位元組 1.0 回答下列問題 答案在文章末尾 1.sizeof char 2.sizeof a 3.sizeof a 4.strlen a 如果你答對了全部四道題,那麼你可以不用細看下面關於sizeof的論述。如果你答錯了部分題目,那麼就跟著我來一起 關於sizeof...

深入淺出ShellExecute

ipconfig c log.txt應如何處理?二樓的朋友,開啟拔號網路這樣 shellexecute null,open c windows rundll32.exe shell32.dll,control rundll c windows system telephon.cpl null,sw ...

深入淺出ShellExecute

深入淺出shellexecute譯者 徐景周 原作 nishant s q 如何開啟乙個應用程式?shellexecute this m hwnd,open calc.exe sw show 或shellexecute this m hwnd,open notepad.exe c mylog.log...