设为首页 收藏本站
查看: 328|回复: 0

[经验分享] php_代码分析与优化_转转转转

[复制链接]

尚未签到

发表于 2017-3-30 09:02:34 | 显示全部楼层 |阅读模式
PHP 性能优化
  1 不要随便就复制变量
有时候为了使 PHP 代码更加整洁,一些 PHP 新手(包括我)会把预定义好的变量复制到一个名字更简短的变量中,其实这样做的结果是增加了一倍的内存消耗,只会使程序更加慢。试想一下,在下面的例子中,如果用户恶意插入 512KB 字节的文字到文本输入框中,这样就会导致 1MB 的内存被消耗!

BAD:
$description = $_POST['description'];
echo $description;

GOOD:
echo $_POST['description'];

2 字符串使用单引号,并且字符串中含有变量的使用单引号字符串链接。
GOOD:
$output = 'This is a plain string';

BAD:
$type = "mixed";
$output = "This is a $type string";

GOOD:
$type = 'mixed';
$output = 'This is a ' . $type .' string';
  3 静态成员的调用一定要定义成static类型 foo::bar();效率会提升50-60%
  // PHP CODE Highliting for CU by dZ902
Php代码


  • <?php  
  • class foo {  
  •     function bar () {  
  •         echo 'foobar' ;  
  •     }  
  • }  
  • $foo = new foo ;  
  • // instance way  
  • $foo -> bar ();  
  • // static way  
  • foo :: bar ();  
  • ?>  

<?phpclass foo {function bar () {echo 'foobar' ;}}$foo = new foo ;// instance way$foo -> bar ();// static wayfoo :: bar ();?>


  效率会提升50-60%
  4 使用类常量的好处是: 贴士:PHP 5 新功能,类似于 C++ 的 const。

- 编译时解析,没有额外开销
- 杂凑表更小,所以内部查找更快
- 类常量仅存在于特定「命名空间」,所以杂凑名更短
- 代码更干净,使除错更方便
  5 不要调用毫无意义的函数,有对应常量的时候,不要使用函数
php_uname('s') == PHP_OS;
php_version() == PHP_VERSION;
php_sapi_name() == PHP_SAPI;
虽然使用不多,但是效率提升大概在 3500% 左右
  6 当记录时间的时候使用$_SERVER['REQUEST_TIME'];不用time();
  7 require/include_once 每次被调用的时候都会打开目标文件! require_once()代价昂贵
- 如果用绝对路径的话,PHP 5.2/6.0 不存在这个问题
- 新版的 APC 缓存系统已经解决这个问题
文件 I/O 增加 => 效率降低
如果需要,可以自行检查文件是否已被 require/include。
  include 'file.php'; // bad approach

incldue './file.php'; // good

include '/path/to/file.php'; // ideal

  8 加速 pcre 能不用正则就不用正则,仔细看阅读手册的字符串函数
  例如: strpbrk() strncasecmp() strpos()/strrpos()/stripos()/strripos()
  9 如果需要转换的全是单个字符的时候,用字符串而不是数组来做 strtr:
  $addr = strtr($addr, "abcd", "efgh"); // good
$addr = strtr($addr, array('a' => 'e',
// ...
)); // bad

  效率提升十倍
  10 不要做无谓的替换: 即使没有替换,str_replace 也会为其参数分配内存。很慢!解决办法:
- 用 strpos 先查找(非常快),看是否需要替换,如果需要,再替换
效率:
- 如果需要替换:效率几乎相等,差别在 0.1% 左右。
- 如果不需要替换:用 strpos 快 200%。
  11 善用 strncmp:当需要对比「前 n 个字符」是否一样的时候,用 strncmp/strncasecmp,而不是 substr/strtolower,更不是 PCRE,更千万别提 ereg。strncmp/strncasecmp 效率最高(虽然高得不多)。
  12 substr_compare 应该比先 substr 再比较快咯。答案是否定的,除非:- 无视大小写的比较- 比较较大的字符串
  13 不要使用常量代替字符串
  为什么:
  - 需要查询杂凑表两次
- 需要把常量名转换为小写(进行第二次查询的时候)
- 生成 E_NOTICE 警告
- 会建立临时字符串
效率差别:700%。
  
  14 不要把count/strlen/sizeof放到for循环的条件语句中
  <?php
