php常见的坑

十、filesize缓存的问题
php

PHP的filesize竟然会缓存(固然还有很多,这里仅用filesize举例,其它会缓存的函数,以官方文档为准)
线上代码常常随机出各类问题,排查了1个月,线上加各类日志,最终发现是filesize缓存的问题,以下代码:mysql

[php]  view plain  copy
 
 在CODE上查看代码片派生到个人代码片
  1. echo filesize("a.txt");  
  2. exec("rm a.txt");  // 删除文件  
  3. echo filesize("a.txt"); // 这里会输出大小,而不是报错说文件不存在  
  4.   
  5. echo filesize("b.txt");  
  6. echo filesize("a.txt"); // 这里会报错文件不存在,由于只缓存最后一个文件,缓存里只有b,没有a的缓存了  

看到了吧,filesize不只有缓存,并且还只缓存最后一个文件,因此说PHP的开发人员也不知道怎么考虑的,就不会加个filesize_withcache方法?
知道了缘由,解决也就简单了,在filesize调用前清除缓存,加代码: clearstatcache()
参考官方文档:http://php.net/manual/zh/function.filesize.php

linux

 

九、保存源码文件时,注意要使用utf-8无bom签名sql

以前用Windows的记事本编辑文件,发布到Linux上线后,一直报错:Cannot modify header information - headers already sent by (output started at xxx.php:1)
用Winmerge或BeyondCompare对比代码也没法发现问题,后来用Netbeans才发现文件最前面多了一个不可见字符,研究后才知道是Windows的Bom签名
也就是说,在Windows上开发,在Linux上发布,注意要使用不支持Bom的编辑器,若是用VisualStudio要选择高级保存选项里的不带签名centos

 

一、null和空、0、false等四个值的比较数组

在PHP中,== 会先进行类型转换,再进行对比,而===会先比较类型,若是类型不一样直接返回不相等,参考以下示例缓存

[php]  view plain  copy
 
 在CODE上查看代码片派生到个人代码片
  1. $a = null; $b = ''; $c = 0; $d = false;  
  2. echo ($a == $b)?1:0;    // 输出1  
  3. echo ($a === $b)?1:0;   // 输出0  
  4. echo ($a == $c)?1:0;    // 输出1  
  5. echo ($a === $c)?1:0;   // 输出0  
  6. echo ($b == $c)?1:0;    // 输出1  
  7. echo ($b === $c)?1:0;   // 输出0  
  8. echo ($a == $d)?1:0;    // 输出1  
  9. echo ($a === $d)?1:0;   // 输出0  

对于我这种之前只写js或C#代码的码农,被这几个值忽悠过n次,n大于3app

 

 

 

二、strrchr函数编辑器

W3School站点上的注释以下:函数

strrchr() 函数查找字符串在另外一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的全部字符。
若是成失败,不然返回 false。

实际上,这个函数是查找某个字符,而不是查找字符串,应该参考官方文档

代码示例:

[php]  view plain  copy
 
 在CODE上查看代码片派生到个人代码片
  1. $a = 'abcdef.txt';  
  2. $b = '.php';  
  3. echo strrchr($a, $b);  

上面的代码输出是:.txt

也就是说,若是$b是字符串,只使用第一个字符,后面的其它字符会忽略

注:php提供了strstr函数,为何不提供strrstr函数呢,虽然本身实现也很简单

 

 

三、foreach里的引用赋值参见官方文档

这个引用赋值很好哇,对用C#的我,在C#里要修改foreach的元素,是不可能的,是会出异常滴,php把这个变成了可能,可是:
在官方文档里有一句警告:Warning 数组最后一个元素的 $value 引用在 foreach 循环以后仍会保留。建议使用 unset() 来将其销毁。
咱们看一组代码:

[php]  view plain  copy
 
 在CODE上查看代码片派生到个人代码片
  1. $a = [1,2,3];  
  2. foreach($a as &$item){  
  3.     echo $item . ',';  
  4. }  
  5. //unset($item); // 引用赋值后不销毁对象  
  6. foreach($a as $item){  
  7.     echo $item . ',';  
  8. }  

