PHP性能优化建议


基本原则:少写php代码,多使用PHP内置的变量、常量、函数。 性能问题:php代码写的越长长执行效果就会越差,多用php自身的函数等

【内置函数的性能优劣】

    尽量使用更快内置函数,不同函数依然存在快慢差异。

    尽量少用魔法函数,魔法函数性能低。为了给程序员省事,php语言为你做了很多linux time函数 可以直接测试程序的耗时情况 魔法函数举例:__get();可以不用尽量不用,如果必须要用的时候再用。

    不使用@错误抑制符,改用try throw


【合理使用内存】

    情况描述:php有内存回收机制保底,但也要小心使用内存

    建议:利用unset()及时释放不使用的内存(注:unset出现注销不掉的情况,自己查资料)


【少的使用正则表达式】

    情况描述:正则表达式性能低,因为正则表达式回溯开销较大

    好的建议:利用字符串处理函数,实现相同的逻辑


【避免循环内做运算】

    情况描述:循环内的计算式会被重复计算

    例 for($i=0;$i<strlen($str);$i++) 每一次for循环都会进行计算strlen


【减少计算密集型业务】

    比如不适合大批量日志分析,或者大批量数据处理。

    语言特性决定了PHP不适合做大数据运算

    所有处理都需要转换成C语言,与C相比,C更好。

    还有环境问题,还有语言特性。额外开销比C大很多。变量寄存等。

    适合处理场景:适合衔接webserver与后端服务、UI呈现。(就是接口,简单数据处理,和套页面)


【使用带引号字符串做键值】

    php会将没有引号的键值检查一遍是不是常量,产生查询常量的开销


【扩展使用】

    PHP扩展除了使用方便,还是提升性能的亲密伙伴。主要应用有三点:

    ·    开启opcode的缓存,来避免重复的编译。可以使用APC,eAccelerator,XCache等PHP扩展,我们使用xcache。这种只要安装即可。

    ·    使用扩展提供的方法(或PHP标准库的方法)。通过PHP扩展代替原PHP代码中高频的逻辑,扩展实现的效率比PHP代码中的高。但实际上满足我们项目的扩展方法有限,很多基础方法需要时一步封装,除非有能力自己开发扩展。可考虑使用扩展实现的PHP框架,如phalcon、yaf。

    ·    本地缓存,也常用扩展来支持,比如xcache。本地可使用缓存扩展,缓存一些配置数据、元数据或主数据,不用每次都从数据库或文件中读取。


【推荐方案】

    减少文件类操作。常见PHP场景的开销次序:读写内存 < 读写数据库 < 读写磁盘 < 读写网络数据

    减少php发起网络请求,优化网络请求

    ·    网络请求的坑:1对方接口的不确定因素 2 网络稳定性

    ·    优化网络请求方法

        ·    设置超时时间(建议值)

                连接超时 200ms 这是上限,最多也不能超过这个时间

                读超时 800ms 这个看具体情况

                写超时 500ms 建议不要超过500ms

        ·    将串行请求并行化

                使用curl_multi_*() 返回时间是看用时最长的那个请求

                使用swoole扩展,通过C来进行并行化。(推荐使用)

    压缩PHP接口输出:如果用php做接口可通过使用Gzip压缩实现更高效的输出。压缩输出的利弊:

    ·    利:利于数据输出,client能更快获取数据

    ·    弊:额外的CPU开销。如果请求大,可能会有问题

        gzip如果数据量小于几十K的时候效果并不理想。如果大于100k,压缩就有效果。

    缓存重复计算内容:固定重复请求的数据做缓存。

    重叠时间窗口思想:串行变并行。如果后一个请求不强依赖于前一个返回值。就可以变成并行,降低总体时间消耗