for ($i = 0, $max = count($array);$i < $max; ++$i);
?>

  

  15 PHP 有很多扩展和函数可用,在实现一个功能的之前,应该看看 PHP 是否有了这个功能?是否有更简单的实现?
  $filename = "./somepic.gif";
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);
// vs. much simpler
file_get_contents('./somepic.gif');

  16 关于引用的技巧
  引用就是将多个不同的php变量绑定到一个地址,对于大容量参数似乎会节省内存
  简化对复杂结构数据的访问
  Php代码


  • <?php  
  • $a [ 'b' ][ 'c' ] = array();  
  • // slow 2 extra hash lookups per access  
  • for ( $i = 0 ; $i < 5 ; ++ $i )  
  •     $a [ 'b' ][ 'c' ][ $i ] = $i ;  
  • // much faster reference based approach  
  • $ref =& $a [ 'b' ][ 'c' ];  
  • for ( $i = 0 ; $i < 5 ; ++ $i )  
  •     $ref [ $i ] = $i ;  
  • ?>  

<?php$a [ 'b' ][ 'c' ] = array();// slow 2 extra hash lookups per accessfor ( $i = 0 ; $i < 5 ; ++ $i )$a [ 'b' ][ 'c' ][ $i ] = $i ;// much faster reference based approach$ref =& $a [ 'b' ][ 'c' ];for ( $i = 0 ; $i < 5 ; ++ $i )$ref [ $i ] = $i ;?>

  - 优化内存使用
C-sharp代码


  • <?php  
  • $a = 'large string';  
  • // memory intensive approach  
  • function a($str)  
  • {  
  •  return $str.'something';  
  • }  
  • // more efficient solution  
  • function a(&$str)  
  • {  
  •  $str .= 'something';  
  • }  
  • ?>  

  <?php$a = 'large string';// memory intensive approachfunction a($str){return $str.'something';}// more efficient solutionfunction a(&$str){$str .= 'something';}?>
  通过修改$str的值道道修改$a值的目的
  注意不要错误的使用引用传递,因为php具有写时拷贝的特征,一般不需要改变值的时候不要使用引用传递
  http://www.wljcz.com/html/PHPjiaocheng/phpjichu/2010/0319/3068.html
  按值传递:函数范围内对值的任何改变在函数外部都会被忽略
按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改
优缺点:按值传递时,php必须复制值。特别是对于大型的字符串和对象来说,这将会是一个代价很大的操作。
按引用传递则不需要复制值,对于性能提高很有好处。
  17 注销那些不用的变量尤其是大数组,以便释放内存。
  使用unset:
  对于PHP的局部变量,劈如自定义函数和类方法中的过程变量,完全无需使用 unset,越 unset 占用内存就越多,应该是PHP在运行过程中,局部变量在使用过后会立即注销,所以如果再注销的话,完全是多了步骤,起了反作用。
  而对于全局变量,PHP只会在当前PHP文件的运行结束后才会释放此部分内存,在运行过程中是不释放的,所以应该适时的注销相关不再用的全局变量。
对于已经实例化的类的属性,注销掉也是可以释放内存的,因为这也是在整个过程中生效,当然如果可以,你可以直接注销实例化的变量。
  对于注销数组还可以使用$a = array();
  避免溢出,释放内存,也是优化程序
  http://blog.zol.com.cn/781/article_780182.html
  18 尽量避免使用__get,__set,__autoload。
  19 str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。
  20 如果一个字符串替换函数,可接受数组或字符作为参数,并且参数长度不太长,那么可以考虑额外写一段替换代码,使得每次传递参数是一个字符,而不是只写一行代码接受数组作为查询和替换的参数。 ?
  21 打开apache的mod_deflate模块,启动压缩功能
  http://yangsiwei.com/add-mod_deflate-module-to-apache2/comment-page-1
  22 数据库连接当使用完毕时应关掉。这个是需要在不同的情况下有不同的考虑的
  链接使用:mysql_connent, 关闭使用:mysql_close
  http://bbs.chinaunix.net/viewthread.php?tid=785198
  具体的数据库持久连结的概念在php手册里有很详细的介绍
  方案一:
