一、参考文章
1、#trim截取乱码 #字符串16进制转换 #mb移除字符的实现
2、#你真的了解strtotime么
二、trim的坑
1、trim的困惑
## 例1
var_dump(trim('adsssas、', '、')); ## 打印 adsssas
## 例2
var_dump(trim('哈哈哈哈哈、', '、')); ## 打印 哈哈哈哈哈
## 例3
var_dump(trim('小米科技、', '、')); ## 打印 小米科� 乱码了
2、trim移除字符的规则
var_dump(trim('abacabb', 'ab'));
## 猜猜打印啥? acaabb ?
## 其实打印 c [捂脸]
知识点:trim移除字符规则:trim会循环去掉字符串首位存在的字符、直到没有没有可移除的字符
a. 上述例子执行过程是:
循环a存在字符串ab中,去掉,剩下bacabb
循环b存在字符串ab中,去掉,剩下acabb
循环a存在字符串ab中,去掉,剩下cabb
循环c不存在字符串ab中,停止循环,所以去掉首字符就剩下:cabb。
由于trim是过滤首尾字符,所以还会从末尾循环去掉。
最后打印 c
b. 移除中文乱码的问题:
trim是不支持宽字节的、所以在进行去移除字符的时候
、
的十六进制码为0xe3 0x80 0x81 trim会当成三个字符
哈、
的十六进制是0xe5 0x93 0x88 0xe3 0x80 0x81
技、
的十六进制是0xe6 0x8a 0x80 0xe3 0x80 0x81
所以 小米科技、
的技的 0x80 部分也会被trim移除掉 所以会乱码
3、解决方法
//trim宽字节实现
//$encoding 是必传参数
function mb_trim($string, $trim, $encoding = 'utf-8') {
$mask = array();
$trimLength = mb_strlen($trim, $encoding);
for ($i = 0; $i < $trimLength; $i++) {
$item = mb_substr($trim, $i, 1, $encoding);
$mask[] = $item;
}
$len = mb_strlen($string, $encoding);
if ($len > 0) {
$i = $len - 1;
do {
$item = mb_substr($string, $i, 1, $encoding);
if (in_array($item, $mask)) {
$len--;
} else {
break;
}
} while ($i-- != 0);
}
return mb_substr($string, 0, $len, $encoding);
}
三、strtotime 的坑
1、strtotime的困惑
## 例1
var_dump(date('Y-m-d',strtotime('-1 month',strtotime('2019-03-10')))); ## 打印 2019-02-10
## 例2
var_dump(date('Y-m-d',strtotime('-1 month',strtotime('2019-03-29'))));
## 猜猜打印啥 2019-02-29 ? 2019-02-28 ?
## 其实打印 2019-03-01 [捂脸]
2、date的规则
虽然这个问题看起来很迷惑, 但从内部逻辑上来说呢, 其实是 "对" 的
date内部的对于这种事情的处理逻辑:
先做-1 month, 那么当前是07-31, 减去一以后就是06-31.
再做日期规范化, 因为6月没有31号, 所以就好像2点60等于3点一样, 6月31就等于了7月1
是不是逻辑很”清晰”呢? 我们也可以手动验证第二个步骤, 比如:
var_dump(date("Y-m-d", strtotime("2017-06-31"))); ## 打印2017-07-01
## 验证其他月份
var_dump(date("Y-m-d", strtotime("-1 month", strtotime("2017-03-31"))));##打印2017-03-03
var_dump(date("Y-m-d", strtotime("+1 month", strtotime("2017-08-31"))));##打印2017-10-01
var_dump(date("Y-m-d", strtotime("next month", strtotime("2017-01-31"))));##打印2017-03-03
var_dump(date("Y-m-d", strtotime("last month", strtotime("2017-03-31"))));##打印2017-03-03
3、解决方法
## 解决方法1:
$tmp_date = date("Ym");##得到系统的年月
$tmp_year = substr($tmp_date, 0, 4);##切割出年份
$tmp_mon = substr($tmp_date, 4, 2);##切割出月份
$time = mktime(0, 0, 0, $tmp_mon - $sign, 1, $tmp_year);##得到当前月份的前几月
## 解决方法2: PHP5.3之后新增
date("Y-m-d", strtotime("first day of +1 month", strtotime("2017-08-31"))); ##2017-09-01
date("Y-m-d", strtotime("last day of -1 month", strtotime("2017-03-31"))); ## 2017-02-28
date("Y-m-d", strtotime("first day of next month", strtotime("2017-01-31"))); ## 2017-02-01
三、switch 的坑
1、switch的困惑
function switchTest1($key) {
switch ($key) {
case 'per':
echo 'per';
break;
case 'pro':
echo 'pro';
break;
default:
echo 'exit';
}
}
function switchTest2($key) {
switch ($key) {
case 'per':
echo 'per';
case 'pro':
echo 'pro';
default:
echo 'exit';
}
}
switchTest1('per'); ## 打印 per
switchTest1(0);
## 猜猜打印啥? exit ?
## 其实打印 per [捂脸]
switchTest2('per'); ## 打印 perproexit
2、结论
a、switch 的 type 为0时代码的时候始终走第一个case switch 因此使用switch时一定要注意
b、原来 switch 语句不遇到 break 将不会自己"拐弯"
四、explode 的坑
1、示例
$arr = explode('|','');
if (!empty($arr)) {
echo 'true';
}
## 打印 true
## var_dump($arr) 是一个空字符数组
2、结论
explode 分割空字符串时返回的结果并不是空数组 而是包含一个空字符元素的数组
五、empty 的坑
1、示例
## type 是通过魔术方法取得的值
if(empty($param->type)) {
echo 'true';
}
## 不管type的值是多少 该判断语句始终打印 true
2、结论
empty中的参数是对象属性时,如果对象属性的值是通过魔术方法获取,则empty始终返回true
六、strpos 的坑
1、示例
if (strpos('abcd','a') != false) {
echo 'true';
} else {
echo 'false';
}
## 我们想的是 如果 'a' 在 'abcd' 中返回 true 但是上边代码打印 false
##由于 strpos('abcd','a') 返回 a 首次出现的位置 0 == false
2、结论
strpos查找字符串首次出现的位置,字符串位置是从0开始不是从1开始,没有找到字符串返回false
strpos('abc','a') !== false 注意是两个等号
七、array_merge 和 + 的坑
1、示例
## 例1
$a = array('0' => 'a', '1' => 'b', '2' => 'c');
$b = array('0' => 'd', '1' => 'e', '2' => 'f');
var_dump(array_merge($a, $b)); ## 打印 数组 a、b、c、d、e、f
var_dump($a + $b); ## 打印 数组 a、b、c
## 例2
$a = array('0a' => 'a', '1a' => 'b', '2a' => 'c');
$b = array('0a' => 'd', '1a' => 'e', '2a' => 'f');
var_dump(array_merge($a, $b)); ## 打印 数组 d、e、f
var_dump($a + $b); ## 打印 数组 a、b、c
2、结论
a.当下标为数值时,array_merge()不会覆盖掉原来的值,但array+array合并数组则会把最先出现的值作为最终结果返回,而把后面的数组拥有相同键名的那些值“抛弃”掉(不是覆盖)
b.当下标为字符时,array+array仍然把最先出现的值作为最终结果返回,而把后面的数组拥有相同键名的那些值“抛弃”掉,但array_merge()此时会覆盖掉前面相同键名的值
注意:array_merge_recursive() 不会进行键名覆盖,而是将多个相同键名的值递归组成一个数组
八、iconv的坑
1、示例
## utf-8编码转成gb2312 如果遇到一些特别字符时,如:"—",英文名中的"."等等字符,转换就断掉
iconv('utf-8','gb2312',$file);
2、解决方法
## 第二个参数,加上//IGNORE,忽略错误
iconv("UTF-8","GB2312//IGNORE",$file);