每當我看到開發人員從 Java 或 C# 等編譯語言切換到 PHP 這樣的解釋語言時解放了生產力後感到很高興。除了這些常規的執行模型(發起、處理請求和結束請求)和更短的反饋環(無需等待編譯器)外,還有一個能解決開發人員平常問題的開源框架生態系統,所以,PHP 是目前來講 web 開發中最流行的語言。php
但它有一個缺點。html
編譯型語言須要在程序運行以前瞭解每一個變量的類型,每一個方法的返回類型。這就是爲何編譯器須要確保程序是沒有錯誤的,而且會在源碼中向你指出這些類型的錯誤,好比調用了未定義的方法或者是向某個函數傳遞了錯誤數量的參數。在把應用程序部署到生產環境前,編譯器算是第一道防線。laravel
然而 PHP 就不會這樣了。若是程序出錯,會執行到錯誤的代碼的時候崩潰。在測試 PHP 應用時,不論是自動化測試仍是手動測試,開發人員都會花費大量時間去查一些其它編譯型語言不會犯的錯從而減小測試實際業務邏輯的時間。git
我想改變這一點。github
現階段 PHP 實踐所產生的代碼庫中,咱們能夠肯定大部分數據的類型,而且轉換爲靜態類型的語言,儘管還保留着一些動態語言的特性。人們把如今的 PHP 代碼庫變得跟其餘語言同樣更加有趣。面向對象,依賴注入以及設計模式的使用已經變得很是廣泛。web
這讓我想到了 PHP 的 靜態分析工具,它將替代其餘語言的編譯器角色。我花了不少時間研究它,而且已經使用它的各類開發版原本檢查咱們的代碼庫超過一年。設計模式
這個清單的內容隨着每次發佈都在遞增。但成就 PHPStan 也不會只仰賴此一技之微。服務器
它設法一次性檢查整個代碼庫。 它無需屢次遍歷代碼。 只需瀏覽您想要分析的代碼,例如 你寫的代碼。它無需解析和分析第三方依賴項。 相反,它使用反射來找出有關你代碼庫中引用的他人代碼的有用信息。composer
PHPStan 能在一分鐘裏檢查咱們的代碼庫 (6000 個文件, 600k LOCs) 。它可在一秒內完成自查。框架
即使當前正在使用靜態類型,開發者也能夠合法的使用 PHP 的動態語法特性,例如 **get, **set 和 __call 這些魔術方法。它們能夠在運行時去定義新屬性和方法。一般,靜態分析都會爆出屬性和方法未定義,可是有一種機制能夠告訴引擎如何建立新的屬性和方法。
它得益於對容許用戶擴展的原生 PHP 反射的自定義抽象。更多細節可查看 README 中類反射擴展章節。
某些方法返回的類型取決於它的參數。它能夠取決於你傳遞給它的類名,也可能返回與傳遞的對象相同的類的對象。這就是 動態返回類型擴展 的用途。
壓軸語: 若是你想本身出一個 PHPStan 的新的檢查項, 你能夠自力更生。能夠提出基於特定框架的規則,例如檢查 DQL查詢中引用的實體和字段是否存在,或者你選擇的 MVC 框架中生成的連接是否和現存的控制器有關。
我使用過其餘工具,並將之集成進現有的代碼庫中,這種體驗真是往事不堪回首。他們爆出成千上萬的錯誤讓你無法使用。
取而代之,我回顧如何集成 PHPStan 到剛進入開發階段的代碼庫中。 首個版本的功能不是很強大,這時並未發現多少錯誤。但從集成的角度來看,它仍是很是不錯的 --- 有空時,我就爲它增長新規則,我修復了它在版本庫中找到的錯誤,並將新代碼合併到主分支。咱們會使用新版本幾周用來發現其找到的錯誤,並不斷重複這件事。這種逐級增長的規範性的作法在實踐中看來大有裨益,因此我使用 PHPStan 的現有功能來模擬它。
默認狀況下,PHPStan 只檢查它肯定的代碼---常量,實例化,調用$ this的方法,靜態調用的方法,函數和各類語言結構中的現有類。 經過增長級別(從默認值0到當前值4),您還能夠增長它對代碼所作的假設數量以及它檢查的規則數量。
若是內建級別沒法知足你的要求,你一樣也能夠自定義規則。
可能這個建議你聞所未聞。即使是很是細碎的代碼,開發者也不得不編寫單元測試,由於這方面犯錯的概率都是均等的,例如簡單的拼寫錯誤或者忘記將結果賦值給變量。爲那些常常出如今控制器或者門臉中的轉發代碼編寫單元測試是很不划算的事。
單元測試也有其成本。它們一樣也是代碼,難逃編寫和維護的窠臼。最理想的作法就是在持續集成服務器上,每次更改時都運行 PHPStan,從而在無需單元測試的狀況下防止此類錯誤的產生。實現100%的代碼覆蓋率真的很難,而且很是昂貴,但你能夠靜態分析100%的代碼。
至於單元測試的重點應當集中在靜態分析代碼難以察覺的,容易出錯的地方。包括:複雜的數據過濾,循環,條件判斷,乘除法包含舍入的計算等。
若是不是 Nikita Popov 建立了 PHP Parser。就不會有 PHPStan 的出現。
PHP 在 2016 年開始普遍使用 包管理, 單元測試 和 編碼標準 的工具。然而到如今也沒有一個普遍使用的工具,能夠在不運行代碼的狀況下檢查代碼中的錯誤。因此我建立了一個易於使用,快速,可擴展的版本,既不會對您的代碼有嚴格的要求,你還會從這些檢查中受益。查看 GitHub 倉庫 ,瞭解如何將其集成到您的項目中!