说 PHP 入门门槛低, 其中一个原因是我们不需要关心变量的类型, PHP 为我们做了自动的转化但事实上是这样吗? 下面就是一个隐蔽的 bug
字符串 == 比较类型强转隐患
- http://php.net/manual/zh/language.operators.comparison.php
- // php 5
- var_dump(md5('240610708') == md5('QNKCDZO'));//bool(true)
- var_dump(md5('aabg7XSs') == md5('aabC9RqS'));//bool(true)
- var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));//bool(true)
- var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));//bool(true)
- var_dump('0010e2' == '1e3');//10×10^2 = 1×10^3 bool(true)
- var_dump('0x1234Ab' == '1193131');//bool(true)
- var_dump('0xABCdef' == '0xABCdef');//bool(true)
- var_dump('0e1' == '0e2'); //bool(true)
- // php 7 含十六进制字符串不再被认为是数字 http://php.net/manual/zh/migration70.incompatible.php
- var_dump('0x1234Ab' == '1193131');//bool(false)
- var_dump('0xABCdef' == '0xABCdef');//bool(false)
- var_dump("0x123" == "291");//bool(false)
- var_dump(is_numeric("0x123"));//bool(false)>>> md5('240610708')
- => "0e462097431906509019562988736854">>> md5('QNKCDZO')
- => "0e830400451993494058024219903391"
- // php 是弱语言, 会自动判断数据类型, 0eXXXXXXXXXX 转成 0 了
- // 来自文档: 如果比较一个数字和字符串或者比较涉及到数字内容的字符串, 则字符串会被转换为数值并且比较按照数值来进行此规则也适用于 switch 语句当用 === 或 !== 进行比较时则不进行类型转换, 因为此时类型和数值都要比对>>> md5('QNKCDZO')==0
- => true>>> md5('240610708')==0
- => true
- // 使用 === 判断 官方都建议直接用 password_hash 加密
- var_dump(md5('240610708') === md5('QNKCDZO'));//bool(false)
ps: php 7 优化和不兼容
PDO bindParam 要求第二个参数是一个引用变量
- http://www.laruence.com/2012/10/16/2831.html
- $dbh = new PDO('mysql:host=localhost;dbname=test', "test");
- $query = <<<QUERY
- INSERT INTO `user` (`username`, `password`) VALUES (:username, :password);
- QUERY;
- $statement = $dbh->prepare($query);
- $bind_params = array(':username' => "laruence", ':password' => "weibo");
- foreach( $bind_params as $key => $value ){
- $statement->bindParam($key, $value);
- }
- $statement->execute();
- // 期望执行 sql
- INSERT INTO `user` (`username`, `password`) VALUES ("laruence", "weibo");
- // 实际执行 sql
- INSERT INTO `user` (`username`, `password`) VALUES ("weibo", "weibo");
- // 第一次循环
- $value = $bind_params[":username"];
- $statement->bindParam(":username", &$value); // 此时, :username 是对 $value 变量的引用
- // 第二次循环
- $value = $bind_params[":password"]; //oops! $value 被覆盖成了: password 的值
- $statement->bindParam(":password", &$value);
- // 解决
- foreach( $bind_params as $key => &$value ) { // 注意这里
- $statement->bindParam($key, $value);
- }
- return $statement->execute($params);
PHP 引用
https://glot.io/snippets/estgofa359
参考鸟哥一条微博
- $arr = range(1,3);
- foreach($arr as &$v){
- }
- foreach($arr as $v){
- }
- print_r($arr);//[1,2,2]
- // 解决一
- $arr = range(1,3);
- foreach($arr as &$v){
- }
- unset($v);
- foreach($arr as $v){
- }
- print_r($arr);//[1,2,3]
- // 解决二
- $arr = range(1,3);
- foreach($arr as &$v){
- }
- foreach($arr as $v2){
- }
- print_r($arr);//[1,2,3]
- // 解决三
- $arr = range(1,3);
- foreach($arr as &$v){
- }
- foreach($arr as &$v){
- }
- print_r($arr);//[1,2,3]
- array_merge vs +
- https://glot.io/snippets/estgpi43bc
- //
- $arr1 = array(1 => "one", "2" => "two", 3 => "three");
- $arr2 = array(2 => "new two", 3 => "new three");
- print_r($arr1 + $arr2);
- Array
- (
- [1] => one
- [2] => two
- [3] => three
- )
- print_r(array_merge($arr1, $arr2));
- Array
- (
- [0] => one
- [1] => two
- [2] => three
- [3] => new two
- [4] => new three
- )
浮点数精度问题
http://php.net/manual/zh/language.types.float.php
- var_dump(15702>=(157.02*100));//bool(false)
- var_dump(11111>=(111.11*100));//bool(true)
- var_dump(bcsub(15702,(157.02*100))>= 0);//bool(true)
- if(abs(15702-(157.02*100)) <0.001) {
- echo "相等";
- } else {
- echo "不相等";
- }
- $f = 0.58;
- var_dump(intval($f * 100)); //57 0.58 * 100 = 57.999999999...
- in_array switch
- https://glot.io/snippets/esth249n0y
- $arr = ['a', 'pro' => 'php', 8, true];
- var_dump(in_array(2, $arr)); // bool(true)
- var_dump(in_array('b', $arr)); // bool(true)
- var_dump(in_array(0, $arr)); // tbool(true)
- var_dump(in_array(null, $arr)); // bool(false)
- var_dump(in_array(2, $arr, true)); // bool(false)
- var_dump(in_array(0, $arr, true)); // bool(false)
- $name = 0;
- switch ($name) {
- case "a":
- //...
- break;
- case "b":
- //...
- break;
- }
- switch (strval($name)) {
- case "a":
- //...
- break;
- case "b":
- //...
- break;
- }
- strpos
- https://glot.io/snippets/esthlvjtki
- function getReferer($link)
- {
- $refMap = [
- 'baidu' => '百度',
- 'sougou' => '搜狗',
- '360' => '360',
- 'google' => '谷歌'
- ];
- foreach ($refMap as $key => $value) {
- if (strpos($link, $key) !== false) {
- return $value;
- }
- }
- return '其他';
- }
- // https://secure.php.net/manual/zh/function.strpos.php 如果 needle 不是一个字符串, 那么它将被转换为整型并被视为字符的顺序值
- echo getReferer('https://www.google.com/search?workd=google');//360
- // 解决
- function getReferer($link)
- {
- $refMap = [
- 'baidu' => '百度',
- 'sougou' => '搜狗',
- '360' => '360',
- 'google' => '谷歌'
- ];
- foreach ($refMap as $key => $value) {
- if (mb_strpos($link, $key) !== false) {
- //if (strpos($link, strval($key)) !== false) {
- return $value;
- }
- }
- return '其他';
- }
curl 文件上传
- http://php.net/manual/zh/curlfile.construct.php
- //PHP 的 cURL 支持通过给 CURL_POSTFIELDS 传递关联数组 (而不是字符串) 来生成 multipart/form-data 的 POST 请求
- if (class_exists('\CURLFile')) {
- $field = array('fieldname' => new \CURLFile(realpath($filepath)));
- } else {
- $field = array('fieldname' => '@' . realpath($filepath));
- }
foreach 顺序
- $arr=[];
- $arr[2] = 2;
- $arr[1] = 1;
- $arr[0] = 0;
- foreach ($arr as $key => $val) {
- echo $val;// 2 1 0
- }
- while (list($key, $v) = each($arr)) {
- // 获取不到 foreach 会自动 reset,each 之前, 先 reset 数组的内部指针
- }
- for($i=0,$l=count($arr); $i<$l; $i++) {
- echo $arr[$i];// 0 1 2
- }
- json_decode>>> json_decode('php')
- => null>>> json_decode('0x123')
- => 291
- strtotime('-x month')
- date_default_timezone_set('Asia/Shanghai');
- $t = strtotime('2017-08-31');
- echo date('Ym', strtotime('- 1 month', $t)); //201707
- echo date('Ym', strtotime('- 2 month', $t)); //201707
- //
- $first_day_of_month = date('Y-m', strtotime('2017-08-31')).'-01 00:00:01';
- $t = strtotime($first_day_of_month);
- echo date('Ym', strtotime('- 1 month', $t)); //201707
- echo date('Ym', strtotime('- 2 month', $t)); //201706
- echo date("Ym", strtotime("-2 month", strtotime("first day of 2017-08-31"))); //201706
来源: https://mp.weixin.qq.com/s/Xj1MGNftPQnpQGXIOCCwSw