下面我们根据小程序来验证一些常见的性能差别。
2.1、使用 echo 还是 print
在有的建议规则中,会建议使用 echo ,而不使用 print。说 print 是函数,而 echo 是语法结构。实际上并不是如此,print 也是语法结构,类似的语法结构,还有多个,比如 list、isset、require 等。不过对于 PHP 7 以下 PHP 版本而言,两者确实有性能上的差别。如下两份代码:
for($i=0; $i<1000000; $i++)
{
echo("Hello,World!");
}
for($i=0; $i<1000000; $i++)
{
print ("Hello,World!");
}
在 PHP 5.3 中运行速度分别如下(各2次):
[root@localhostphpperf]# time php echo1.php > /dev/null
real 0m0.233s
user 0m0.153s
sys 0m0.080s
[root@localhostphpperf]# time php echo1.php > /dev/null
real 0m0.234s
user 0m0.159s
sys 0m0.073s
[root@localhostphpperf]# time phpecho.php> /dev/null
real 0m0.203s
user 0m0.130s
sys 0m0.072s
[root@localhostphpperf]# time phpecho.php> /dev/null
real 0m0.203s
user 0m0.128s
sys 0m0.075s
在 PHP5.3 版中效率差距10%以上。而在 PHP5.4 以上的版本中,区别不大,如下是 PHP7 中的运行效率。
[root@localhostphpperf]# time php7 echo.php> /dev/null
real 0m0.151s
user 0m0.088s
sys 0m0.062s
[root@localhostphpperf]# time php7 echo.php> /dev/null
real 0m0.145s
user 0m0.084s
sys 0m0.061s
[root@localhostphpperf]# time php7 echo1.php > /dev/null
real 0m0.140s
user 0m0.075s
sys 0m0.064s
[root@localhostphpperf]# time php7 echo1.php > /dev/null
real 0m0.146s
user 0m0.077s
sys 0m0.069s
正如浏览器前端的一些优化准则一样,没有啥特别通用的原则,往往根据不同的情况和版本,规则也会存在不同。
2.2、require 还是 require_once?
在一些常规的优化规则中,会提到,建议使用 require_ once 而不是 require,现由是 require_ once 会去检测是否重复,而 require 则不需要重复检测。
在大量不同文件的包含中,require_ once 略慢于 require。但是 require_ once 的检测是一项内存中的行为,也就是说即使有数个需要加载的文件,检测也只是内存中的比较。而 require 的每次重新加载,都会从文件系统中去读取分析。因而 require_ once 会比 require 更佳。咱们也使用一个例子来看一下。
str.php
global$str;
$str= "China has a large population";
require.php
for($i=0; $i<100000; $i++) {
require "str.php";
}
require_once.php
for($i=0; $i<100000; $i++) {
require_once"str.php";
}
上面的例子,在 PHP7 中,require_ once.php 的运行速度是 require.php 的30倍!在其他版本也能得到大致相同的结果。
[root@localhostphpperf]# time php7 require.php
real 0m1.712s
user 0m1.126s
sys 0m0.569s
[root@localhostphpperf]# time php7 require.php
real 0m1.640s
user 0m1.113s
sys 0m0.515s
[root@localhostphpperf]# time php7 require_once.php
real 0m0.066s
user 0m0.063s
sys 0m0.003s
[root@localhostphpperf]# time php7 require_once.php
real 0m0.057s
user 0m0.052s
sys 0m0.004s
从上可以看到,如果存在大量的重复加载的话,require_ once 明显优于 require,因为重复的文件不再有 IO 操作。即使不是大量重复的加载,也建议使用 require_ once,因为在一个程序中,一般不会存在数以千百计的文件包含,100次内存比较的速度差距,一个文件包含就相当了。
2.3、单引号还是双引号?
单引号,还是双引号,是一个问题。一般的建议是能使用单引号的地方,就不要使用双引号,因为字符串中的单引号,不会引起解析,从而效率更高。那来看一下实际的差别。
classUser
{
private $uid;
private $username;
private $age;
function __construct($uid, $username,$age){
$this->uid= $uid;
$this->username = $username;
$this->age = $age;
}
function getUserInfo()
{
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
}
function getUserInfoSingle()
{
return 'UID:'.$this->uid.' UserName:'.$this->username.' Age'.$this->age;
}
function getUserInfoOnce()
{
return "UID:{$this->uid}UserName:{$this->username} Age:{$this->age}";
}
function getUserInfoSingle2()
{
return 'UID:{$this->uid} UserName:{$this->username} Age:{$this->age}';
}
}
for($i=0; $i<1000000;$i++) {
$user = new User($i, "name".$i, $i%100);
$user->getUserInfoSingle();
}
在上面的 User 类中,有四个不同的方法,完成一样的功能,就是拼接信息返回,看看这四个不同的方法的区别。
第一个、getUserInfo ,使用双引号和属性相拼接
[root@localhostphpperf]# time php7 string.php
real 0m0.670s
user 0m0.665s
sys 0m0.002s
[root@localhostphpperf]# time php7 string.php
real 0m0.692s
user 0m0.689s
sys 0m0.002s
[root@localhostphpperf]# time php7 string.php
real 0m0.683s
user 0m0.672s
sys 0m0.004s
第二个、getUserInfoSingle ,使用单引号和属性相拼接
[root@localhostphpperf]# time php7 string.php
real 0m0.686s
user 0m0.683s
sys 0m0.001s
[root@localhostphpperf]# time php7 string.php
real 0m0.671s
user 0m0.666s
sys 0m0.003s
[root@localhostphpperf]# time php7 string.php
real 0m0.669s
user 0m0.666s
sys 0m0.002s
可见在拼接中,单双引号并无明显差别。
第三个、getUserInfoOnce,不再使用句号.连接,而是直接引入在字符串中解析。
[root@localhostphpperf]# time php7 string.php
real 0m0.564s
user 0m0.556s
sys 0m0.006s
[root@localhostphpperf]# time php7 string.php
real 0m0.592s
user 0m0.587s
sys 0m0.004s
[root@localhostphpperf]# time php7 string.php
real 0m0.563s
user 0m0.559s
sys 0m0.003s
从上面可见,速度提高了0.06s-0.10s,有10%-20%的效率提升。可见连缀效率更低一些。
第四个、getUserInfoSingle2 虽然没有达到我们真正想要的效果,功能是不正确的,但是在字符串中,不再需要解析变量和获取变量值,所以效率确实有大幅度提升。
[root@localhostphpperf]# time php7 string.php
real 0m0.379s
user 0m0.375s
sys 0m0.003s
[root@localhostphpperf]# time php7 string.php
real 0m0.399s
user 0m0.394s
sys 0m0.003s
[root@localhostphpperf]# time php7 string.php
real 0m0.377s
user 0m0.371s
sys 0m0.004s
效率确实有了大的提升,快了50%。
那么这个快,是由于不需要变量引用解析带来的,还是只要加入$天然的呢?我们再试着写了一个方法。
functiongetUserInfoSingle3()
{
return "UID:{\$this->uid} UserName:{\$this->username} Age:{\$this->age}";
}
得到如下运行时间:
[root@localhostphpperf]# time php7 string.php
real 0m0.385s
user 0m0.381s
sys 0m0.002s
[root@localhostphpperf]# time php7 string.php
real 0m0.382s
user 0m0.380s
sys 0m0.002s
[root@localhostphpperf]# time php7 string.php
real 0m0.386s
user 0m0.380s
sys 0m0.004s
发现转义后的字符串,效率跟单引号是一致的,从这里也可以看见,单引号还是双引号包含,如果不存在需要解析的变量,几乎没有差别。如果有需要解析的变量,你也不能光用单引号,要么使用单引号和连缀,要么使用内部插值,所以在这条规则上,不用太过纠结。
2.4、错误应该打开还是关闭?
在 PHP 中,有多种错误消息,错误消息的开启是否会带来性能上的影响呢?从直觉觉得,由于错误消息,本身会涉及到 IO 输出,无论是输出到终端或者 error_log,都是如此,所以肯定会影响性能。我们来看看这个影响有多大。
error_reporting(E_ERROR);
for($i=0; $i<1000000;$i++) {
$str= "通常,$PHP中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加。但是在平常的(更小的)脚本中应根本就没有性能影响。
然而,在平常脚本中有循环回收机制运行的情况下,内存的节省将允许更多这种脚本同时运行在你的服务器上。因为总共使用的内存没达到上限。";
}
在上面的代码中,我们涉及到一个不存在的变量,所以会报出 Notice 错误:
Notice: Undefined variable: PHP 中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加。但是在平常的 in xxxx/string2.php on line 10
如果把 E_ ERROR 改成 E_ ALL 就能看到大量的上述错误输出。
我们先执行 E_ ERROR 版,这个时候没有任何错误日志输出。得到如下数据:
[root@localhostphpperf]# time php7 string2.php
real 0m0.442s
user 0m0.434s
sys 0m0.005s
[root@localhostphpperf]# time php7 string2.php
real 0m0.487s
user 0m0.484s
sys 0m0.002s
[root@localhostphpperf]# time php7 string2.php
real 0m0.476s
user 0m0.471s
sys 0m0.003s
再执行 E_ ALL 版,有大量的错误日志输出,我们把输出重定向到/dev/null
[root@localhostphpperf]# time php7 string2.php > /dev/null
real 0m0.928s
user 0m0.873s
sys 0m0.051s
[root@localhostphpperf]# time php7 string2.php > /dev/null
real 0m0.984s
user 0m0.917s
sys 0m0.064s
[root@localhostphpperf]# time php7 string2.php > /dev/null
real 0m0.945s
user 0m0.887s
sys 0m0.056s
可见慢了将近一倍。
如上可见,即使输出没有正式写入文件,错误级别打开的影响也是巨大的。在线上我们应该将错误级别调到 E_ ERROR 这个级别,同时将错误写入 error_ log,既减少了不必要的错误信息输出,又避免泄漏路径等信息,造成安全隐患。
2.5、正则表达式和普通字符串操作
在字符串操作中,有一条常见的规则,即是能使用普通字符串操作方法替代的,就不要使用正则表达式来处理,用 C 语言操作 PCRE 做过正则表达式处理的童鞋应该清楚,需要先 compile,再 exec,也就是说是一个相对复杂的过程。现在就比较一下两者的差别。
对于简单的分隔,我们可以使用 explode 来实现,也可以使用正则表达式,比如下面的例子:
ini_set("precision", 16);
function microtime_ex()
{
list($usec, $sec) = explode(" ", microtime());
return $sec+$usec;
}
for($i=0; $i<1000000; $i++) {
microtime_ex();
}
耗时在0.93-1S之间。
[root@localhostphpperf]# time php7 pregstring.php
real 0m0.941s
user 0m0.931s
sys 0m0.007s
[root@localhostphpperf]# time php7 pregstring.php
real 0m0.986s
user 0m0.980s
sys 0m0.004s
[root@localhostphpperf]# time php7 pregstring.php
real 0m1.004s
user 0m0.998s
sys 0m0.003s
我们再将分隔语句替换成:
list($usec, $sec) = preg_split("#\s#", microtime());
得到如下数据,慢了近10-20%。
[root@localhostphpperf]# time php7 pregstring1.php
real 0m1.195s
user 0m1.182s
sys 0m0.004s
[root@localhostphpperf]# time php7 pregstring1.php
real 0m1.222s
user 0m1.217s
sys 0m0.003s
[root@localhostphpperf]# time php7 pregstring1.php
real 0m1.101s
user 0m1.091s
sys 0m0.005s
再将语句替换成:
list($usec, $sec) = preg_split("#\s+#", microtime());
即匹配一到多个空格,并没有太多的影响。除了分隔外,查找我们也来看一个例子。
第一段代码:
$str= "China has a Large population";
for($i=0; $i<1000000; $i++) {
if(preg_match("#l#i", $str))
{
}
}
第二段代码:
$str= "China has a large population";
for($i=0; $i<1000000; $i++) {
if(stripos($str, "l")!==false)
{
}
}
这两段代码达到的效果相同,都是查找字符串中有无 l 或者 L 字符。
在 PHP 7 下运行效果如下:
[root@localhostphpperf]# time php7 pregstring2.php
real 0m0.172s
user 0m0.167s
sys 0m0.003s
[root@localhostphpperf]# time php7 pregstring2.php
real 0m0.199s
user 0m0.196s
sys 0m0.002s
[root@localhostphpperf]# time php7 pregstring3.php
real 0m0.185s
user 0m0.182s
sys 0m0.003s
[root@localhostphpperf]# time php7 pregstring3.php
real 0m0.184s
user 0m0.181s
sys 0m0.003s
两者区别不大。再看看在 PHP5.6 中的表现。
[root@localhostphpperf]# time php56 pregstring2.php
real 0m0.470s
user 0m0.456s
sys 0m0.004s
[root@localhostphpperf]# time php56 pregstring2.php
real 0m0.506s
user 0m0.500s
sys 0m0.005s
[root@localhostphpperf]# time php56 pregstring3.php
real 0m0.348s
user 0m0.342s
sys 0m0.004s
[root@localhostphpperf]# time php56 pregstring3.php
real 0m0.376s
user 0m0.364s
sys 0m0.003s
可见在 PHP 5.6 中表现还是非常明显的,使用正则表达式慢了20%。PHP7 难道是对已使用过的正则表达式做了缓存?我们调整一下代码如下:
$str= "China has a Large population";
for($i=0; $i<1000000; $i++) {
$pattern = "#".chr(ord('a')+$i%26)."#i";
if($ret = preg_match($pattern, $str)!==false)
{
}
}
这是一个动态编译的 pattern。
$str= "China has a large population";
for($i=0; $i<1000000; $i++) {
$pattern = "".chr(ord('a')+$i%26)."";
if($ret = stripos($str, $pattern)!==false)
{
}
}
在 PHP7 中,得到了如下结果:
[root@localhostphpperf]# time php7 pregstring2.php
real 0m0.351s
user 0m0.346s
sys 0m0.004s
[root@localhostphpperf]# time php7 pregstring2.php
real 0m0.359s
user 0m0.352s
sys 0m0.004s
[root@localhostphpperf]# time php7 pregstring3.php
real 0m0.375s
user 0m0.369s
sys 0m0.003s
[root@localhostphpperf]# time php7 pregstring3.php
real 0m0.370s
user 0m0.365s
sys 0m0.005s
可见两者并不明显。而在 PHP 5.6 中,同样的代码:
[root@localhostphpperf]# time php56 pregstring2.php
real 0m1.022s
user 0m1.015s
sys 0m0.005s
[root@localhostphpperf]# time php56 pregstring2.php
real 0m1.049s
user 0m1.041s
sys 0m0.005s
[root@localhostphpperf]# time php56 pregstring3.php
real 0m0.923s
user 0m0.821s
sys 0m0.002s
[root@localhostphpperf]# time php56 pregstring3.php
real 0m0.838s
user 0m0.831s
sys 0m0.004s
在 PHP 5.6 中,stripos 版明显要快于正则表达式版,由上两例可见,PHP7对正则表达式的优化还是相当惊人的。其次也建议,能用普通字符串操作的地方,可以避免使用正则表达式。因为在其他版本中,这个规则还是适用的。某 zend 大牛官方的分享给出如下数据:
stripos(‘http://’, $website) 速度是preg_match(‘/http:\/\//i’, $website) 的两倍
ctype_alnum()速度是preg_match(‘/^\s*$/’)的5倍;
“if ($test == (int)$test)” 比 preg_match(‘/^\d*$/’)快5倍
可以相见,正则表达式是相对低效的。
2.6、数组元素定位查找
在数组元素的查找中,有一个关键的注意点就是数组值和键的查找速度,差异非常大。了解过 PHP 扩展开发的朋友,应该清楚,数组在底层其实是 Hash 表。所以键是以快速定位的,而值却未必。下面来看例子。
首先们构造一个数组:
$a= array();
for($i=0;$i<100000;$i++){
$a[$i] = $i;
}
在这个数组中,我们测试查找值和查找键的效率差别。
第一种方法用 array_ search,第二种用 array_ key_ exists,第三种用 isset 语法结构。 代码分别如下:
//查找值
foreach($a as $i)
{
array_search($i, $a);
}
//查找键
foreach($a as $i)
{
array_key_exists($i, $a);
}
//判定键是否存在
foreach($a as $i)
{
if(isset($a[$i]));
}
运行结果如下:
[root@localhostphpperf]# time php7 array.php
real 0m9.026s
user 0m8.965s
sys 0m0.007s
[root@localhostphpperf]# time php7 array.php
real 0m9.063s
user 0m8.965s
sys 0m0.005s
[root@localhostphpperf]# time php7 array1.php
real 0m0.018s
user 0m0.016s
sys 0m0.001s
[root@localhostphpperf]# time php7 array1.php
real 0m0.021s
user 0m0.015s
sys 0m0.004s
[root@localhostphpperf]# time php7 array2.php
real 0m0.020s
user 0m0.014s
sys 0m0.006s
[root@localhostphpperf]# time php7 array2.php
real 0m0.016s
user 0m0.009s
sys 0m0.006s
由上例子可见,键值查找的速度比值查找的速度有百倍以上的效率差别。因而如果能用键值定位的地方,尽量用键值定位,而不是值查找。
2.7、对象与数组
在 PHP 中,数组就是字典,字典可以存储属性和属性值,而且无论是键还是值,都不要求数据类型统一,所以对象数据存储,既能用对象数据结构的属性存储数据,也能使用数组的元素存储数据。那么两者有何差别呢?
使用对象:
classUser
{
public $uid;
public $username;
public $age;
function getUserInfo()
{
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
}
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->username="User".$i;
$user->getUserInfo();
}
使用数组:
functiongetUserInfo($user)
{
return "UID:".$user['uid']." UserName:".$user['username']." Age:".$user['age'];
}
for($i=0; $i<1000000;$i++) {
$user = array("uid"=>$i,"age" =>$i%100,"username"=>"User".$i);
getUserInfo($user);
}
我们分别在 PHP5.3、PHP 5.6 和 PHP 7 中运行这两段代码。
[root@localhostphpperf]# time phpobject.php
real 0m2.144s
user 0m2.119s
sys 0m0.009s
[root@localhostphpperf]# time phpobject.php
real 0m2.106s
user 0m2.089s
sys 0m0.013s
[root@localhostphpperf]# time php object1.php
real 0m1.421s
user 0m1.402s
sys 0m0.016s
[root@localhostphpperf]# time php object1.php
real 0m1.431s
user 0m1.410s
sys 0m0.012s
在 PHP 5.3 中,数组版比对象版快了近30%。
[root@localhostphpperf]# time php56 object.php
real 0m1.323s
user 0m1.319s
sys 0m0.002s
[root@localhostphpperf]# time php56 object.php
real 0m1.414s
user 0m1.400s
sys 0m0.006s
[root@localhostphpperf]# time php56 object1.php
real 0m1.356s
user 0m1.352s
sys 0m0.002s
[root@localhostphpperf]# time php56 object1.php
real 0m1.364s
user 0m1.349s
sys 0m0.006s
[root@localhostphpperf]# time php7 object.php
real 0m0.642s
user 0m0.638s
sys 0m0.003s
[root@localhostphpperf]# time php7 object.php
real 0m0.606s
user 0m0.602s
sys 0m0.003s
[root@localhostphpperf]# time php7 object1.php
real 0m0.615s
user 0m0.613s
sys 0m0.000s
[root@localhostphpperf]# time php7 object1.php
real 0m0.615s
user 0m0.611s
sys 0m0.003s
到了 PHP 5.6 和 PHP7 中,两个版本基本没有差别,而在 PHP7 中的速度是 PHP5.6 中的2倍。在新的版本中,差别已几乎没有,那么为了清楚起见我们当然应该声明类,实例化类来存储对象数据。
2.8、getter 和 setter
从 Java 转过来学习 PHP 的朋友,在对象声明时,可能习惯使用 getter 和 setter,那么,在 PHP 中,使用 getter 和 setter 是否会带来性能上的损失呢?同样,先上例子。
无 setter版:
classUser
{
public $uid;
public $username;
public $age;
function getUserInfo()
{
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
}
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->username="User".$i;
$user->getUserInfo();
}
有 setter版:
classUser
{
public $uid;
private $username;
public $age;
function setUserName($name)
{
$this->username = $name;
}
function getUserInfo()
{
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
}
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->setUserName("User".$i);
$user->getUserInfo();
}
这里只增加了一个 setter。运行结果如下:
[root@localhostphpperf]# time php7 object.php
real 0m0.607s
user 0m0.602s
sys 0m0.004s
[root@localhostphpperf]# time php7 object.php
real 0m0.598s
user 0m0.596s
sys 0m0.000s
[root@localhostphpperf]# time php7 object2.php
real 0m0.673s
user 0m0.669s
sys 0m0.003s
[root@localhostphpperf]# time php7 object2.php
real 0m0.668s
user 0m0.664s
sys 0m0.004s
从上面可以看到,增加了一个 setter,带来了近10%的效率损失。可见这个性能损失是相当大的,在 PHP 中,我们没有必要再来做 setter 和 getter了。需要引用的属性,直接使用即可。
2.9、类属性该声明还是不声明
PHP 本身支持属性可以在使用时增加,也就是不声明属性,可以在运行时添加属性。那么问题来了,事先声明属性与事后增加属性,是否会有性能上的差别。这里也举一个例子探讨一下。
事先声明了属性的代码就是2.8节中,无 setter 的代码,不再重复。而无属性声明的代码如下:
classUser
{
function getUserInfo()
{
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
}
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->username="User".$i;
$user->getUserInfo();
}
两段代码,运行结果如下:
[root@localhostphpperf]# time php7 object.php
real 0m0.608s
user 0m0.604s
sys 0m0.003s
[root@localhostphpperf]# time php7 object.php
real 0m0.615s
user 0m0.605s
sys 0m0.003s
[root@localhostphpperf]# time php7 object3.php
real 0m0.733s
user 0m0.728s
sys 0m0.004s
[root@localhostphpperf]# time php7 object3.php
real 0m0.727s
user 0m0.720s
sys 0m0.004s
从上面的运行可以看到,无属性声明的代码慢了20%。可以推断出来的就是对于对象的属性,如果事先知道的话,我们还是事先声明的好,这一方面是效率问题,另一方面,也有助于提高代码的可读性呢。
2.10、图片操作 API 的效率差别
在图片处理操作中,一个非常常见的操作是将图片缩放成小图。缩放成小图的办法有多种,有使用 API 的,有使用命令行的。在 PHP 中,有 imagick 和 gmagick 两个扩展可供操作,而命令行则一般使用 convert 命令来处理。我们这里来讨论使用 imagick 扩展中的 API 处理图片的效率差别。
先上代码:
function imagick_resize($filename, $outname)
{
$thumbnail = new Imagick($filename);
$thumbnail->resizeImage(200, 200, imagick::FILTER_LANCZOS, 1);
$thumbnail->writeImage($outname);
unset($thumbnail);
}
function imagick_scale($filename, $outname)
{
$thumbnail = new Imagick($filename);
$thumbnail->scaleImage(200, 200);
$thumbnail->writeImage($outname);
unset($thumbnail);
}
function convert($func)
{
$cmd= "find /var/data/ppt |grep jpg";
$start = microtime(true);
exec($cmd, $files);
$index = 0;
foreach($files as $key =>$filename)
{
$outname= " /tmp/$func"."_"."$key.jpg";
$func($filename, $outname);
$index++;
}
$end = microtime(true);
echo "$func $index files: " . ($end- $start) . "s\n";
}
convert("imagick_resize");
convert("imagick_scale");
在上面的代码中,我们分别使用了 resizeImage 和 scaleImage 来进行图片的压缩,压缩的是常见的 1-3M 之间的数码相机图片,得到如下运行结果:
[root@localhostphpperf]# php55 imagick.php
imagick_ resize 169 files: 5.0612308979034s
imagick_ scale 169 files: 3.1105840206146s
[root@localhostphpperf]# php55 imagick.php
imagick_ resize 169 files: 4.4953861236572s
imagick_ scale 169 files: 3.1514940261841s
[root@localhostphpperf]# php55 imagick.php
imagick_ resize 169 files: 4.5400381088257s
imagick_ scale 169 files: 3.2625908851624s
169张图片压缩,使用 resizeImage 压缩,速度在4.5S以上,而使用 scaleImage 则在 3.2S 左右,快了将近50%,压缩的效果,用肉眼看不出明显区别。当然 resizeImage 的控制能力更强,不过对于批量处理而言,使用 scaleImage 是更好的选择,尤其对头像压缩这种频繁大量的操作。本节只是例举了图片压缩 API 作为例子,也正像 explode 和 preg_ split 一样,在 PHP 中,完成同样一件事情,往往有多种手法。建议采用效率高的做法。
以上就是关于 PHP 开发的10个方面的对比,这些点涉及到 PHP 语法、写法以及 API 的使用。有些策略随着 PHP 的发展,有的已经不再适用,有些策略则会一直有用。
有童鞋也许会说,在现实的开发应用中,上面的某些观点和解决策略,有点「然并卵」。为什么这么说呢?因为在一个程序的性能瓶颈中,最为核心的瓶颈,往往并不在 PHP 语言本身。即使是跟 PHP 代码中暴露出来的性能瓶颈,也常在外部资源和程序的不良写法导致的瓶颈上。于是为了做好性能分析,我们需要向 PHP 的上下游戏延伸,比如延伸到后端的服务上去,比如延伸到前端的优化规则。在这两块,都有了相当多的积累和分析,雅虎也据此提出了多达35条前端优化规则,这些同 PHP 本身的性能分析构成了一个整体,就是降低用户的访问延时。
所以前面两部分所述的性能分析,只是有助于大家了解 PHP 开发本身,写出更好的 PHP 程序,为你成为一个资深的 PHP 程序员打下基础,对于实际生产中程序的效率提升,往往帮助也不是特别显著,因为大家也看到,在文章的实例中,很多操作往往是百万次才能看出明显的性能差别。在现实的页面中,每一个请求很快执行完成,对这些基础代码的调用,往往不会有这么多次调用。不过了解这些,总是好的。
那么,对于一个程序而言,其他的性能瓶颈可能存在哪里?我们将深入探讨。所以在本系列的下两篇,我们将探讨 PHP 程序的外围效源的效率问题和前端效率问题,敬请期待。
- PHP技术文章
- PHP中session和cookie的区别
- php设计模式(一):简介及创建型模式
- php设计模式结构型模式
- Php设计模式(三):行为型模式
- 十款最出色的 PHP 安全开发库中文详细介绍
- 12个提问频率最高的PHP面试题
- PHP 语言需要避免的 10 大误区
- PHP 死锁问题分析
- 致PHP路上的“年轻人”
- PHP网站常见安全漏洞,及相应防范措施总结
- 各开源框架使用与设计总结(一)
- 数据库的本质、概念及其应用实践(二)
- PHP导出MySQL数据到Excel文件(fputcsv)
- PHP中14种排序算法评测
- 深入理解PHP原理之--echo的实现
- PHP性能分析相关的函数
- PHP 性能分析10则
- 10 位顶级 PHP 大师的开发原则
- 30条爆笑的程序员梗 PHP是最好的语言
- PHP底层的运行机制与原理
- PHP 性能分析与实验——性能的宏观分析
- PHP7 性能翻倍关键大揭露
- 鸟哥:写在PHP7发布之际一些话
- PHP与MySQL通讯那点事
- Php session内部执行流程的再次剖析
- 关于 PHP 中的 Class 的几点个人看法
- PHP Socket 编程过程详解
- PHP过往及现在及变革
- PHP吉祥物大象的由来
- PHP生成静态页面的方法
- 吊炸天的 PHP 7 ,你值得拥有!
- PHP开发中文件操作疑难问答
- MongoDB PHP Driver的连接处理解析
- PHP 杂谈《重构-改善既有代码的设计》之二 对象
- 在php中判断一个请求是ajax请求还是普通请求的方法
- 使用HAProxy、PHP、Redis和MySQL支撑10亿请求每周架构细节
- HTML、HTML5、XHTML、CSS、SQL、JavaScript、PHP、Web Services 是什么?
- 重构-改善既有代码的设计
- PHP场景中getshell防御思路分享
- 移动互联时代,你看看除了PHP你还会些什么
- 安卓系统上搭建本地php服务器环境
- PHP中常见的缓存技术!
- PHP里10个鲜为人知但却非常有用的函数
- 成为一名PHP专家其实并不难
- PHP 命令行?是的,您可以!
- PHP开发提高效率技巧
- PHP八大安全函数解析
- PHP实现四种基本排序算法
- PHP开发中的中文编码问题
- php.get.post
- php发送get、post请求的6种方法简明总结
- 中高级PHP开发者应该掌握哪些技术?
- 前端开发
- web前端知识体系大全
- 前端工程与性能优化(下)
- 前端工程与性能优化(上)
- 2016 年技术发展方向
- Web应用检查清单
- 如何成为一名优秀的web前端工程师
- 前端组件化开发实践
- 移动端H5页面高清多屏适配方案
- 2015前端框架何去何从
- 从前端看“百度迁徙”的技术实现(一)
- 从前端看“百度迁徙”的技术实现(二)
- 前端路上的旅行
- 大公司里怎样开发和部署前端代码?
- 5个经典的前端面试问题
- 前端工程师新手必读
- 手机淘宝前端的图片相关工作流程梳理
- 一个自动化的前端项目实现(附源码)
- 前端代码异常日志收集与监控
- 15年双11手淘前端技术总结 - H5性能最佳实践
- 深入理解javascript原型和闭包系列
- 一切都是对象
- 函数和对象的关系
- prototype原型
- 隐式原型
- instanceof
- 继承
- 原型的灵活性
- 简述【执行上下文】上
- 简述【执行上下文】下
- this
- 执行上下文栈
- 简介【作用域】
- 【作用域】和【上下文环境】
- 从【自由变量】到【作用域链】
- 闭包
- 完结
- 补充:上下文环境和作用域的关系
- Linux私房菜