在日常开发中,我们经常碰到这样的问题,即有些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($str, "\xEF\xBB\xBF"); rtrim($str, ".txt"); 。但是很快,就会发现这些函数会多去除了一些东西,比如本来是想去除后缀的,结果 logtext.txt 会变成了 logte 而不是 logtext。为什么呢?因为后面这个参数的意思不是一个完整字符串,而是字符列表,也就是说会一直检查最左/最右是否符合此列表的其中一个。
5、htmlspecialchars 函数默认不转义单引号
不少网站都是使用此函数作为通用的输入过滤函数,但是此函数默认情况是不过滤单引号的。这是非常非常地容易造成XSS漏洞。这样的做法和不过滤双引号没太大区别,只要前端写得稍微有点不规范(用了单引号)就会中招。因此,我们用的时候一定要给这个函数加上参数 htmlspecialchars( $data, ENT_QUOTES)
6、foreach的保留现象
使用 foreach($someArr as $someL){ } 之类的用法时,要注意***的一个 $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是字符串,只使用***个字符,后面的其它字符会忽略。