【思考】PHP——成也Web,败也Web
背景
早年我并不知道Python寫的Web應用是怎么部署的,總覺得像PHP、ASP一樣,僅僅提供一個語言級別的執行模塊,直接嵌入Web服務器運行,甚至于直接對外提供帶擴展名的URL都是自然而然的事情。
前一陣學習了Python,總是如別人一樣,不自覺的和PHP進行對比。隨著學習的逐步深入,更發現PHP的發展受限于其Web出身,恐將來難成正經的通用開發語言。
先說說PHP從歷史到今天分別是怎么運行的: * CGI SAPI:由Web服務器的請求處理進程fork+exec這個CGI,用環境變量單向傳遞Headers給應用程序,應用程序從stdin讀request body,其stdout會被Web服務器作為response headers和body輸出給客戶端。Web服務器和PHP CGI的關系是父子進程間通信,當應用程序的響應速度較慢時(忙于計算、外部I/O等),會阻塞對應的Web服務器進程/線程 * Apache2Handler等Web服務器模塊類SAPI:Apache2調用Handler,并向其傳遞server_context;Handler利用server_context讀到Header、body等內容之后構造起PHP腳本的context,也就是$_SERVER之類,然后開始執行PHP腳本。而腳本執行的輸出也直接被Web服務器收集。PHP和Web服務器在同一個進程內執行,處于完全從屬的地位。Apache2Handler方式本來可以通過多線程等方式讓Apache不受PHP阻塞,但由于PHP社區的堅持,目前常見的Apache2+PHP配置都是prefork MPM的,以至于性能相當一般 * FastCGI SAPI:原理是把每次fork處理一個請求,變成一個不退出的循環,每循環一輪就處理一個請求;多進程listen在同一個socket上,實現并發。PHP-FPM是后來的一個民間補丁項目,提供了更好的進程管理和附加功能,處理完License問題之后,FPM合并入PHP主線。Web服務器和PHP的關系是網絡通信的關系,可以分離到不同服務器上部署。Web服務器可以使用多線程或者I/O復用技術來處理別的請求,性能會>比前二者好很多。但FPM的實現仍然不夠好。
PHP的各種擴展模塊,大都是偏重于數據庫、字符串處理等應用層面的功能,充分體現了其作為Web開發利器的特點;而對于I/O、POSIX基礎功能,則關注較少。 Web開發之外的領域,用PHP寫獨立運行的服務器,并不是主流的用法。其依賴的pcntl、pthread等模塊也是較晚加進來的,而且也沒啥人用。用以下幾個模塊可以很容易的創作一個獨立的HTTP靜態文件或SOA服務: 1. PEAR Net_Server(無人維護) 通用服務器框架 2. PEAR HTTP2 協議解析庫 3. PEAR HTTP_Server(無人維護) HTTP服務器框架 4. PECL pecl_HTTP(需要編譯) HTTP服務器框架,我沒編譯出來…… 但如果想在其中運行一般的Web PHP腳本,就需要用PHP本身實現一個SAPI: * 輸入方面是很容易仿制的,除了需要構造Predefined/Reserved Variables(感謝作者,$_SERVER等只是普通數組,只須填充內容就差不多了,而不像ASP那樣是復雜的Request對象)再寫一下上傳文件自動存盤的處理就差不多了 * 輸出方面就比較麻煩,因為“寫”是動作??紤]到PHP深深的“假設stdout”情結,須使用output buffer機制收集輸出內容。另外,header()函數等的實現可能會比較復雜
傳統上,協議解析是SAPI的工作,PHP從屬于Web服務器,以至于沒積累出什么好用的協議解析庫;而PHP書寫的Web應用向來都是直接調用SAPI提供的函數,積習難改,以至于想用PHP本身來寫Web服務器就須要去實現一個SAPI,但又會遭遇到這個語言本身的Web烙印太深、假設太多,以及不夠“動態”的問題。 傳統上,網絡通信向來也不須由PHP來處理,以至于也沒積累出什么好用的通信框架庫。
最終,PHP成了一個Web only的開發語言。真可謂成也Web、敗也Web。
一些新興的PECL擴展提供了高性能I/O框架,比如swoole,但因為上述SAPI的問題,目前尚未出現像Python那樣用PHP本身寫的PHP Web服務器。
相比之下,不用寫<%的Python語言,其發展道路就更加general purpose一些: 1. 標準庫中有os、multiprocess、threading、select等模塊,一看就是面向系統編程而非僅僅針對Web開發 2. 標準庫中的SocketServer及其MixIn classes、HTTPServer等可用于寫服務器;CGI模塊可用于解析HTTP協議請求 3. 標準庫中的wsgiref是純Python的。也就是說,用Python語言寫一個WSGI Server很容易且是提倡的做法 4. yield語法加入語言比較早,可以實現協程 在Web應用方面,Python的WSGI接口已經基本統一江湖。WSGI不是通信協議,而是語言級別的調用約定(關于這個函數后面帶幾個什么樣的參數的約定),而WSGI可以用純Python實現,因此不會遇見用PHP實現SAPI的尷尬。由于Python沒有像PHP那樣深深的Web烙印*(甚至早年在Web上的部署并不太方便)*加上標準庫中很早就帶有各種基礎模塊,導向結果就是出現了很多優秀的高性能框架和服務器軟件?,F在流行的組合是用 gunicorn WSGI Server運行WSGI應用程序,管理多個worker充分利用多處理器,用gevent消除I/O等待時的浪費;對外提供HTTP服務,前面套一個nginx提供靜態文件和訪問控制、rewrite等功能。
總結
以上是生活随笔為你收集整理的【思考】PHP——成也Web,败也Web的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 业务赋能利器之外卖特征档案
- 下一篇: PHP 开发者大会