mysql.open();
mysql.insert('sql1');
mysql.insert('sql2');

mysql.insert('sqln');
mysql.close();
方案二:
mysql.open();
mysql.insert('sql1');
mysql.close();
mysql.open();
mysql.insert('sql2');
mysql.close();

mysql.open();
mysql.insert('sqln');
mysql.close();
  肯定是第一个效率高的。
从最简单的来说,连接数据库是要有时间的,多次的连接效率肯定慢。
而且要是是远程数据库的话,你这种不停的要求连接的语句会带宽占用时间也大。
第二种方法应该是防止有的线程占线的,就是连接后有大段不需要连数据库的逻辑执行的程序,但像楼主这样写的连续执行sql的都不用多说了,肯定是第一个好。
  mysql Resource id概念 ?
  数据库的连接将保持开放状态,直到所有对它的引用被释放。如果在主脚本的顶端打开连接,并将其句柄存储在一个全局变量中,那么该连接将一直处于开放状态,直到脚本结束,或者直到 $dbh 变量被设为 null。如果在一个函数中打开连接,并且只将句柄存储在一个本地变量中,那么当函数返回时,连接将被关闭。这些语义对于 PHP 中的任何对象都是一样的,没有什么特别的地方。
  23 $row[‘id’]的效率是$row[id]的7倍
  24 错误消息代价昂贵
  25 在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。
  http://www.huison.cn/blog/article.asp?id=230
  26 递增一个全局变量要比递增一个局部变量慢2倍
  27 递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。
  28 仅定义一个局部变量而没在函数中调用它,同样会减慢速度(其程度相当于递增一个局部变量)。PHP大概会检查看是否存在全局变量。
  29 方法调用看来与类中定义的方法的数量无关,因为我(在测试方法之前和之后都)添加了10个方法,但性能上没有变化。
  30 派生类中的方法运行起来要快于在基类中定义的同样的方法。
  31 用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会。当然,只有当你不需要在字符串中包含变量时才可以这么做。
  32 Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。尽量多用静态HTML页面,少用脚本
  33 除非脚本可以缓存,否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能,以免除编译开销。
  34 尽量做缓存,可使用memcached。memcached是一款高性能的内存对象缓存系统,可用来加速动态Web应用程序,减轻数据库负载。对运算码(OP code)的缓存很有用,使得脚本不必为每个请求做重新编译。
  35 当操作字符串并需要检验其长度是否满足某种要求时,你想当然地会使用strlen()函数。此函数执行起来相当快,因为它不做任何计算,只返回在zval结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数,多多少少会有些慢,因为函数调用会经过诸多步骤,如字母小写化(译注:指函数名小写化,PHP不区分函数名大小写)、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用isset()技巧加速执行你的代码。
  Ex.(举例如下)
