1. 程式人生 > >PHP之那些年我們踩過的坑

PHP之那些年我們踩過的坑

PHP之那些年我們踩過的坑

1、由於使用單引號,以“ ”為分割符,使用PHP函式explode分割字串,不能正常分割。

原因:這個涉及到單引號與雙引號的區別,在單引號中反斜槓不能被解析。因此,使用explode分割時,如果使用單引號, 會被當作字串,而不是換行符,所以此時,不能正常分割。

類似問題還有字串中包含{}的情況。在字串中,要想使使用了{}包含的變數成功解析,該字串必須使用雙引號。

2、由於BOM頭,使用PHP函式json_decode解析json字串,不能解析成功。

原因:UTF-8 編碼的檔案可以分為無 BOM 和 BOM 兩種格式。何謂BOM? “EF BB BF” 這三個位元組就叫BOM,BOM的全稱叫做"Byte Order Mard"。在utf-8檔案中常用BOM來表明這個檔案是UTF-8檔案,而BOM的本意實在utf16中用來表示高低位元組序列的。在位元組流之前有 BOM表示採用低位元組序列(低位元組在前面),而utf8不用考慮位元組序列,所以其實有無BOM都可以。UTF-8以位元組為編碼單元,沒有位元組序的問題。 UTF-16以兩個位元組為編碼單元,在解釋一個UTF-16文字前,首先要弄清楚每個編碼單元的位元組序。例如收到一個“奎”的Unicode編碼是 594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16位元組流“594E”,那麼這是 “奎”還是“乙”?

如果檔案保 存時,選擇了使用 BOM,會使頁面顯示不正常。一般來說,php是不支援有BOM的,php檔案應該儲存為UTF-8無BOM型別,所以在儲存 UTF8 編碼PHP檔案時,不要使用 BOM。

3、由於正反斜槓的原因,PHP函式basename使用無效

我們經常使用PHP函式basename,來從一個包含有指向一個檔案的全路徑的字串中獲取基本的檔名,但是由於正反斜槓的原因,有時你會發現basename函式無法生效,特別是在window系統和linux系統中切換時。原來,basename函式受作業系統影響,用在 Windows 中,斜線(/)和反斜線()都可以用作目錄分隔符,而在其它環境下只能是斜線(/)。因此,如果你在window系統下使用的反斜線(),那到其他系統時是有問題的。

為避免此影響,最好都使用斜線(/)來作為目錄分割符,對於使用了名稱空間的情況,最好先使用str_replace函式將反斜線()替換成斜線(/)。

4、trim系列函式的過多去除

trim函式的基本用法是去除最外邊的空格、換行符之類的。因為其可選引數,很多人也會將其用於去除UTF8BOM頭、副檔名等等,比如 ltrim(KaTeX parse error: Expected 'EOF', got '\xEF' at position 7: str, "\̲x̲E̲F̲\xBB\xBF"); rtr…str, “.txt”); 。但是很快,就會發現這些函式會多去除了一些東西,比如本來是想去除字尾的,結果 logtext.txt 會變成了 logte 而不是 logtext。為什麼呢?因為後面這個引數的意思不是一個完整字串,而是字元列表,也就是說會一直檢查最左/最右是否符合此列表的其中一個。

5、htmlspecialchars 函式預設不轉義單引號

不少網站都是使用此函式作為通用的輸入過濾函式,但是此函式預設情況是不過濾單引號的。這是非常非常地容易造成XSS漏洞。這樣的做法和不過濾雙引號沒太大區別,只要前端寫得稍微有點不規範(用了單引號)就會中招。因此,我們用的時候一定要給這個函式加上引數 htmlspecialchars( $data, ENT_QUOTES)

6、foreach的保留現象

使用 foreach($someArr as $someL){ } 之類的用法時,要注意最後的一個 s o m e L / 使 f o r e a c h ( someL 會一直保留到該函式/方法結束。而當使用引用的時候 foreach( someArr as &$someL){ }這是以引用來儲存,也就是說後面若有使用同一個名字的變數名,將會把原資料改變(就像一個亂用的C指標)。為安全起見,建議每個foreach(尤其是引用的)結束之後都使用unset把這些變數清除掉。

7、小數(符點數)不能直接比較是否相等

比如 if( 0.5+0.2==0.7 ) 的結果是 false。究其原因是因為,PHP是基於C語言的,而C語言由於其二進位制符點數的表示方式,導致不能精確表示大多數符點數。實際上,幾乎所有的程式語言都沒能精確表示小數(符點數),這是一個普遍存在的現象,因為這個是 IEEE 754 的缺陷。想要解決此問題,只能另立標準,似乎只有Mathematica解決了此問題。

8、字串是否相同建議用 === 而非 ==

為什麼呢?因為這個比較是弱型別。兩個比較時,PHP會先嚐試判別左右兩者是否為數字。而問題就在於什麼樣的字串是數字,是單純的數字串嗎?遠遠不只於此,還包括 0x 開頭的十六進位制,XXeX型別的科學記數法 等等,如 ‘12e0’ == ‘0x0C’ 得到的是true。而在數值型別與字串比較時,甚至一些數字開頭的非數值串,比如 12==‘12這個串’ 得到的值也會是 true。

所以這些情況下,可能會使本來並不相同的字串被判定為相等。而使用===比較則為包含型別的比較,不會有任何轉換,所以是可以準確比較字串是否相同的。

另外吐槽一下JAVA,==居然比較不了字串是否相等,因為字串是一個物件,==變成了判斷是否為同一個物件……

9、不能把switch中的case當作if來使用

在PHP函式switch……case中,switch 匹配的是case語句的值,而不能把case當if用。同時,switch表示式優先匹配與其值型別一致的case語句,型別不一致的放在後面處理,如下:

10、strrchr函式是查詢某個字元,而不是查詢字串

在PHP手冊上strrchr() 函式的解釋是查詢字串在另一個字串中最後一次出現的位置,並返回從該位置到字串結尾的所有字元。如果成失敗,否則返回 false。實際上,這個函式是查詢某個字元,而不是查詢字串。如下示例,很多人一開始肯定以為返回false,但實際上並不是。

上面示例說明,如果$b是字串,只使用第一個字元,後面的其它字元會忽略。