我剛開始升級我的程式碼以相容 php 8.1。我有很多程式碼片段,我將潛在的空值傳遞給內部函數。
if (strlen($row) > 0) { ... }
其中 $row 來自可能具有空值的來源(例如查詢)。這可能會產生棄用警告;在這種情況下:
已棄用:strlen():已棄用將 null 傳遞給字串類型的參數 #1 ($string)
我正在尋找最簡單、最省時的方法來處理升級此程式碼,例如修復可以進行全域搜尋和替換的地方。似乎對我傳遞給內部函數的變數進行類型轉換,無需更改功能。
error_reporting(E_ALL); $row = null; if (strlen((string) $row) > 0) { ... }
除了以這種方式編碼的道德方面之外,這種內部功能方法是否存在問題?有沒有更好的方法(除了完全重寫程式碼並以不同的方式處理空值之外)?我更喜歡這個向後相容 v7.4 的解決方案,儘管我可能會相容於 8.0。
我知道我的使用者定義函數還有其他選擇。
回答有關「處理升級此程式碼的最簡單、最省時的方法」的問題。
簡而言之,你不能。
首先,一些背景...
大約15% 的開發者使用
strict_types=1
,所以您屬於大多數不這樣做的開發者中。您現在可以忽略這個問題(棄用),但是 PHP 9.0 會透過使其成為致命類型錯誤而導致很多問題。
也就是說,您仍然可以使用 NULL 連接字串:
您仍然可以將 NULL 與空字串進行比較:
並且您仍然可以使用 NULL 進行計算(它仍然被視為 0):
你仍然可以列印/回顯 NULL:
您仍然可以將 NULL 傳遞到
sprintf()
中,並使用%s
將其強制為空字串,例如您仍然可以強制其他值(遵循規則),例如
從那時起,NULL 強制就這樣運作了,我假設從一開始,也有記錄:
無論如何,要修復...第一部分,它會嘗試尋找您需要更新的程式碼。
只要可以將 NULL 傳遞給這些函數參數之一,就會發生這種情況。
至少有 335 受此影響的參數。
還有一個額外的104,它們是有點可疑;和558 其中NULL 有問題,你應該在哪裡修復這些問題,例如
define(NULL, '值')
。Psalm 是我能找到的唯一能夠對此提供幫助的工具。
詩篇需要處於非常高的檢查等級(1、2 或 3)。
並且您不能使用基準來忽略問題(開發人員在現有專案中引入靜態分析的技術,因此它只檢查新的/編輯過的程式碼)。
如果您之前沒有使用過靜態分析工具(不用擔心,建議僅使用33% 的開發者這樣做);然後預計會花費大量時間修改程式碼(從第8 級開始,最寬鬆,然後慢慢提高)。
我無法使用PHPStan、Rector、PHP CodeSniffer、PHP CS Fixer 或PHPCompatibility 來查找這些問題(來源)。
找到每個問題後,第二部分就是編輯。
最不可能引起問題的地方是更換水槽,例如
或者,您可以嘗試追溯到變數的來源,並嘗試先封鎖將其設為 NULL。
以下是一些非常常見的 NULL 來源:
其中一些函數需要第二個參數來指定預設值,或者您可以提前使用
strval()
...但要小心,您的程式碼可能會通過($a = == NULL),而且您不想破壞它。許多開發人員不會意識到他們的某些變數可以包含NULL - 例如期望
(他們創建的)始終提交所有輸入欄位;由於網路問題、瀏覽器擴充功能、用戶在瀏覽器中編輯DOM/URL 等,這種情況可能不會發生。
一年中的大部分時間我都在研究這個問題。
我開始寫兩個 RFC 來嘗試解決這個問題。第一個是更新一些函數以接受NULL(這並不理想,因為它讓使用strict_types 的開發人員感到不安); 第二個RFC 是允許NULL 在這種情況下繼續被強制. .....但我沒有不要將其付諸投票,因為我剛剛收到了大量負面反饋,並且我不希望將來引用該拒絕來解釋為什麼此問題無法解決(而最初的更改幾乎沒有被討論,這一個)。
似乎 NULL 的處理方式有所不同,因為它從未被視為「標量值」 - 我認為許多開發人員並不關心這種區別,但它不時會出現。
與我合作過的開發人員中,大多數人都忽略了這個問題(希望稍後能解決它,這可能不是最好的主意);例如
有一個團隊試圖將
strval()
套用到所有事情,例如修剪(strval($search))
。但一年多後他們仍然發現問題(他們表示使用 8.1 alpha 1 進行測試)。我正在考慮的另一個選擇是創建一個庫,在命名空間下將所有這些 ~335 個函數重新定義為可為空;例如
然後開發人員將包含該庫,並自行使用命名空間:
如果您明確嘗試處理
null
的情況,那麼稍微乾淨一點的修復方法是strlen($row ?? '')
使用「null合併運算子」。在大多數情況下,兩者可能是等效的,但在
strict_types=1
生效的情況下,如果值是可以轉換為字串的其他類型,則它們的行為會有所不同:另一方面,請注意
??
運算子是基於isset
,而不是=== null
,因此未定義變數的行為會有所不同:如果您關心這種情況,與舊行為最直接等效的程式碼會更加冗長: