摘要:為那些經(jīng)常出現(xiàn)在控制器或者門臉中的轉(zhuǎn)發(fā)代碼編寫(xiě)單元測(cè)試是很不劃算的事。單元測(cè)試也有其成本。最理想的做法就是在持續(xù)集成服務(wù)器上,每次更改時(shí)都運(yùn)行,從而在無(wú)需單元測(cè)試的情況下防止此類錯(cuò)誤的產(chǎn)生。在年開(kāi)始廣泛使用包管理,單元測(cè)試和編碼標(biāo)準(zhǔn)的工具。
PHPStan:無(wú)需寫(xiě)測(cè)試就能找到代碼中的 Bug
每當(dāng)我看到開(kāi)發(fā)人員從 Java 或 C# 等編譯語(yǔ)言切換到 PHP 這樣的解釋語(yǔ)言時(shí)解放了生產(chǎn)力后感到很高興。除了這些常規(guī)的執(zhí)行模型(發(fā)起、處理請(qǐng)求和結(jié)束請(qǐng)求)和更短的反饋環(huán)(無(wú)需等待編譯器)外,還有一個(gè)能解決開(kāi)發(fā)人員日常問(wèn)題的開(kāi)源框架生態(tài)系統(tǒng),因此,PHP 是目前來(lái)說(shuō)?web 開(kāi)發(fā)中最流行的語(yǔ)言。
但它有一個(gè)缺點(diǎn)。
你會(huì)在什么時(shí)候發(fā)現(xiàn)錯(cuò)誤?編譯型語(yǔ)言需要在程序運(yùn)行之前了解每個(gè)變量的類型,每個(gè)方法的返回類型。這就是為什么編譯器需要確保程序是沒(méi)有錯(cuò)誤的,并且會(huì)在源碼中向你指出這些類型的錯(cuò)誤,比如調(diào)用了未定義的方法或者是向某個(gè)函數(shù)傳遞了錯(cuò)誤數(shù)量的參數(shù)。在把應(yīng)用程序部署到生產(chǎn)環(huán)境前,編譯器算是第一道防線。
然而 PHP 就不會(huì)這樣了。如果程序出錯(cuò),會(huì)執(zhí)行到錯(cuò)誤的代碼的時(shí)候崩潰。在測(cè)試 PHP 應(yīng)用時(shí),不管是自動(dòng)化測(cè)試還是手動(dòng)測(cè)試,開(kāi)發(fā)人員都會(huì)花費(fèi)大量時(shí)間去查一些其它編譯型語(yǔ)言不會(huì)犯的錯(cuò)從而減少測(cè)試實(shí)際業(yè)務(wù)邏輯的時(shí)間。
我想改變這一點(diǎn)。
歡迎來(lái)到 PHPStan 的世界現(xiàn)階段 PHP 實(shí)踐所產(chǎn)生的代碼庫(kù)中,我們可以確定大部分?jǐn)?shù)據(jù)的類型,并且轉(zhuǎn)換為靜態(tài)類型的語(yǔ)言,盡管還保留著一些動(dòng)態(tài)語(yǔ)言的特性。人們把現(xiàn)在的 PHP 代碼庫(kù)變得跟其他語(yǔ)言一樣更加有趣。面向?qū)ο?,依賴注入以及設(shè)計(jì)模式的使用已經(jīng)變得非常普遍。
這讓我想到了 PHP 的?靜態(tài)分析工具,它將替代其他語(yǔ)言的編譯器角色。我花了很多時(shí)間研究它,并且已經(jīng)使用它的各種開(kāi)發(fā)版本來(lái)檢查我們的代碼庫(kù)超過(guò)一年。
它就是?PHPStan, 開(kāi)源且免費(fèi) 它目前校驗(yàn)什么?有關(guān)類中涉及的,對(duì)象實(shí)例, 錯(cuò)誤/異常捕獲,類型約束以及其他語(yǔ)言結(jié)構(gòu)的存在性。 PHP 照舊不會(huì)檢查這些, 但是會(huì)展現(xiàn)其中未被使用的代碼。
被調(diào)用的方法和函數(shù)的存在性和可訪問(wèn)性。同樣也會(huì)檢查他們的參數(shù)個(gè)數(shù)。
方法是否返回了它聲明的返回值類型。
被訪問(wèn)成員變量的存在性和可見(jiàn)性。它也可指出是否將一個(gè)其他的類型的值賦給了既定類型的成員變量。
sprintf/printf 函數(shù)基于格式化字符串所應(yīng)接收的參數(shù)個(gè)數(shù)。
分支和循環(huán)范圍中的變量的存在性。
無(wú)用的形式指定。例如 (string) "foo" ,以及不同類型變量間的嚴(yán)格比較 (=== 和?!==),因?yàn)樗麄兊慕Y(jié)果總為 false。
這個(gè)清單的內(nèi)容隨著每次發(fā)布都在遞增。但成就 PHPStan 也不會(huì)只仰賴此一技之微。
PHPStan 迅疾如飛...它設(shè)法一次性檢查整個(gè)代碼庫(kù)。 它無(wú)需多次遍歷代碼。 只需瀏覽您想要分析的代碼,例如 你寫(xiě)的代碼。它無(wú)需解析和分析第三方依賴項(xiàng)。 相反,它使用反射來(lái)找出有關(guān)你代碼庫(kù)中引用的他人代碼的有用信息。
PHPStan 能在一分鐘里檢查我們的代碼庫(kù) (6000 個(gè)文件, 600k LOCs) 。它可在一秒內(nèi)完成自查。
...可擴(kuò)展性即便當(dāng)前正在使用靜態(tài)類型,開(kāi)發(fā)者也可以合法的使用 PHP 的動(dòng)態(tài)語(yǔ)法特性,例如?get,?set 和 __call 這些魔術(shù)方法。它們可以在運(yùn)行時(shí)去定義新屬性和方法。通常,靜態(tài)分析都會(huì)爆出屬性和方法未定義,但是有一種機(jī)制可以告訴引擎如何創(chuàng)建新的屬性和方法。
它得益于對(duì)允許用戶擴(kuò)展的原生 PHP 反射的自定義抽象。更多細(xì)節(jié)可查看?README 中類反射擴(kuò)展章節(jié)。
某些方法返回的類型取決于它的參數(shù)。它可以取決于你傳遞給它的類名,也可能返回與傳遞的對(duì)象相同的類的對(duì)象。這就是?動(dòng)態(tài)返回類型擴(kuò)展?的用途。
壓軸語(yǔ): 如果你想自己出一個(gè) PHPStan 的新的檢查項(xiàng),?你可以自力更生??梢蕴岢龌谔囟蚣艿囊?guī)則,例如檢查?DQL查詢中引用的實(shí)體和字段是否存在,或者你選擇的 MVC 框架中生成的鏈接是否和現(xiàn)存的控制器有關(guān)。
選擇規(guī)范級(jí)別我使用過(guò)其他工具,并將之集成進(jìn)現(xiàn)有的代碼庫(kù)中,這種體驗(yàn)真是往事不堪回首。他們爆出成千上萬(wàn)的錯(cuò)誤讓你沒(méi)法使用。
取而代之,我回顧如何集成 PHPStan 到剛進(jìn)入開(kāi)發(fā)階段的代碼庫(kù)中。 首個(gè)版本的功能不是很強(qiáng)大,這時(shí)并未發(fā)現(xiàn)多少錯(cuò)誤。但從集成的角度來(lái)看,它還是非常不錯(cuò)的?---?有空時(shí),我就為它增加新規(guī)則,我修復(fù)了它在版本庫(kù)中找到的錯(cuò)誤,并將新代碼合并到主分支。我們會(huì)使用新版本幾周用來(lái)發(fā)現(xiàn)其找到的錯(cuò)誤,并不斷重復(fù)這件事。這種逐級(jí)增加的規(guī)范性的做法在實(shí)踐中看來(lái)大有裨益,所以我使用 PHPStan 的現(xiàn)有功能來(lái)模擬它。
默認(rèn)情況下,PHPStan 只檢查它確定的代碼---常量,實(shí)例化,調(diào)用$ this的方法,靜態(tài)調(diào)用的方法,函數(shù)和各種語(yǔ)言結(jié)構(gòu)中的現(xiàn)有類。 通過(guò)增加級(jí)別(從默認(rèn)值0到當(dāng)前值4),您還可以增加它對(duì)代碼所做的假設(shè)數(shù)量以及它檢查的規(guī)則數(shù)量。
如果內(nèi)建級(jí)別無(wú)法滿足你的要求,你同樣也可以自定義規(guī)則。
少寫(xiě)單元測(cè)試! (披沙揀金)可能這個(gè)建議你聞所未聞。即便是非常細(xì)碎的代碼,開(kāi)發(fā)者也不得不編寫(xiě)單元測(cè)試,因?yàn)檫@方面犯錯(cuò)的幾率都是均等的,例如簡(jiǎn)單的拼寫(xiě)錯(cuò)誤或者忘記將結(jié)果賦值給變量。為那些經(jīng)常出現(xiàn)在控制器或者門臉中的轉(zhuǎn)發(fā)代碼編寫(xiě)單元測(cè)試是很不劃算的事。
單元測(cè)試也有其成本。它們同樣也是代碼,難逃編寫(xiě)和維護(hù)的窠臼。最理想的做法就是在持續(xù)集成服務(wù)器上,每次更改時(shí)都運(yùn)行 PHPStan,從而在無(wú)需單元測(cè)試的情況下防止此類錯(cuò)誤的產(chǎn)生。實(shí)現(xiàn)100%的代碼覆蓋率真的很難,并且非常昂貴,但你可以靜態(tài)分析100%的代碼。
至于單元測(cè)試的重點(diǎn)應(yīng)當(dāng)集中在靜態(tài)分析代碼難以察覺(jué)的,容易出錯(cuò)的地方。包括:復(fù)雜的數(shù)據(jù)過(guò)濾,循環(huán),條件判斷,乘除法包含舍入的計(jì)算等。
站在巨人的肩膀上如果不是?Nikita Popov?創(chuàng)建了?PHP Parser。就不會(huì)有 PHPStan 的出現(xiàn)。
PHP 在 2016 年開(kāi)始廣泛使用?包管理,?單元測(cè)試?和?編碼標(biāo)準(zhǔn)?的工具。然而到現(xiàn)在也沒(méi)有一個(gè)廣泛使用的工具,可以在不運(yùn)行代碼的情況下檢查代碼中的錯(cuò)誤。所以我創(chuàng)建了一個(gè)易于使用,快速,可擴(kuò)展的版本,既不會(huì)對(duì)您的代碼有嚴(yán)格的要求,你還會(huì)從這些檢查中受益。查看?GitHub 倉(cāng)庫(kù)?,了解如何將其集成到您的項(xiàng)目中!
更多文章:https://laravel-china.org/c/t...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/29635.html
摘要:最近發(fā)現(xiàn)自己寫(xiě)的代碼運(yùn)行結(jié)果總跟自己預(yù)想的不一樣,排查時(shí)發(fā)現(xiàn)大多是語(yǔ)法錯(cuò)誤,在運(yùn)行之前錯(cuò)誤已經(jīng)種下。最后代碼的語(yǔ)法錯(cuò)誤,應(yīng)該在編寫(xiě)的時(shí)候及時(shí)發(fā)現(xiàn),盡量減少正式運(yùn)行時(shí)錯(cuò)誤。 最近發(fā)現(xiàn)自己寫(xiě)的PHP代碼運(yùn)行結(jié)果總跟自己預(yù)想的不一樣,排查時(shí)發(fā)現(xiàn)大多是語(yǔ)法錯(cuò)誤,在運(yùn)行之前錯(cuò)誤已經(jīng)種下??赡苁亲约捍中拇笠?,或者說(shuō)php -l檢測(cè)太簡(jiǎn)單,不過(guò)的確是有一些語(yǔ)法錯(cuò)誤埋藏得太深(畢竟PHP是動(dòng)態(tài)語(yǔ)言),...
摘要:默認(rèn)的配置不會(huì)檢測(cè)任何代碼。參數(shù)列表質(zhì)量檢測(cè)包其他有人問(wèn),你為什么要這么折磨自己呢其實(shí)像類型代碼質(zhì)量工具,不是僅僅自己拿來(lái)玩的,在開(kāi)發(fā)人員略多的技術(shù)團(tuán)隊(duì),可以通過(guò)使用它來(lái)達(dá)到代碼規(guī)范一致,如果每個(gè)人代碼都不一樣,后果不堪設(shè)想。 showImg(https://segmentfault.com/img/bVbtfeF?w=1796&h=724); 前言 我一生的文章都會(huì)放在這里,我的博客...
摘要:是一個(gè)免費(fèi)和開(kāi)源的應(yīng)用,能夠集成至任何項(xiàng)目中,并收集和展示分析數(shù)據(jù)。它有沒(méi)有任何依賴,支持請(qǐng)求,包括常用開(kāi)發(fā)庫(kù)的通用數(shù)據(jù)采集器和收集器。 DebugBar 是一個(gè)免費(fèi)和開(kāi)源的應(yīng)用,能夠集成至任何PHP項(xiàng)目中,并收集和展示分析數(shù)據(jù)。它有沒(méi)有任何依賴,支持Ajax請(qǐng)求,包括常用開(kāi)發(fā)庫(kù)的通用數(shù)據(jù)采集器和收集器。 相信用過(guò)Laravel的調(diào)試工具的同學(xué),都感到這個(gè)工具非常強(qiáng)大好用,極大地提高了...
摘要:比如上面的例子文件文件我們利用做了語(yǔ)法解析檢測(cè),代碼如下報(bào)錯(cuò)哪里類重復(fù)了不存在查看該屬性是否存在于父類中原理能就是對(duì)解析出來(lái)的繼續(xù)做分析,但是前人栽樹(shù)后人乘涼,這樣的完整工具已經(jīng)有大神幫我們做好了。 原文:我的個(gè)人博客 https://mengkang.net/1356.html 工作了兩三年,技術(shù)停滯不前,迷茫沒(méi)有方向,不如看下我的直播 PHP 進(jìn)階之路 (金三銀四跳槽必考,一般人...
摘要:注意本文是我們的性能分析系列的第三篇,點(diǎn)此閱讀性能分析第一篇介紹,或性能分析第二篇深入研究。小的性能提升很可能來(lái)自優(yōu)化,而非緩存。注意此更改已提交到并已獲更新。目前,兩者具備相同的特性,只有一些部分重命名了。 注意:本文是我們的 PHP 性能分析系列的第三篇,點(diǎn)此閱讀?PHP 性能分析第一篇: XHProf & XHGui 介紹?,或??PHP 性能分析第二篇: 深入研究 XHGui...
閱讀 1613·2021-11-22 09:34
閱讀 1696·2019-08-29 16:36
閱讀 2677·2019-08-29 15:43
閱讀 3120·2019-08-29 13:57
閱讀 1306·2019-08-28 18:05
閱讀 1885·2019-08-26 18:26
閱讀 3254·2019-08-26 10:39
閱讀 3467·2019-08-23 18:40