首页 > 代码库 > 分享php工作中遇到的一些探究和技巧【1】

分享php工作中遇到的一些探究和技巧【1】

一 foreach的引用

$arr = range(1,3); //[1,2,3] 

foreach($arr as &$val) { 

} 
foreach($arr as $val) { 

} 
print_r($arr);

上面的代码会输出什么?

Array (
    [0] => 1 
    [1] => 2 
    [2] => 2 
)

这是因为foreach的源代码中,对变量进行了引用。导致其作用之后,将地址赋值于最后一个

例:

tmp是var的引用,指向的是var的存储空间,当tmp改变的时候,var也改变
$var = 123;
$tmp = &$var;
$tmp = 200;
echo $var;
//20

示意图:

技术分享

技术分享

解决方法:

//方法1
 foreach ($arr as &$value) {
 } 
 unset($value); 
 foreach ($arr as $value) {
 } 
 print_r($arr); //[1,2,3] 
//方法2 
foreach ($arr as &$value) {
} 
foreach ($arr as $val) {
} 
 print_r($arr); 
 //[1,2,3] 
//方法3 
foreach ($arr as &$value) {
}  
foreach ($arr as &$value) { 
} 
print_r($arr); 
//[1,2,3]

二 擅于用array_walk 和 foreach, for

<?php
/**
 * array_walk 和 foreach, for 的效率的比较。
 * 我们要测试的是foreach, for, 和 array_walk的效率的问题。 
 */

//产生一个10000的一个数组。
$max = 10000;
$test_arr = range(0, $max);
$temp;
//我们分别用三种方法测试求这些数加上1的值的时间。

// for 的方法
$t1 = microtime(true);
for ($i = 0; $i < $max; $i++) {
    $temp = $temp + 1;
}
$t2 = microtime(true);
$t = $t2 - $t1;
echo "就使用for, 没有对数组操作 花费: {$t}\n";

$t1 = microtime(true);
for ($i = 0; $i < $max; $i++) {
    $test_arr[$i] = $test_arr[$i] + 1;
}
$t2 = microtime(true);
$t = $t2 - $t1;
echo "使用for 并且直接对数组进行了操作 花费: {$t}\n";

$t1 = microtime(true);
for ($i = 0; $i < $max; $i++) {
    addOne($test_arr[$i]);
}
$t2 = microtime(true);
$t = $t2 - $t1;
echo "使用for 调用函数对数组操作 花费 : {$t}\n";

$t1 = microtime(true);
foreach ($test_arr as $k => &$v) {
    $temp = $temp + 1;
}
$t2 = microtime(true);
$t = $t2 - $t1;
echo "使用 foreach 没有对数组操作 花费 : {$t}\n";

$t1 = microtime(true);
foreach ($test_arr as $k => &$v) {
    $v = $v + 1;
}
$t2 = microtime(true);
$t = $t2 - $t1;
echo "使用 foreach 直接对数组操作 : {$t}\n";

$t1 = microtime(true);
foreach ($test_arr as $k => &$v) {
    addOne($v);
}
$t2 = microtime(true);
$t = $t2 - $t1;
echo "使用 foreach 调用函数对数组操作 : {$t}\n";

$t1 = microtime(true);
array_walk($test_arr, addOne);
$t2 = microtime(true);
$t = $t2 - $t1;
echo "使用 array_walk 花费 : {$t}\n";

function addOne(&$item) {
    $item = $item + 1;
}

执行的结果:
就使用for, 没有对数组操作 花费: 0.15388584136963
使用 foreach 没有对数组操作 花费 : 0.076934814453125

使用for 并且直接对数组进行了操作 花费: 0.14769005775452
使用 foreach 直接对数组操作 : 0.076115131378174

使用for 调用函数对数组操作 花费 : 0.32393312454224
使用 foreach 调用函数对数组操作 : 0.25716996192932
使用 array_walk 花费 : 0.17966890335083

 

在对10000个数的操作过程中,这个实验我们可以得出这样的结论:
foreach 的效率要比for 高很多,也许有很大的一个原因是for 要进行很多次条件判断。所以以后能用foreach的地方就用foreach,可以提高1倍的效率。
如果循环内要调用函数,用array_walk  最好,它的效率要比for 高出1倍,要比foreach高出43%的效率。
还有一个提示就是如果你这个程序对效率的要求是很高的,那不要在很深的循环中调用函数,要调用函数也要用array_walk,最好的直接把代码写在循环里面。

同时,我们来看一下这两个函数的区别:

array_walk 主要是要对数组内的每个值进行操作,操作结果影响原来的数组

array_map主要是对数组中的值进行操作后返回数组,以得到一个新数组

wallk 可以没有返回值 map要有,因为要填充数组

 

三 为什么要用联合索引 ?

1 在多条件查询时,联合索引效率要高。在允许的范围内,多条件个条件查询的时候,应该根据业务创建多个联合索引。这样效率比分开创建多个索引要快

2 查询条件中出现联合索引第一列,或者全部,则能利用联合索引.

  换句话说:查询条件中没有出现联合索引的第一列,而出现联合索引的第二列,或者第三列,都不会利用联合索引查询.

  而单一索引:只要条件列中出现索引列,无论在什么位置,都能利用索引查询.

我本地电脑有如下表:

CREATE TABLE `t_log_change_name` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `player_id` int(11) NOT NULL DEFAULT 0,
  `old_name` varchar(255) NOT NULL DEFAULT ‘‘,
  `day` int(11) NOT NULL DEFAULT 20110101,
  PRIMARY KEY (`id`),
  KEY `idx_player_id` (`player_id`,`day`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

 当我使用联合条件查询,

EXPLAIN select * from t_log_change_name where player_id =344 and `day`>=20161012;

结果当然是没问题的,直接选中想要的数据,影响行为3行

技术分享

当我用只使用第一列为条件查询,

EXPLAIN select * from t_log_change_name where player_id =344;

它处于索引的第一列,因此是可以命中索引的

技术分享

当我使用第二列为条件查询,

EXPLAIN select * from t_log_change_name where `day`>=20161012;

那不好意思,它属于索引的第二列,因此无法命中索引,全部行都检索一遍

技术分享

所以务必根据业务需求而去建立合适的索引
,同时注意联合索引的顺序,失效情况。

 

 

 

 

 

分享php工作中遇到的一些探究和技巧【1】