【汇总建议】

    用单引号替代双引号引用字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会。

    如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。

    $row['id'] 的速度是$row[id]的7倍。

    echo 比 print 快,并且使用echo的多重参数(译注:指用‘,’号而不是‘.’)代替字符串连接,比如echo $str1,$str2。区别用‘.’,先拼接,在整个输出;用‘,’,是挨个把三个变量输出。

    在执行for循环之前先确定最大循环数,不要每循环一次都计算最大值。

    foreach效率更高,尽量用foreach代替while和for循环,如果考虑到foreach($array as $var)每次拷贝的消耗,可以使用foreach($array as &$var)这样的引用。

    尽量避免使用魔术变量,如__get,__set,__autoload。

    require_once()代价昂贵。require_once和include_once需要判重,因此效率上要低,但是5.2版本后效率问题已经基本解决。

    include文件时尽量使用绝对路径,因为它避免了PHP去include_path里查找文件的速度,解析操作系统路径所需的时间会更少。尽量少用iniset()来设置include_path。

    返回脚本开始执行(即服务器端收到客户端请求)的时刻,使用$_SERVER['REQUEST_TIME']要好于time()。因为$_SERVER['REQUEST_TIME']保存了发起该请求时刻的时间戳,而time()则返回当前时刻的Unix时间戳。

    函数代替正则表达式完成相同功能,字符串操作比正则替换要快。如strtok、strstr、strpos、str_replace、substr、explode、implode等等。注意不同的函数快慢也不同,str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。

    使用选择分支语句(译注:即switch case)好于使用多个if,else if语句。因为php中switch支持数值和字符串变量,比C的switch要好用,建议使用。

    数据库连接当使用完毕时应关掉,不要用长连接。建议在连接之前,最好设置一下相应的超时机制,例如链接超时、读写超时、等待超时等。

    错误消息代价昂贵。所以说在代码测试完成,上线之前删除错误信息报告代码。

    在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。递增一个全局变量要比递增一个局部变量慢2倍。递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9至10倍。仅定义一个局部变量而没在函数中调用它,同样会减慢速度(其程度相当于递增一个局部变量)。

    派生类中的方法运行起来要快于在基类中定义的同样的方法。

    Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。尽量多用静态HTML页面,少用脚本。

    除非脚本可以缓存,否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能,以免除编译开销。

    尽量可使用memcached等做缓存。memcached是一款高性能的内存对象缓存系统,可用来加速动态Web应用程序,减轻数据库负载。对运算码(OPcode)的缓存很有用,使得脚本不必为每个请求做重新编译。

    当执行变量$i的递增或递减时,$i++会比++$i慢一些。这种差异是PHP特有的,并不适用于其他语言。++$i更快是因为它只需要3条指令(opcodes),$i++则需要4条指令。后置递增实际上会产生一个临时变量,这个临时变量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种,正如Zend的PHP优化器所作的那样。

    面向对象(OOP)是非必要的,因为面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。并非要用类实现所有的数据结构,数组也很有用。

    不要把方法细分得过多,仔细想想你真正打算重用的是哪些代码?不要过分迷恋各种设计模式,如上一条描述,过分的封装会带来性能的下降。需要考虑两者的权衡。Php有自己的特点,切不可东施效颦,过分效仿java的模式。

    分解成方法要适当,行数少使用频率高的方法尽量用直接写代码,可以减少函数堆栈开销;且方法嵌套不宜过深,否则大大影响PHP的运行效率。

    尽量采用大量的PHP内置函数,除去空函数调用的影响,内置函数和同样功能的C函数性能基本差不多。

    如果在代码中存在大量耗时的函数,你可以考虑用C扩展的方式实现它们。

    打开apache的mod_deflate模块,可以提高网页的浏览速度。mod_zip可作为Apache模块,用来即时压缩你的数据,并可让数据传输量降低80%。

    在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情况下,尽量用file_get_contents,因为他的效率高得多!但是要注意file_get_contents在打开一个URL文件时候的PHP版本问题。这个要记住,尽量使用file_get_contents和file_put_contents,不需要自己判断文件句柄打开是否成功。

    尽量的少进行文件操作,虽然PHP的文件操作效率也不低的;

    优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作;

    循环内部不要声明变量,尤其是大变量:对象。这个必须的,变量过多或者过大时,每次重分配的开销就无法忽略。

    多维数组尽量不要循环嵌套赋值;

    对global变量,应该用完就unset()释放掉;

    当操作字符串并需要检验其长度是否满足某种要求时,使用isset()替代strlen()函数。isset()作为一种语言结构,它的执行不需要函数查找和字母小写化。此函数执行起来相当快,只返回在zval结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数更慢,因为函数调用会经过诸多步骤,如字母小写化(指函数名小写化,PHP不区分函数名大小写)、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用isset() 技巧加速执行你的代码。   

    评估检验(profile)你的代码。检验器会告诉你,代码的哪些部分消耗了多少时间。Xdebug调试器包含了检验程序,评估检验总体上可以显示出代码的瓶颈。

    函数相关信息保存在一个大的hash_table中,每次调用时通过函数名在hash表中查找,因此函数名长度对性能也有一定影响。

    函数不宜嵌套过深,递归使用要谨慎。

    如不是特殊需要,参数传递都建议使用传值而不是传引用。当然,如果参数是很大的数组且需要修改时可以考虑引用传递。

    使用NoSQL、Memchached或者Redis缓存。这些是高性能的分布式内存对象缓存系统,能提高动态网络应用程序性能,减轻数据库的负担。这对运算码 (OPcode)的缓存也很有用,使得脚本不必为每个请求重新编译。


上一篇 下一篇

评论

登录后可发表评论