「PHP編程」PHP中的這些坑,你沒(méi)踩過(guò)算你厲害
在日常開(kāi)發(fā)中,我們經(jīng)常碰到這樣的問(wèn)題,即有些PHP問(wèn)題看似簡(jiǎn)單,一說(shuō)就明,但是一到使用時(shí)就踩坑。比如,下面我所列的幾條:
1、由于使用單引號(hào),以“ ”為分割符,使用PHP函數(shù)explode分割字符串,不能正常分割。
原因:這個(gè)涉及到單引號(hào)與雙引號(hào)的區(qū)別,在單引號(hào)中反斜杠不能被解析。因此,使用explode分割時(shí),如果使用單引號(hào), 會(huì)被當(dāng)作字符串,而不是換行符,所以此時(shí),不能正常分割。
類似問(wèn)題還有字符串中包含{}的情況。在字符串中,要想使使用了{(lán)}包含的變量成功解析,該字符串必須使用雙引號(hào)。
2、由于BOM頭,使用PHP函數(shù)json_decode解析json字符串,不能解析成功。
原因:UTF-8 編碼的文件可以分為無(wú) BOM 和 BOM 兩種格式。何謂BOM? "EF BB BF" 這三個(gè)字節(jié)就叫BOM,BOM的全稱叫做"Byte Order Mard"。在utf-8文件中常用BOM來(lái)表明這個(gè)文件是UTF-8文件,而BOM的本意實(shí)在utf16中用來(lái)表示高低字節(jié)序列的。在字節(jié)流之前有 BOM表示采用低字節(jié)序列(低字節(jié)在前面),而utf8不用考慮字節(jié)序列,所以其實(shí)有無(wú)BOM都可以。UTF-8以字節(jié)為編碼單元,沒(méi)有字節(jié)序的問(wèn)題。 UTF-16以兩個(gè)字節(jié)為編碼單元,在解釋一個(gè)UTF-16文本前,首先要弄清楚每個(gè)編碼單元的字節(jié)序。例如收到一個(gè)“奎”的Unicode編碼是 594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節(jié)流“594E”,那么這是 “奎”還是“乙”?
如果文件保 存時(shí),選擇了使用 BOM,會(huì)使頁(yè)面顯示不正常。一般來(lái)說(shuō),php是不支持有BOM的,php文件應(yīng)該保存為UTF-8無(wú)BOM類型,所以在保存 UTF8 編碼PHP文件時(shí),不要使用 BOM。
3、由于正反斜杠的原因,PHP函數(shù)basename使用無(wú)效
我們經(jīng)常使用PHP函數(shù)basename,來(lái)從一個(gè)包含有指向一個(gè)文件的全路徑的字符串中獲取基本的文件名,但是由于正反斜杠的原因,有時(shí)你會(huì)發(fā)現(xiàn)basename函數(shù)無(wú)法生效,特別是在window系統(tǒng)和linux系統(tǒng)中切換時(shí)。原來(lái),basename函數(shù)受操作系統(tǒng)影響,用在 Windows 中,斜線(/)和反斜線()都可以用作目錄分隔符,而在其它環(huán)境下只能是斜線(/)。因此,如果你在window系統(tǒng)下使用的反斜線(),那到其他系統(tǒng)時(shí)是有問(wèn)題的。
為避免此影響,***都使用斜線(/)來(lái)作為目錄分割符,對(duì)于使用了命名空間的情況,***先使用str_replace函數(shù)將反斜線()替換成斜線(/)。
4、trim系列函數(shù)的過(guò)多去除
trim函數(shù)的基本用法是去除最外邊的空格、換行符之類的。因?yàn)槠淇蛇x參數(shù),很多人也會(huì)將其用于去除UTF8BOM頭、文件擴(kuò)展名等等,比如 ltrim($str, "\xEF\xBB\xBF"); rtrim($str, ".txt"); 。但是很快,就會(huì)發(fā)現(xiàn)這些函數(shù)會(huì)多去除了一些東西,比如本來(lái)是想去除后綴的,結(jié)果 logtext.txt 會(huì)變成了 logte 而不是 logtext。為什么呢?因?yàn)楹竺孢@個(gè)參數(shù)的意思不是一個(gè)完整字符串,而是字符列表,也就是說(shuō)會(huì)一直檢查最左/最右是否符合此列表的其中一個(gè)。
5、htmlspecialchars 函數(shù)默認(rèn)不轉(zhuǎn)義單引號(hào)
不少網(wǎng)站都是使用此函數(shù)作為通用的輸入過(guò)濾函數(shù),但是此函數(shù)默認(rèn)情況是不過(guò)濾單引號(hào)的。這是非常非常地容易造成XSS漏洞。這樣的做法和不過(guò)濾雙引號(hào)沒(méi)太大區(qū)別,只要前端寫得稍微有點(diǎn)不規(guī)范(用了單引號(hào))就會(huì)中招。因此,我們用的時(shí)候一定要給這個(gè)函數(shù)加上參數(shù) htmlspecialchars( $data, ENT_QUOTES)
6、foreach的保留現(xiàn)象
使用 foreach($someArr as $someL){ } 之類的用法時(shí),要注意***的一個(gè) $someL 會(huì)一直保留到該函數(shù)/方法結(jié)束。而當(dāng)使用引用的時(shí)候 foreach($someArr as &$someL){ }這是以引用來(lái)保存,也就是說(shuō)后面若有使用同一個(gè)名字的變量名,將會(huì)把原數(shù)據(jù)改變(就像一個(gè)亂用的C指針)。為安全起見(jiàn),建議每個(gè)foreach(尤其是引用的)結(jié)束之后都使用unset把這些變量清除掉。
7、小數(shù)(符點(diǎn)數(shù))不能直接比較是否相等
比如 if( 0.5+0.2==0.7 ) 的結(jié)果是 false。究其原因是因?yàn)椋琍HP是基于C語(yǔ)言的,而C語(yǔ)言由于其二進(jìn)制符點(diǎn)數(shù)的表示方式,導(dǎo)致不能精確表示大多數(shù)符點(diǎn)數(shù)。實(shí)際上,幾乎所有的編程語(yǔ)言都沒(méi)能精確表示小數(shù)(符點(diǎn)數(shù)),這是一個(gè)普遍存在的現(xiàn)象,因?yàn)檫@個(gè)是 IEEE 754 的缺陷。想要解決此問(wèn)題,只能另立標(biāo)準(zhǔn),似乎只有Mathematica解決了此問(wèn)題。
8、字符串是否相同建議用 === 而非 ==
為什么呢?因?yàn)檫@個(gè)比較是弱類型。兩個(gè)比較時(shí),PHP會(huì)先嘗試判別左右兩者是否為數(shù)字。而問(wèn)題就在于什么樣的字符串是數(shù)字,是單純的數(shù)字串嗎?遠(yuǎn)遠(yuǎn)不只于此,還包括 0x 開(kāi)頭的十六進(jìn)制,XXeX類型的科學(xué)記數(shù)法 等等,如 '12e0'=='0x0C' 得到的是true。而在數(shù)值類型與字符串比較時(shí),甚至一些數(shù)字開(kāi)頭的非數(shù)值串,比如 12=='12這個(gè)串' 得到的值也會(huì)是 true。
所以這些情況下,可能會(huì)使本來(lái)并不相同的字符串被判定為相等。而使用===比較則為包含類型的比較,不會(huì)有任何轉(zhuǎn)換,所以是可以準(zhǔn)確比較字符串是否相同的。
另外吐槽一下JAVA,==居然比較不了字符串是否相等,因?yàn)樽址且粋€(gè)對(duì)象,==變成了判斷是否為同一個(gè)對(duì)象……
9、不能把switch中的case當(dāng)作if來(lái)使用
在PHP函數(shù)switch……case中,switch 匹配的是case語(yǔ)句的值,而不能把case當(dāng)if用。同時(shí),switch表達(dá)式優(yōu)先匹配與其值類型一致的case語(yǔ)句,類型不一致的放在后面處理,如下:
10、strrchr函數(shù)是查找某個(gè)字符,而不是查找字符串
在PHP手冊(cè)上strrchr() 函數(shù)的解釋是查找字符串在另一個(gè)字符串中***一次出現(xiàn)的位置,并返回從該位置到字符串結(jié)尾的所有字符。如果成失敗,否則返回 false。實(shí)際上,這個(gè)函數(shù)是查找某個(gè)字符,而不是查找字符串。如下示例,很多人一開(kāi)始肯定以為返回false,但實(shí)際上并不是。
上面示例說(shuō)明,如果$b是字符串,只使用***個(gè)字符,后面的其它字符會(huì)忽略。