溫馨提示×

溫馨提示×

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

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

PHP是解釋型還是編譯型語言

發(fā)布時間:2021-06-21 10:05:22 來源:億速云 閱讀:109 作者:chen 欄目:編程語言

本篇內(nèi)容主要講解“PHP是解釋型還是編譯型語言”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“PHP是解釋型還是編譯型語言”吧!

編譯型語言

  • 使用專門的編譯器(類似于Windows下的Visual Studio)、針對特定平臺(操作系統(tǒng))將某種高級語言源代碼一次性“翻譯”成該平臺硬件執(zhí)行的機器碼(包括機器指令和操作數(shù)),并包裝成該平臺所能識別的可執(zhí)行性程序(.exe)的格式,這個轉(zhuǎn)換過程稱為編譯(Compile)。編譯生成的可執(zhí)行程序可以以脫離開發(fā)環(huán)境,在特定的平臺上獨立運行。有些程序在編譯結(jié)束之后,還可能需要對其他編譯好的目標代碼進行鏈接,即組裝兩個以上的目標代碼模塊生成最終的可執(zhí)行程序,通過這種方式實現(xiàn)低層次的代碼復用。

  • 編譯型語言的代碼是一次編譯,循環(huán)使用。換句話說就是前人種樹,后人乘涼。

  • C、C++、Objective -C 等都屬于編譯型語言

解釋型語言

  • 在程序運行前將源程序預編譯成中間語言,然后再由解釋器執(zhí)行中間語言

  • 每次執(zhí)行解釋型語言的程序都需要進行一次編譯,因此解釋型語言的程序運行效率通常較低,而且它不能脫離解釋器獨立運行。

  • C#、PHP、Python、Java等都是解釋型語言。

OK,通過上面概念的簡單了解,你可能對解釋型、編譯型語言有了一個大概的了解。既然兩者平分天下,下面我們就來看一下兩者各有什么優(yōu)勢吧。

編譯型語言

優(yōu)勢

  • 編譯型語言最大的優(yōu)勢之一就是其執(zhí)行速度。用C/C++編寫的程序運行速度要比用Java編寫的相同程序快30%-70%。

  • 編譯型程序比解釋型程序消耗的內(nèi)存更少。

劣勢

  • 不利的一面——編譯器比解釋器要難寫得多

  • 編譯器在調(diào)試程序時提供不了多少幫助——有多少次在你的C語言代碼中遇到一個“空指針異?!睍r,需要花費好幾個小時來明確錯誤到底在代碼中的什么位置。

  • 可執(zhí)行的編譯型代碼要比相同的解釋型代碼大許多。例如,C/C++的.exe文件要比同樣功能的Java的.class文件大很多。

  • 編譯型程序是面向特定平臺的因而是平臺依賴的。

  • 編譯型程序不支持代碼中實現(xiàn)安全性——例如,一個編譯型的程序可以訪問內(nèi)存的任何區(qū)域,并且可以對你的PC做它想做的任何事情(大部分病毒是使用編譯型語言編寫的)

  • 由于松散的安全性和平臺依賴性,編譯型語言不太適合開發(fā)因特網(wǎng)或者基于Web的應用。

解釋型語言

優(yōu)勢

  • 極佳的調(diào)試支持。一名PHP程序員只需要幾分鐘就可以定位并修復一個“空指針異常”,因為PHP運行環(huán)境不僅指明了異常的性質(zhì),而且給出了異常發(fā)生位置具體的行號和函數(shù)調(diào)用順序(著名的堆棧跟蹤信息)。這樣的便利是編譯型語言所無法提供的。

  • 解釋器比編譯器容易實現(xiàn)

  • 極佳的平臺獨立性

  • 高度的安全性——這是互聯(lián)網(wǎng)應用迫切需要的

  • 中間語言代碼的大小比編譯型可執(zhí)行代碼小很多

劣勢

  • 占用更多的內(nèi)存和CPU資源。這是由于,為了運行解釋型語言編寫的程序,相關的解釋器必須首先運行。解釋器是復雜的,智能的,大量消耗資源的程序并且它們會占用很多CPU周期和內(nèi)存。

  • 運行效率較編譯型程序慢很多。解釋器會做很多代碼優(yōu)化,運行時安全性檢查;這些額外的步驟占用了更多的資源并進一步降低了應用的運行速度。

OK,通過上面的學習,相信大家對解釋型語言與編譯型語言有了大致的了解,而且PHP語言是解釋型語言,而且解釋PHP語言的解釋器就是Zend引擎。

而且,根據(jù)兩者的優(yōu)劣勢比較可以發(fā)現(xiàn),編譯型語言更適合做底層的操作,而解釋型語言較多的用在了Web開發(fā)上。

再深入探討下PHP的執(zhí)行過程:

php的編譯和執(zhí)行是分離開的,亦即:先執(zhí)行完編譯,而后再執(zhí)行。很多人會說:c++也是如此啊,確實。不過php的這種分離可以給我們提供很多便利,當然不可避免也有很有缺點。

先說一下整個過程:

①php會調(diào)用編譯函數(shù)zend_compile_file()來進行編譯。 這個函數(shù)的具體實現(xiàn)其實是包括兩個主要過程的:詞法分析(Lex實現(xiàn)),語法分析(Yacc實現(xiàn))。當執(zhí)行完這個函數(shù)之后:php腳本的編譯就算結(jié)束了。 這個函數(shù)的輸入是:php腳本文件,而輸出則是op_array.簡單一點說:編譯過程就是把腳本給解析成一條條php虛擬機可以處理的指令,而op_array就是這些指令做成的一個array而已(這很類似一些編譯型語言編譯產(chǎn)生的匯編代碼了,也是一條條的命令)。

