PHP 编程 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($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 是字符串, 只使用第一个字符, 后面的其它字符会忽略.
来源: http://developer.51cto.com/art/201808/580192.htm