if (strlen($foo) < 5) { echo "Foo is too short"; }
vs.(与下面的技巧做比较)
if (!isset($foo{5})) { echo "Foo is too short"; }
  调用isset()恰巧比strlen()快,因为与后者不同的是,isset()作为一种语言结构,意味着它的执行不需要函数查找和字母小写化。也就是说,实际上在检验字符串长度的顶层代码中你没有花太多开销。
  36 当执行变量$i的递增或递减时,$i++会比++$i慢一些。这种差异是PHP特有的,并不适用于其他语言,所以请不要修改你的C或Java代码并指望它们能立即变快,没用的。++$i更快是因为它只需要3条指令(opcodes),$i++则需要4条指令。后置递增实际上会产生一个临时变量,这个临时变量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种,正如Zend的PHP优化器所作的那样。牢记这个优化处理不失为一个好主意,因为并不是所有的指令优化器都会做同样的优化处理,并且存在大量没有装配指令优化器的互联网服务提供商(ISPs)和服务器。
  37 并不是事必面向对象(OOP),面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。
  38 并非要用类实现所有的数据结构,数组也很有用。
  39 不要把方法细分得过多,仔细想想你真正打算重用的是哪些代码?
  40 当你需要时,你总能把代码分解成方法。
  41 尽量采用大量的PHP内置函数。
  42 如果在代码中存在大量耗时的函数,你可以考虑用C扩展的方式实现它们
  43 评估检验(profile)你的代码。检验器会告诉你,代码的哪些部分消耗了多少时间。Xdebug调试器包含了检验程序,评估检验总体上可以显示出代码的瓶颈。
  44 mod_gzip可作为Apache模块,用来即时压缩你的数据,并可让数据传输量降低80%。
  http://www.wangchao.net.cn/bbsdetail_1754024.html 压缩页面
  45 Excellent Article (http://phplens.com/lens/php-book/optimizing-debugging-php.php)about optimizing php by John Lim 另一篇优化PHP的精彩文章,由John Lim撰写。
  参考 :http://www.cnblogs.com/xin478/archive/2008/09/10/1288657.html
  46 线程池的介绍及简单实现 http://www.wangchao.net.cn/bbsdetail_1754028.html
  http://www.ajaxstu.com/PHPbiancheng/183975.html 针对php,
  http://home.phpchina.com/space.php?uid=92493&do=blog&id=182169 深入研究线程池
  php在连接mysql数据库的时候我们可以采用临时的连接,当然我们也可以采用永久连接,采用永久连接的时候因为有一次连接的开销,所以时间就大大的减少了,但是我们才用永久连接的时候一定要注意一下的一些问题?

  永久连接在数据库崩溃或者别的原因的话,永久连接不知道数据库已经关闭,然后在去连接数据库的时候就会出错,解决的办法只有写一个方法定时的检查数据库的状态,如果出错就从新连接。

  php与mysql数据库的连接的永久连接是创建一些线程,然后每一次都连接的时候就在线程池中找到一个闲置的连接,然后返回,但是apache服务器只支持一定数目的线程,当服务器的访问量特别大的时候,数据库的连接线程可能就会超出apache服务器支持的数目,这样可能回造成服务器的崩溃,所以我门要在apache服务器的配制文件中修改线程的最大数目,来保证服务器的稳定。

  当有多个用户同时使用一个永久连接的时候,可能回出现数据的错误,或者是读脏数据等其他的情况,这也是我们经常要注意的问题!
  问题:什么时候使用线程池
  47 php效率总结
  1),在函数中,传递数组时
使用 return 比使用 global 要高效
比如


function userloginfo($usertemp){
$detail=explode("|",$usertemp);
return $detail;
}
$login=userloginfo($userdb);



function userloginfo($usertemp){
global $detail;
$detail=explode("|",$usertemp);
}
userloginfo($userdb);



要高效

2),(这个代码用于得到程序目录对应的网址,推荐使用)

$urlarray=explode('/',$HTTP_SERVER_VARS['REQUEST_URI']);
$urlcount=count($urlarray);
  unset($urlarray[$urlcount-1]);
$ofstarurl='http://'.$HTTP_SERVER_VARS['HTTP_HOST'].implode('/',$urlarray);

这段代码比

$pre_urlarray=explode('/',$HTTP_SERVER_VARS['HTTP_REFERER']);
$pre_url=array_pop($pre_urlarray);

要高效

3),在循环中判断时,数值判断使用恒等要比等于高效
$a=2;$b=2;
比如
if($a==$b)$c=$a;

if($a===$b)$c=$a;
高效

4),mysql 查询时尽量使用where in 少用 limit
limit查多记录的前几条, 速度很快, 但是查询最面几条就会慢
使用in .在查询连续性记录,非常快, 非连续性记录第一次运行会稍微慢一点,但是之后将比较快!

5),NT 服务器数据操作稳定性不及unix/linux

6),输出前使用尽量使用 ob_start(); 可以加快输出速度,适用NT或nuli/linux,对unlix类服务器 如果使用 ob_start('ob_gzhandler');输出效率将更高

7),判断的时候尽量使用if($a==他的值) 否定的时候尽量使用if(empty($a)),因为这样程序运行更快速

8),使用不等时 != 与 <> 效率相当

9), 个人经验得 使用 $a="11111111111111"; 的效率和 $a='11111111111111'; 相当.并不象书本说的相差很大

10), 使用规范的SQL语句, 会有利于MySQL的解析

11),使用

if($online){
$online1=$online;
setcookie('online1',$online,$cookietime,$ckpath,$ckdomain,$secure);
}

COOKIE 将马上生效
使用

if($online)
setcookie('online1',$online,$cookietime,$ckpath,$ckdomain,$secure);