②:之后php虛擬機會調(diào)用zend_execute()這個函數(shù)來執(zhí)行。該函數(shù)的輸入就是上邊編譯階段產(chǎn)生的op_array,在這里他會解析每條命令并進行處理。 由于op命令一共有150左右,所以它需要處理這150中命令。這里會產(chǎn)生一個很有意思的問題:它是如何處理這150種命令的呢?首先每條命令都是有對應的處理器來進行處理的。所以:虛擬機會依據(jù)op_array中各條命令的類型來分發(fā)給響應的處理器來進行處理。

這里有兩個小問題: 1:這里的處理器是什么?  2:如何分發(fā)的?

要解答這兩個問題都是要從分發(fā)機制上來解釋:php虛擬機分發(fā)命令的機制有三種:CALL, SWITCH, 和GOTO這三種類型.php默認是使用CALL方式, 也就是所有的opcode處理器都定義為函數(shù), 然后供虛擬機調(diào)用. 這種方式是傳統(tǒng)的方式, 也一般被認為是最穩(wěn)定的方式.而SWITCH方式和GOTO方式則是通過switch和goto來分發(fā)opcode到對應的處理邏輯(段)執(zhí)行的.

那現(xiàn)在來回答上邊兩個問題:

1:處理器其實是處理op命令的邏輯。其可以以函數(shù)的形式存在,也可能是以邏輯段的方式存在,這取決于命令的分發(fā)方式。

2:分發(fā)方式有call,switch和goto三種。哪種效率高呢?其實從上邊解釋已經(jīng)可以初步了解了。switch和goto都是在zend_execute()這個函數(shù)中有對應的邏輯段,直接執(zhí)行就可以了。而call是在zend_execute()這個函數(shù)中執(zhí)行函數(shù)調(diào)用。明擺著:函數(shù)調(diào)用效率是最低的,調(diào)用一次就得壓棧啊!所以效率上:call是最低的。對于switch和goto:比如要執(zhí)行第三種命令的處理:switch還要先挨個判斷是不是前兩種,而goto根本不需要判斷,直接跳到第三種命令的邏輯代碼段去執(zhí)行,這比switch少了順序從上到下判斷的損耗,所以:goto效率又比switch要高。  所以這三種分發(fā)方式總體而言:goto > switch > call

再說一下php這種編譯和執(zhí)行分離的弱點:

其實也不能算是弱點,雖然zend engine(php的虛擬機)將編譯和執(zhí)行嚴格分開,但是對于用戶而言:就跟沒分開一樣,因為我每次執(zhí)行一個php腳本請求都是要執(zhí)行:編譯->執(zhí)行  這兩個階段。任何一個階段都少不了。那么這一點我們可以拿來和c++這種編譯型語言做一下對比: 同一個請求運行100遍

①對于c++,由于其前期只要編譯一遍,編譯好就不會再重復編譯了,只需要執(zhí)行就ok,所以其損耗為:

1次編譯 + 100次執(zhí)行

②對于php,其每次都要編譯+執(zhí)行,所以其損耗為:

100次編譯 + 100次執(zhí)行

顯然:解釋性語言從數(shù)量上來看:其消耗是比編譯型語言多的多。說白了就是:php這種編譯和執(zhí)行相分離并不是真正的分離。而c++那種才算是真正的分離。

php也早就意識到這個問題了,于是就想了一個辦法來解決這個問題:這個解決方案就是eAccelerator。主要思路如下:

當腳本第一次運行后,以某種方式保存編譯后腳本(里邊存放的是op_array),在我們規(guī)定的緩存有效時間內(nèi),當?shù)诙芜\行該腳本時就不在進行重復性的編譯工作,而是直接調(diào)用執(zhí)行前面保存的編譯后文件,大大提高了程序性能。

最后說一下php編譯和執(zhí)行分離的優(yōu)點;

這個優(yōu)點其實是針對程序員而言,對用戶而言沒什么。因為這兩個階段的分離,我們可以在這里做一些我們想做的事情。

比如想做文件加解密,你想把一些php腳本源碼文件加密,讓用戶看不到源碼。同時呢這個加密后的源碼文件又可以被php虛擬機所解析和處理。當然:要實現(xiàn)這個前提是你先想好加解密算法并保證這個是可逆的過程。

現(xiàn)在你對php源碼文件已經(jīng)加密了,此時你需要定義一下這種加密文件的后綴,假設為:*.buaa。 那問題就是:我們怎么讓php虛擬機可以處理這種后綴的文件呢?這就要用到上邊所說的編譯和執(zhí)行相分離的過程了。

回想一下:編譯階段的輸入是php源文件,輸出是op_array。 ok,我們就在這個階段做文章。主要思路為:首先在zend_compile_file()這個編譯函數(shù)中:看一下輸入文件的后綴:如果是正常的.php那就走正常邏輯,如果是*.buaa,那就先解密然后再走正常邏輯。。。

結(jié)論:

  • PHP是解釋型語言,將PHP代碼解釋為opcode之后再交由Zend引擎執(zhí)行。

  • 使用APC緩存了opcode,減少了PHP解釋為opcode這一步驟的時間。

到此,相信大家對“PHP是解釋型還是編譯型語言”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關內(nèi)容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

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

php
AI