PHP 又是一門相當奇怪的編程語言。當人們抱怨這門語言“很槽糕”時,他們并沒有說錯。這門語言確實有很多不好的地方。
擱在以前,這門語言還有更多糟糕的問題。嘲笑 PHP 的博文《全面解析 PHP 的槽糕設計》(PHP: a fractal of bad design)確實有幾個正確的觀點,即使這些觀點在九年前發表時就已經過時了。
然而,與此同時,開發人員卻可以利用 PHP 創建結構上“正確”的軟件,并從其他語言中引入被視為良好實踐的哲學。
像 Laminas 和 Symfony 這樣的框架就使用了面向對象編程的最佳實踐,使開發者可以用這些框架編寫結構正確的代碼。
PHP 是怎么做到這些的?這是因為 PHP 是最糟糕的編程語言。
設計軟件
1991 年,Richard P. Gabriel 發表了一篇文章《Lisp:好消息,壞消息,如何贏得大》(Lisp: Good News, Bad News, How to Win Big)。這篇文章的論點是,在軟件設計和壽命方面,“更糟就是更好”的哲學將是更好的選擇。
他之所以得出這一結論,是因為他意識到出現了兩種不同的程序設計流派,他分別將之命名為“麻省理工學院 / 斯坦福風格”(MIT/Standford Style),或者“正確的方式”,以及“新澤西風格”(New Jersey Style)或者“更糟就是更好”。
這兩種哲學的目標相似,但在關鍵領域卻有所不同。兩種風格都側重于哲學理念的四個關鍵領域:簡單性(Simplicity)、正確性(Correctness)、一致性(Consistency)和完整性(Completeness)。
麻省理工學院風格是這樣描述的:
- 簡單性:設計一定要簡單,不論它的實現還是接口,都一定要簡單。相較而言,讓接口保持簡單更重要。
- 正確性:在所有可以觀察到的方方面面,設計一定要正確。不要妄想做一個不正確的設計。
- 一致性:設計一定不能是不一致的。為了確保一致性,你可以略微犧牲簡單性和完整性。一致性和正確性同等重要。
- 完整性:設計一定要盡可能多地涵蓋重要的情況。所有符合預期的情況一定要被覆蓋到。完整性優先級應該高于簡單性。
至于新澤西風格,Gabriel 說,它將其目標定義為:
- 簡單性:設計一定要簡單,不論它的實現還是接口,都一定要簡單。而相較而言,讓實現保持簡單更重要。簡單是最重要的,其他的特性都不如保持簡單更重要。
- 正確性:在所有可以觀察到的方面,設計一定要正確。但是可以為了簡單而輕微犧牲正確性。
- 一致性:設計一定不能太過不一致。某些情況下,為了保證簡單可以犧牲一致性。如果將某個不常見的情況引入設計,會導致實現變復雜或者不一致,那么就不要考慮這種情況。
- 完整性:設計一定要盡可能多地涵蓋重要的情況。所有符合預期的情況一定要被覆蓋到。完整性可以為任何其他特性讓步。實際上,一旦威脅到實現的簡單性,完整性必須要被犧牲。如果為了保持簡單,可以犧牲一致性來實現完整性;尤其是接口的一致性。
這場爭論的關鍵是用 LISP 和 C 作為例子來說明為什么“更糟就是更好”。對于 LISP 程序員 Gabriel 來說,LISP 是一種比 C 更好的語言,速度和 C 一樣快,而且 Common LISP 的設計、開發和標準化已經花了很多年。
定義該語言的規范吸取了所有不同的 LISP 的精華,而現代開發環境對于 LISP 開發者來說是最好的。
LISP 是正確的方式
LISP 代表了軟件開發的“正確的方式”。LISP 易于交互,你可以通過各種方式與它交互。希望從 Fortran 中調用 LISP?
你可以從 Fortran 中調用 LISP 并將數據傳入,反之亦然。在使用遺留代碼時,你可以愉快地使用 LISP 的所有現代“豪華”特性。
LISP 擁有一致的設計,這得益于它的規范。假如你研究一下 Python 這樣的現代語言,規范在提供多個后端和編譯器方面有很大的作用,而且它們都以同樣的方式解釋或編譯代碼。
這些工具是一流的,1991 年的 LISP 擁有我們今天仍然享受的所有舒適,比如步驟調試、數據檢查和花哨的編輯器。
作為一種語言,LISP 是完備的。它具有先進的面向對象編程層、多重繼承、一流的對象以及函數和類型。LISP 似乎是開發人員心中想要的編程語言。
1991 年,LISP 這么編程語言可能處于有史以來的最佳狀態。這種技術上的正確性并沒有被實際使用所證實。
LISP 的開發商正在衰退。多年來負面新聞和錯誤定位阻礙了 LISP 的外部聲譽。人們不再將其視為向最終用戶交付軟件的方式。
就開發而言,LISP 往往代表著許多與“大規模預先設計”(Big Design Up Front,BDUF)一樣的理想。
假如你曾經使用過瀑布模型(Waterfall Model)這樣的設計方法,你就會發現一些問題。“正確的方式”非常強調一致性、正確性,并確保考慮到所有能想到的問題。
LISP 本身并非一種單一的語言,而是一個語言家族。盡管 Common LISP 被設計成一種標準,但是 LISP 本身的實現方式是根據需要完成的各種工作而存在的。
Lockless Inc 網站上的一篇文章指出,這種“碎片化”是 LISP 最終失敗的決定因素之一。盡管 LISP 堅持軟件設計的“正確的方式”,但是這種碎片化導致代碼維護和可移植性都受到了影響。
PHP 是最槽糕的
因此,“更糟就是更好”的軟件首先會被接受,其次它會使用戶期望更少,第三,這些軟件將被不斷改進,直到接近“正確的方法”的程度。——Richard Gabrie
在這一啟示的幾年后,Rasmus Lerdorf 開始研究個人主頁 / 表單解釋器,也就是我們現在所知的 PHP。
PHP/FI 的誕生是因為 Lerdorf 需要維護他的主頁,并與表單和數據庫進行交互。PHP/FI 甚至不是作為一種實際的編程語言設計的,而是作為 C 語言之上的一層腳本和函數設計的。
PHP 很簡單
設計一定要簡單,不論是它的實現還是接口。
PHP 底層使用了 C 語言,我們之前已經說過,這部分是“最糟糕的”。然而,這也帶來了一些優勢,最重要的是,更簡單的底層語言可以讓它更容易擴展。雖然 Hack/HHVM 采用了更多的 C++ 方法,但 PHP 本身仍然是 C 語言。
只需短短幾個小時就能學完這門語言的內部結構。Elizabeth Smith 發表過一篇關于 PHP 擴展的精彩演講,其中介紹了大量關于 PHP 的內部工作原理。這門語言本身借鑒了其他 C 風格的語言,不僅易于閱讀,并且能夠跟 C 風格的其他語言互相轉換。
PHP 的大多數接口,或者說標準庫,都非常簡單,因為大多數核心功能都只不過是包裝了各種 C 語言庫,然后幾乎原封不動地公開出來。盡管這樣做會導致接口上的一些不一致,但是它為來自 C 或 C++ 的開發者提供了一個熟悉的環境。
PHP 語言非常注重于 Web 開發。將 HTTP 中的概念提取出來并在語言中找到相似的概念通常非常簡單。希望了解一個請求的頭信息嗎?get_headers() 就能滿足你。獲取請求信息就像讀取 _POST 全局變量一樣簡單。
PHP 保持了簡單的開發者接口,并且盡可能地保持內部結構的簡單。
PHP(幾乎)是正確的
在所有可以觀察到的方面,設計一定要正確。但是可以為了簡單性而輕微犧牲正確性。
在這里,PHP 傾向于選擇“簡單”而不是正確。在 HHVM 出現之前,語言的外觀和特性一直沒有得到規范。
Zend 解釋器本身就是規范,并且這門語言的行為方式總是 “正確”的(不包括實際的錯誤)。要想用別的東西代替 PHP 引擎,就必須實現現有引擎的所有特性。
許多核心函數的 LAX 函數參數和返回類型都使得系統的工作更容易。像 strpos() 這樣的函數返回值可以是整型數或布爾值,相對于嚴格設計成返回整型數或拋出異常的方法,處理要稍微容易一些。
看 PHP 語言的發展,幾乎所有新特性都是建立在開發人員需要的基礎上,而不是“因為它錯了所以必須修復”的嚴肅想法。
更多地關注那些嚴格類型和異常錯誤是一種更正確的做事方法。然而,還有一些東西,比如簡短的箭頭函數(arrow function)、屬性和枚舉,才是開發者想要用來簡化代碼的東西。
PHP 不需要一致性
設計一定不能太過不一致。某些情況下,為了保持簡單可以犧牲一致性。
我甚至不打算假裝 PHP 是一致的,但是它的一致性已經足夠了。當涉及到數組與字符串函數時,人們可能會抱怨 needle/haystack 參數順序。
不過,一般而言,數組函數是一致的,而字符串函數也是一致的。與底層 C 庫保持一致比在語言中保持一致要簡單得多。
PHP 在其他方面也足夠一致。正如我在 strpos() 中提到的,PHP 對于遇到錯誤的函數往往會相當一致地返回 FALSE。這未必是正確的,但它卻是一致的。帶下劃線和不帶下劃線的函數名通常都會匹配其基礎庫。
為了簡單起見, PHP 語言犧牲了一致性,但是即使沒有這個規范,它仍然努力在有意義的地方保持一致。
PHP 的完整性符合所需
設計一定要盡可能多地涵蓋重要的情況。
無論何時,在針對 PHP 需求最大的設計任務:編寫 Web 應用程序時,PHP 都是完備的。PHP 從未被設計成一種可以適用于編程世界所有問題的語言。
盡管如此,它的簡單性還是使它可以用于 Web 以外的場合。PHP 最初的目的就是為 Web 編程提供最基本的功能,這一趨勢一直持續至今。
修改核心語言通常是由開發人員的需求驅動。整個社區提出修改意見,然后經由社區投票,決定新特性被拒絕、改變或者接受。該語言的許多創新都源于快速完成工作的需要。
即便我們吸收了其它語言的功能,也是因為它使我們的開發變得簡單,而很少是因為其他語言做得“更正確”。
今天,你可以用 PHP 開發 Web 應用程序。五年后,你仍然可以用 PHP 開發 Web 應用程序,只不過會增加一些新特性。
但是,語言本身的完整性已經符合今天所需。如果未來有需要,我們可以隨時修改語言或為它添加新功能。
更糟就是更好嗎?
Gabriel 承認,“更糟就是更好”的哲學指的是設計看起來很糟糕,也許不應該作為更好的選擇。唯一的問題是,當他審視這兩種哲學時,與麻省理工學院 /“正確的方式”的設計哲學相比,“更糟就是更好”最終仍然是更靈活的選擇,“具有更好的生存特性”。如果我們看一下 PHP,就可以證實“更糟就是更好”這一觀點。
這些年來,Gabriel 承認他在哪種方式更好之間搖擺不定。PHP 社區一直在爭論我們是應該正確地做事還是繼續簡單地做事。
我們有像 Laminas 這樣的框架,以經典的計算機科學方式構建庫,然后我們有像 Laravel 這樣的框架,關注開發者的體驗和速度。PHP 本身二者兼具。
下次再聽到有人罵 PHP 的時候,就隨他噴去吧。這門語言確實很糟糕。但從許多方面來看,PHP 的長壽和廣泛使用證明了這樣一個事實:用“正確的方式”做事并不總是比用“最糟糕”的方式做事好。
當有人吐槽你正在使用的框架時,你要明白從長遠來看這并不重要。選擇一種你認為適合自己的設計哲學,并欣然接受這一點:更糟的可能實際上是更好。
原文鏈接:https://www.toutiao.com/a7034410973704421919/