您好,登錄后才能下訂單哦!
這篇文章主要介紹PHP指的是解釋型語言還是編譯型語言,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
編譯型語言
使用專門的編譯器(類似于Windows下的Visual Studio)、針對特定平臺(tái)(操作系統(tǒng))將某種高級語言源代碼一次性“翻譯”成該平臺(tái)硬件執(zhí)行的機(jī)器碼(包括機(jī)器指令和操作數(shù)),并包裝成該平臺(tái)所能識(shí)別的可執(zhí)行性程序(.exe)的格式,這個(gè)轉(zhuǎn)換過程稱為編譯(Compile)。編譯生成的可執(zhí)行程序可以以脫離開發(fā)環(huán)境,在特定的平臺(tái)上獨(dú)立運(yùn)行。有些程序在編譯結(jié)束之后,還可能需要對其他編譯好的目標(biāo)代碼進(jìn)行鏈接,即組裝兩個(gè)以上的目標(biāo)代碼模塊生成最終的可執(zhí)行程序,通過這種方式實(shí)現(xiàn)低層次的代碼復(fù)用。
編譯型語言的代碼是一次編譯,循環(huán)使用。換句話說就是前人種樹,后人乘涼。
C、C++、Objective -C 等都屬于編譯型語言
解釋型語言
在程序運(yùn)行前將源程序預(yù)編譯成中間語言,然后再由解釋器執(zhí)行中間語言
每次執(zhí)行解釋型語言的程序都需要進(jìn)行一次編譯,因此解釋型語言的程序運(yùn)行效率通常較低,而且它不能脫離解釋器獨(dú)立運(yùn)行。
C#、PHP、Python、Java等都是解釋型語言。
OK,通過上面概念的簡單了解,你可能對解釋型、編譯型語言有了一個(gè)大概的了解。既然兩者平分天下,下面我們就來看一下兩者各有什么優(yōu)勢吧。
編譯型語言
優(yōu)勢
編譯型語言最大的優(yōu)勢之一就是其執(zhí)行速度。用C/C++編寫的程序運(yùn)行速度要比用Java編寫的相同程序快30%-70%。
編譯型程序比解釋型程序消耗的內(nèi)存更少。
劣勢
不利的一面——編譯器比解釋器要難寫得多
編譯器在調(diào)試程序時(shí)提供不了多少幫助——有多少次在你的C語言代碼中遇到一個(gè)“空指針異常”時(shí),需要花費(fèi)好幾個(gè)小時(shí)來明確錯(cuò)誤到底在代碼中的什么位置。
可執(zhí)行的編譯型代碼要比相同的解釋型代碼大許多。例如,C/C++的.exe文件要比同樣功能的Java的.class文件大很多。
編譯型程序是面向特定平臺(tái)的因而是平臺(tái)依賴的。
編譯型程序不支持代碼中實(shí)現(xiàn)安全性——例如,一個(gè)編譯型的程序可以訪問內(nèi)存的任何區(qū)域,并且可以對你的PC做它想做的任何事情(大部分病毒是使用編譯型語言編寫的)
由于松散的安全性和平臺(tái)依賴性,編譯型語言不太適合開發(fā)因特網(wǎng)或者基于Web的應(yīng)用。
解釋型語言
優(yōu)勢
極佳的調(diào)試支持。一名PHP程序員只需要幾分鐘就可以定位并修復(fù)一個(gè)“空指針異?!保?yàn)镻HP運(yùn)行環(huán)境不僅指明了異常的性質(zhì),而且給出了異常發(fā)生位置具體的行號和函數(shù)調(diào)用順序(著名的堆棧跟蹤信息)。這樣的便利是編譯型語言所無法提供的。
解釋器比編譯器容易實(shí)現(xiàn)
極佳的平臺(tái)獨(dú)立性
高度的安全性——這是互聯(lián)網(wǎng)應(yīng)用迫切需要的
中間語言代碼的大小比編譯型可執(zhí)行代碼小很多
劣勢
占用更多的內(nèi)存和CPU資源。這是由于,為了運(yùn)行解釋型語言編寫的程序,相關(guān)的解釋器必須首先運(yùn)行。解釋器是復(fù)雜的,智能的,大量消耗資源的程序并且它們會(huì)占用很多CPU周期和內(nèi)存。
運(yùn)行效率較編譯型程序慢很多。解釋器會(huì)做很多代碼優(yōu)化,運(yùn)行時(shí)安全性檢查;這些額外的步驟占用了更多的資源并進(jìn)一步降低了應(yīng)用的運(yùn)行速度。
OK,通過上面的學(xué)習(xí),相信大家對解釋型語言與編譯型語言有了大致的了解,而且PHP語言是解釋型語言,而且解釋PHP語言的解釋器就是Zend引擎。
而且,根據(jù)兩者的優(yōu)劣勢比較可以發(fā)現(xiàn),編譯型語言更適合做底層的操作,而解釋型語言較多的用在了Web開發(fā)上。
再深入探討下PHP的執(zhí)行過程:
php的編譯和執(zhí)行是分離開的,亦即:先執(zhí)行完編譯,而后再執(zhí)行。很多人會(huì)說:c++也是如此啊,確實(shí)。不過php的這種分離可以給我們提供很多便利,當(dāng)然不可避免也有很有缺點(diǎn)。
先說一下整個(gè)過程:
①php會(huì)調(diào)用編譯函數(shù)zend_compile_file()來進(jìn)行編譯。 這個(gè)函數(shù)的具體實(shí)現(xiàn)其實(shí)是包括兩個(gè)主要過程的:詞法分析(Lex實(shí)現(xiàn)),語法分析(Yacc實(shí)現(xiàn))。當(dāng)執(zhí)行完這個(gè)函數(shù)之后:php腳本的編譯就算結(jié)束了。 這個(gè)函數(shù)的輸入是:php腳本文件,而輸出則是op_array.簡單一點(diǎn)說:編譯過程就是把腳本給解析成一條條php虛擬機(jī)可以處理的指令,而op_array就是這些指令做成的一個(gè)array而已(這很類似一些編譯型語言編譯產(chǎn)生的匯編代碼了,也是一條條的命令)。
②:之后php虛擬機(jī)會(huì)調(diào)用zend_execute()這個(gè)函數(shù)來執(zhí)行。該函數(shù)的輸入就是上邊編譯階段產(chǎn)生的op_array,在這里他會(huì)解析每條命令并進(jìn)行處理。 由于op命令一共有150左右,所以它需要處理這150中命令。這里會(huì)產(chǎn)生一個(gè)很有意思的問題:它是如何處理這150種命令的呢?首先每條命令都是有對應(yīng)的處理器來進(jìn)行處理的。所以:虛擬機(jī)會(huì)依據(jù)op_array中各條命令的類型來分發(fā)給響應(yīng)的處理器來進(jìn)行處理。
這里有兩個(gè)小問題: 1:這里的處理器是什么? 2:如何分發(fā)的?
要解答這兩個(gè)問題都是要從分發(fā)機(jī)制上來解釋:php虛擬機(jī)分發(fā)命令的機(jī)制有三種:CALL, SWITCH, 和GOTO這三種類型.php默認(rèn)是使用CALL方式, 也就是所有的opcode處理器都定義為函數(shù), 然后供虛擬機(jī)調(diào)用. 這種方式是傳統(tǒng)的方式, 也一般被認(rèn)為是最穩(wěn)定的方式.而SWITCH方式和GOTO方式則是通過switch和goto來分發(fā)opcode到對應(yīng)的處理邏輯(段)執(zhí)行的.
那現(xiàn)在來回答上邊兩個(gè)問題:
1:處理器其實(shí)是處理op命令的邏輯。其可以以函數(shù)的形式存在,也可能是以邏輯段的方式存在,這取決于命令的分發(fā)方式。
2:分發(fā)方式有call,switch和goto三種。哪種效率高呢?其實(shí)從上邊解釋已經(jīng)可以初步了解了。switch和goto都是在zend_execute()這個(gè)函數(shù)中有對應(yīng)的邏輯段,直接執(zhí)行就可以了。而call是在zend_execute()這個(gè)函數(shù)中執(zhí)行函數(shù)調(diào)用。明擺著:函數(shù)調(diào)用效率是最低的,調(diào)用一次就得壓棧??!所以效率上:call是最低的。對于switch和goto:比如要執(zhí)行第三種命令的處理:switch還要先挨個(gè)判斷是不是前兩種,而goto根本不需要判斷,直接跳到第三種命令的邏輯代碼段去執(zhí)行,這比switch少了順序從上到下判斷的損耗,所以:goto效率又比switch要高。 所以這三種分發(fā)方式總體而言:goto > switch > call
題外話:由于php默認(rèn)是call,如果你想進(jìn)一步榨干php的效能,可以更改下其命令分發(fā)方式為goto。不過用goto方式雖然提高了執(zhí)行速度,但是編譯速度上其實(shí)最慢的喔。
--------------------------------------------------------------------------------------------------------------------------------------------------
再說一下php這種編譯和執(zhí)行分離的弱點(diǎn):
其實(shí)也不能算是弱點(diǎn),雖然zend engine(php的虛擬機(jī))將編譯和執(zhí)行嚴(yán)格分開,但是對于用戶而言:就跟沒分開一樣,因?yàn)槲颐看螆?zhí)行一個(gè)php腳本請求都是要執(zhí)行:編譯->執(zhí)行 這兩個(gè)階段。任何一個(gè)階段都少不了。那么這一點(diǎn)我們可以拿來和c++這種編譯型語言做一下對比: 同一個(gè)請求運(yùn)行100遍
①對于c++,由于其前期只要編譯一遍,編譯好就不會(huì)再重復(fù)編譯了,只需要執(zhí)行就ok,所以其損耗為:
1次編譯 + 100次執(zhí)行
②對于php,其每次都要編譯+執(zhí)行,所以其損耗為:
100次編譯 + 100次執(zhí)行
顯然:解釋性語言從數(shù)量上來看:其消耗是比編譯型語言多的多。說白了就是:php這種編譯和執(zhí)行相分離并不是真正的分離。而c++那種才算是真正的分離。
php也早就意識(shí)到這個(gè)問題了,于是就想了一個(gè)辦法來解決這個(gè)問題:這個(gè)解決方案就是eAccelerator。主要思路如下:
當(dāng)腳本第一次運(yùn)行后,以某種方式保存編譯后腳本(里邊存放的是op_array),在我們規(guī)定的緩存有效時(shí)間內(nèi),當(dāng)?shù)诙芜\(yùn)行該腳本時(shí)就不在進(jìn)行重復(fù)性的編譯工作,而是直接調(diào)用執(zhí)行前面保存的編譯后文件,大大提高了程序性能。
這種方式一定程度上提高了php的效率,但不是最終極的方法,最終極的還是改成編譯型語言那種方式好了,吼吼~~~
---------------------------------------------------------------------------------------------------------------------------------------------------
最后說一下php編譯和執(zhí)行分離的優(yōu)點(diǎn);
這個(gè)優(yōu)點(diǎn)其實(shí)是針對程序員而言,對用戶而言沒什么。因?yàn)檫@兩個(gè)階段的分離,我們可以在這里做一些我們想做的事情。
比如想做文件加解密,你想把一些php腳本源碼文件加密,讓用戶看不到源碼。同時(shí)呢這個(gè)加密后的源碼文件又可以被php虛擬機(jī)所解析和處理。當(dāng)然:要實(shí)現(xiàn)這個(gè)前提是你先想好加解密算法并保證這個(gè)是可逆的過程。
現(xiàn)在你對php源碼文件已經(jīng)加密了,此時(shí)你需要定義一下這種加密文件的后綴,假設(shè)為:*.buaa。 那問題就是:我們怎么讓php虛擬機(jī)可以處理這種后綴的文件呢?這就要用到上邊所說的編譯和執(zhí)行相分離的過程了。
回想一下:編譯階段的輸入是php源文件,輸出是op_array。 ok,我們就在這個(gè)階段做文章。主要思路為:首先在zend_compile_file()這個(gè)編譯函數(shù)中:看一下輸入文件的后綴:如果是正常的.php那就走正常邏輯,如果是*.buaa,那就先解密然后再走正常邏輯。。。
哈~就是這么簡單。當(dāng)然:這個(gè)過程沒有所說的這么簡單,而且你也不可能直接修改zend_compile_file()函數(shù),最后是自己擴(kuò)展實(shí)現(xiàn)一個(gè)模塊來處理這個(gè)過程。
結(jié)論:
PHP是解釋型語言,將PHP代碼解釋為opcode之后再交由Zend引擎執(zhí)行。
使用APC緩存了opcode,減少了PHP解釋為opcode這一步驟的時(shí)間。
以上是“PHP指的是解釋型語言還是編譯型語言”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。