PHP 8.1 已棄用將 null
作為參數(shù)傳遞給許多核心函數(shù)。我的主要問題是htmlspecialchars(php)
和trim(php)
等函數(shù),其中null
不再默默轉(zhuǎn)換為空字符串。
為了在不使用大量程式碼的情況下解決此問題,我嘗試重命名原始內(nèi)建函數(shù),並將它們替換為將輸入從 null
轉(zhuǎn)換為(空)字串的包裝器。
這種方法的主要問題是,函數(shù) rename_function(PECL apd)
不再起作用,上次更新是在 2004 年1。
我需要對(duì)內(nèi)建函數(shù)進(jìn)行某種重寫,以避免每次呼叫函數(shù)時(shí)都編寫空檢查,從而使我的所有程式碼變大兩倍。
我能想到的唯一其他解決方案是僅使用我的自訂函數(shù),但這仍然需要遍歷我擁有的所有程式碼和第三方程式庫。
在 PHP 8.1 中,當(dāng)將 null 傳遞給內(nèi)建函數(shù)時(shí),它不再默默地轉(zhuǎn)換為空字串。
我想(作為補(bǔ)充,現(xiàn)有的答案得到了我的支持)就如何看待和解決此類「問題」描繪了一幅不同的圖畫。它並沒有減少所概述的方法的正確性或錯(cuò)誤性,而只是一種希望互惠互利的附加觀點(diǎn)。每個(gè)項(xiàng)目都是不同的。
給定前提:
那麼這對(duì)我來說(首先)看起來是一個(gè)報(bào)告問題。透過不報(bào)告 E_DEPRECATED
。
這樣做的好處是(不僅是您的程式碼),現(xiàn)在知道您的程式碼帶有棄用通知。報(bào)告確實(shí)有效。
另一方面,壓制棄用通知可能會(huì)讓它們消失。如果您丟失了程式碼庫帶有棄用通知的訊息,從技術(shù)上講,從資訊遺失中恢復(fù)可能仍然很容易(再次報(bào)告棄用通知),但是如果更改的時(shí)間延長了,現(xiàn)在可能會(huì)出現(xiàn)壓倒性的雜訊(E_TOO_MUCH_NOISE)。
那麼程式碼不沉默其實(shí)是一件壞事嗎?或者說可以轉(zhuǎn)化為利益嗎?我寧願(yuàn)選擇後者。不管怎樣,我們已經(jīng)在處理這些資訊了。
因此,在這種情況中,我的想法是一般不抑制棄用通知,而是「靜默」函數(shù)呼叫。這很容易,但無論從好的方面還是從壞的方面來說,這都是愚蠢的:
trim($mixed); #1 -> @trim($mixed); #2
這當(dāng)然是一個(gè)可以使用標(biāo)準(zhǔn)文字工具應(yīng)用於程式碼庫的操作。它還會(huì)向您顯示過去已經(jīng)使用過 @
抑制運(yùn)算子的位置:
@trim($mixed); #3 -> @@trim($mixed); #4
如果您是PHP 開發(fā)人員,在編輯器中查看此類程式碼(對(duì)於情況#2-#4),他們會(huì)立即向您尖叫,並且對(duì)於所有四種情況至少都會(huì)吸引您的注意($mixed
)。
感謝您沒有保持沉默,我們讓這些地方尖叫,只是不是在運(yùn)行時(shí)1。
與第一種透過不報(bào)告 E_DEPRECATED
來保持沉默的方法不同,這種方法很容易丟失訊息,而訊息是透過使用所有 @
符號(hào)來保存的。
它對(duì)解決噪音問題有幫助嗎?如果我們停止在這裡工作,那就完全不行了?,F(xiàn)在我們會(huì)在程式碼上塗上@
-符號(hào),決定不採取進(jìn)一步的操作,這樣我們就可以使用第一個(gè)解決方案(不報(bào)告棄用訊息)來完成它,而無需觸及程式碼。 p>
那麼它的好處是什麼?好吧,儘管程式碼現(xiàn)在靜默運(yùn)行,PHP 仍然提供診斷訊息。也就是說,現(xiàn)在可以將 PHP 錯(cuò)誤處理程序註冊(cè)為偵聽器(執(zhí)行程式碼時(shí))。
僅在程式碼級(jí)別,很容易檢查這些位置,因?yàn)?@
符號(hào)(通常)也很容易在程式碼中發(fā)現(xiàn)。
第二部分很很重要,因?yàn)閮嵐芏鄠€(gè)地方可能會(huì)受到棄用的影響,但一定不能有一個(gè)解決方案來解決所有問題(我更喜歡遠(yuǎn)離“一刀切” '解決方案』」(如果可能的話),但特別是在問題上下文中PHP 8.1 發(fā)生了變化,我可以想像根據(jù)使用地點(diǎn)會(huì)有不同的需求。
例如,在模板程式碼(輸出)中,具體類型不是一個(gè)問題,因此轉(zhuǎn)換為字串很可能是首選解決方案:
@trim($mixed); -> trim((string)$mixed) @@trim($mixed); -> @trim((string)$mixed)
模板(輸出)保持穩(wěn)定。
但對(duì)於實(shí)際的輸入處理,棄用通知可能會(huì)發(fā)現(xiàn)值得修復(fù)的實(shí)際潛在缺陷,例如缺少預(yù)設(shè)值(使事情變得過於複雜)、值的處理不明確(空與空、字串、布林與數(shù)字)與PHP 中的陣列與物件)或一般的$mixed
混淆。
這樣的 trim($mixed)
可能是被遺忘多年的安全防護(hù),從未進(jìn)行過升級(jí)(有更好的安全防護(hù)可用)。對(duì)於這樣的程式碼,我很確定我已經(jīng)想要並要求$mixed
實(shí)際上是$string
before 我使用trim ()
。原因很簡單,至少直接想到兩件事:
trim()
- 它可以被刪除(我最喜歡的修復(fù)之一:刪除程式碼?。?- 或 -李>
使用 $mixed 進(jìn)行修補(bǔ)是完全有效的? ''
如果原始使用是字串或null
僅。
@trim($mixed); -> trim($mixed ?? '') @@trim($mixed); -> @trim($mixed ?? '')
但除此之外,例如像 42 這樣的數(shù)字,將拋出 TypeError
,而不是棄用訊息。這可以區(qū)分正在運(yùn)行的程式碼和未運(yùn)行的程式碼。
因此,這裡還有更多需要維護(hù)的地方,例如檢查位置,如果可能的話進(jìn)一步聚類,然後應(yīng)用更多專用修復(fù)程序。它可能會(huì)揭示缺少的測(cè)試或斷言,需要一些時(shí)間來穩(wěn)定整個(gè)應(yīng)用程式流程等。
在這種情況下,要完成程式碼的遷移,進(jìn)行集群,處理空合併運(yùn)算符,並為真正的修復(fù)做適當(dāng)?shù)奈臅ぷ?。一旦完成了使用空合併運(yùn)算符的非明顯錯(cuò)誤抑制並刪除了 @
抑制運(yùn)算符,如果修復(fù)計(jì)劃未捕獲這些信息,您可能會(huì)丟失這些信息。
當(dāng)我在這些地方看起來受過更多教育時(shí),當(dāng)我發(fā)現(xiàn)自己撓頭或揉眼睛時(shí),我並不感到驚訝。然後我提醒自己,這些錯(cuò)誤不是因?yàn)?PHP 8.1 版本造成的,版本更改只是讓它們(再次)出現(xiàn),有時(shí)我什至?xí)ㄟ^維護(hù) PHP 版本來獲得完整的錯(cuò)誤集群作為副漁獲物。
備忘單
#(string)$mixed
- 之前的行為$mixed ?? ''
- 僅在 null
上抑制 TypeError
錯(cuò)誤@
- 完全錯(cuò)誤抑制。您應(yīng)該在適用的地方記錄您的程式碼庫。 @@
- 如果發(fā)生這種情況,這可能是一個(gè)值得研究的有趣地方。 空($mixed)? '' : xxx($mixed)
- 把垃圾帶出去,典型的空癱/混合混亂,尋找集群,有機(jī)會(huì)大大簡化程式碼庫。遷移到標(biāo)量類型(PHP 7),從最內(nèi)向外引入嚴(yán)格的類型處理,在適用的情況下使用 PHP「經(jīng)典」和「嚴(yán)格」類型處理。 PHP 7.0 斷言和 PHP 8.1 棄用訊息可以很好地支援這裡。 錯(cuò)誤處理程序
#錯(cuò)誤處理沒有什麼魔力,它是PHP.net 上記錄的標(biāo)準(zhǔn)(與Example #1),它作為錯(cuò)誤事件的觀察者,可以區(qū)分受抑制的錯(cuò)誤和非受抑制的錯(cuò)誤透過error_reporting(php)
/ error_reporting(php-ini)
至少達(dá)到通常需要的級(jí)別,如果需要區(qū)分(在生產(chǎn)環(huán)境中,E_DEPRECATED
通常不是報(bào)告的一部分)。此示例性處理程序會(huì)拋出所有報(bào)告的錯(cuò)誤,對(duì)於棄用事件以及E_ALL
也會(huì)拋出此類錯(cuò)誤,因此需要@
抑制運(yùn)算符不拋出:
set_error_handler(static function ($type, $message, $file, $line) use (&$deprecations) { if (!(error_reporting() & $type)) { // This error code is not included in error_reporting, so let it fall // through to the standard PHP error handler // capture E_DEPRECATED if ($type === E_DEPRECATED) { $deprecations[] = ['deprecations' => count($deprecations ?: [])] + get_defined_vars(); } return false; } // throwing error handler, stand-in for own error reporter // which may also be `return false;` throw new ErrorException($message, $type, error_reporting(), $file, $line); });
類似的錯(cuò)誤處理程序可以在 3v4l.org 上的擴(kuò)充範(fàn)例中找到,包括要報(bào)告的已棄用程式碼上。
E_USER_DEPRECATED
#從技術(shù)上講,錯(cuò)誤抑制運(yùn)算子可以與 E_USER_DEPRECATED
結(jié)合使用,與上面 E_DEPRECATED
概述的相同。
但是,對(duì)它的控制較少且它可能已被專案依賴項(xiàng)中已有的第三方程式碼使用。類似下面的程式碼並不罕見:
@trigger_error('this. a message.', E_USER_DEPRECATED);
它的作用完全相同:發(fā)出棄用事件,但將它們從 PHP 報(bào)告中排除。訂閱這些內(nèi)容可能會(huì)讓您陷入噪音之中。使用 E_DEPRECATED
,您總是可以直接從 PHP 獲得「好的、原創(chuàng)的」。
@
錯(cuò)誤抑制運(yùn)算符的方法並對(duì)其進(jìn)行評(píng)論時(shí),IMSoP 立即舉起紅/黑旗(正確?。苋菀讓雰号c洗澡水一起倒掉@
抑制運(yùn)算子。在我的回答中,它的目的只是抑制棄用通知但是使用的結(jié)果是它抑制所有診斷訊息和錯(cuò)誤,在某些PHP 版本中甚至是致命的訊息和錯(cuò)誤,因此PHP 退出255,無需任何進(jìn)一步的診斷- 不僅要小心,還要處理。這個(gè)運(yùn)營商很強(qiáng)大。追蹤它在程式碼庫中的使用情況並不斷檢查它是否符合您的基線/期望。對(duì)於合法情況,請(qǐng)考慮使用消音器。為了移植/維護(hù)程式碼,首先使用它來標(biāo)記。完成批量編輯後,再次將其刪除。 首先,要記住兩件事:
htmlspecialchars($something)
可以替換為 htmlspecialchars($something ?? '')
接下來,一些選項(xiàng):
?? ''
或修復(fù)一個(gè)邏輯錯(cuò)誤,無論如何你都不希望出現(xiàn) null。 nullable_htmlspecialchars
等自訂函數(shù),並在程式碼中直接尋找和取代。 nullableoverride\htmlspecialchars
;然後在新增 use function nullableoverride\htmlspecialchars;
的任何檔案中,將使用該函數(shù)而不是內(nèi)建函數(shù)。不過,這必須添加到每個(gè)文件中,因此您可能需要一個(gè)工具來自動(dòng)添加它。 ?? ''
到適當(dāng)?shù)暮瘮?shù)調(diào)用,因此您不必手動(dòng)編輯它們。不幸的是,似乎還沒有這方面的內(nèi)建規(guī)則,因此您必須學(xué)會(huì)編寫自己的規(guī)則。 ?? ''
到簡單的情況。