COOKIE 需要再刷新一次才能生效

12),使用

$handle=fopen($filename,wb);
flock($handle,LOCK_SH);
$filedata=fread($handle,filesize($filename));
fclose($handle);



file($filename);

无论在速度还是稳定上都要优秀

13),截断字符串优化函数(可避免?字符出现)

function substrs($content,$length) {
if(strlen($content)>$length){
$num=0;
for($i=0;$i<$length-3;$i++) {
if(ord($content[$i])>127)$num++;
}
$num%2==1 ? $content=substr($content,0,$length-4):$content=substr($content,0,$length-3);
$content.=' ...';
}
return $content;
}

比如$newarray[1]=substrs($newarray[1],25);

14),程序中屏蔽大小写

for ($asc=65;$asc<=90;$asc++)
{ //strtolower() 此函数在一些服务器会产生乱码!
if (strrpos($regname,chr($asc))!==false)
{
$error="为了避免用户名混乱,用户名中禁止使用大写字母,请使用小写字母";
$reg_check=0;
}
}

15),不使用 file();和不使用 fget();(不稳定或速度慢) 取一数组函数

function openfile($filename,$method="rb")
{
$handle=@fopen($filename,$method);
@flock($handle,LOCK_SH);
@$filedata=fread($handle,filesize($filename));
@fclose($handle);
$filedata=str_replace("\n","\n<ofstar:>",$filedata);
$filedb=explode("<ofstar:>",$filedata);
//array_pop($filedb);
$count=count($filedb);
if($filedb[$count-1]==''){unset($filedb[$count-1]);}
return $filedb;
}
//这个函数虽然代码比较多,不过在速度和稳定性上优势很大!
  48 php autoload与include性能比较
  http://www.xue163.com/html/2009430/1322206.html
  49 使用XDebug对php进行性能分析
  http://www.cnblogs.com/afritxia2008/archive/2010/06/26/1765955.html
  50 三款免费的php加速器:apc、eAccelerator、XCache比较
  http://www.vpser.net/opt/apc-eaccelerator-xcache.html
  51 ab windows下的操作 http://server.csdn.net/n/20090523/1789.html
  52 mysql 慢查询分析 http://www.iteye.com/wiki/topic/543075
  http://www.iteye.com/topic/242516
  http://msnvip.iteye.com/blog/543075
  http://thomaslee007.iteye.com/blog/231611
  54 异步IO,APC,IO完成端口,线程池与高性能服务器系列文章 http://hi.baidu.com/027fs/blog/item/a331d5222e6a61f9d7cae2b6.html
  参考资料
Excellent Article (http://phplens.com/lens/php-book/optimizing-debugging-php.php)about optimizing php by John Lim 另一篇优化PHP的精彩文章,由John Lim撰写。
  
http://ilia.ws

Ilia 的个人网站,Blog,他参与的开发以及出版的一些稿物链接等等。
Ilia Alshanetsky(佩服之至) 在多个 PHP 会议上的演讲,主要是各类提高 PHP 性能的技巧。为求精准,很多部分都有详细的效率数据,以及对应的版本等等。如果需要看原文档,请到文末「参考资料」部分

http://ez.no

eZ components 官方网站,eZ comp 是针对 PHP5 的开源通用库,以效率为己任,Ilia 也参与了开发。

http://phparch.com

php|architect,不错的 php 出版商/培训组织。买不起或者买不到的话,网上可以下到很多经典的盗版。

http://talks.php.net

PHP 会议上的演讲合集,现在还不是很丰富,不过内容都是让人一看就容易废寝忘食的好东东,推荐早上睡眼朦胧的时候或者吃完午饭仔细研究,否则你会忘记吃饭和睡觉的!

  http://www.westphp.com/bbs/archiver/tid-1134.html新的40条有点不同
  做好性能测试应该掌握的内容 http://www.cnblogs.com/jackei/archive/2008/06/27/1231307.html
  一个很好的blog,里面有使用nginx的负载均衡等很多增加性能方面的  http://www.phpabc.cn/

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-357379-1-1.html 上篇帖子: 安装php扩展ssh实现服务器间文件拷贝 下篇帖子: php 作为shell 脚本语言解释器
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表