上面的代码的输出以下:
1,2,3,1,2,2  看最后一个输出的是2,而不是3,就是由于代码里没有销毁$item形成的,缘由以下:
第一个循环,把3的引用赋给了$item,第二个循环,把1赋给了$item,由于$item是引用,致使数组的元素3变成了1,明白了吗?

 

四、isset与empty的联系和区别isset文档 empty文档
empty对以下8种状况返回true:
  null、 空串""、字符串0"0"、空array、布尔值false、数字0、浮点数0.0、类里用var定义可是未赋值

isset 检测变量是否设置,而且不是 NULL,可是对于empty的8种状况,只有null返回false,其它7种状况都返回true

综上所述,除了empty描述的的非null的7种状况,在其它状况下, if(empty(变量)) 等效于 if(!isset(变量))

灵活用法一则:直接访问 $arr['aaa'] 可能报错,说aaa不存在,能够用:
if(isset($arr['aaa']){ 操做代码} 或 if(!empty($arr['aaa']){ 操做代码}

 

五、trim函数遇到中文空格时,会乱码

[php]  view plain  copy
 
 在CODE上查看代码片派生到个人代码片
  1. $str = '  《先后有全半角空格》  ';  
  2. var_dump($str);  
  3. $str2 = trim($str, '  ');  
  4. var_dump($str2);  
  5. $str3 = mb_ereg_replace('^(?:\s| )+|(?:\s| )+$', '', $str);  
  6. var_dump($str3);  
  7. $str4 = mb_ereg_replace('^[\s ]+|[\s ]+$', '', $str);  
  8. var_dump($str4);  

参考如上的代码,输出结果:

[plain]  view plain  copy
 
 在CODE上查看代码片派生到个人代码片
  1. string '  《先后有全半角空格》  ' (length=38)  
  2. string '�先后有全半角空格》' (length=28)  
  3. string '《先后有全半角空格》' (length=30)  
  4.   
  5. A PHP Error was encountered  
  6. Severity: Warning  
  7. Message: mb_ereg_replace(): mbregex compile err: invalid code point value  

能够看出:trim致使乱码出现了,正则^(?:\s| )+|(?:\s| )+$ 能够正常工做,而正则^[\s ]+|[\s ]+$却编译异常,缘由我还没搜索到


六、intval在Windows和Centos上,最大值范围不一样
在centos上,intval转换的最大值是9223372036854775807,

而在个人Win7x64+64位的php上,转换最大值倒是2147483647,很是奇怪,手册明明说64位系统都是9223372036854775807,
这么大一坑啊,官方解释php6如下在win上仅是测试版,不支持64位

 

七、MySQL字段类型为varchar时,不能用where xx=123来检索,会没法利用索引
建议全部SQL的值都用单引号括起来,如:where xx='123',若是字段类型为int,也能正确利用索引

 

八、执行SQL后不判断返回值,或判断逻辑错误:

 

$sql = 'insert into app_log(id)  select 0 from dual where 1=2';
$this->db->query($sql);
return true; // 不加判断,直接返回true

$sql = 'insert into app_log(id)  select 0 from dual where 1=2';
$result = $this->db->query($sql);
if ($result) { // 有bug,插入不成功,result也是true
    return true;
}
return false;

上面的2段代码应该改为:

$sql = 'insert into app_log(id)  select 0 from dual where 1=2';
$this->db->query($sql);
// 若是sql有语法问题,affected_rows是-1
if ($this->db->affected_rows() > 0) {
    return true;
}
return false;

注意:mysql中,update a set name='123' where id=1;
若是id为1的记录,name已是123,那么这条update语句的affected_rows()=0

 

 

 

原文连接:http://blog.csdn.net/youbl/article/details/41014367

相关文章
相关标签/搜索