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

[经验分享] PHP中require PK require_once, 构建自己的高效require_once(10倍的性能提升)

[复制链接]

尚未签到

发表于 2017-4-13 12:03:09 | 显示全部楼层 |阅读模式
  author: selfimpr
  blog: http://blog.csdn.net/lgg201
  mail: lgg860911@yahoo.com.cn
  经过测试, require_once是一个性能低下的语法结构, 当然, 这个性能低下是相对于require而言的, 本文阐述我们项目目前使用的require方式, 通过实验代码证明其高效性, 同时, 描述我们在使用过程中遇到的问题, 避免他人在同一个石头上绊倒....
  如果有更好的建议和本文有不正确观点, 还望指正, 谢谢.
  require: 引入一个文件, 运行时编译引入.
  require_once: 功能等同于require, 只是当这个文件被引用过后, 不再编译引入.
  上面就是两者的区别. 可以看出, 两者的不同仅在于require_once有一个判断是否已经引用过的机制...
  通过网络搜索, 可以看到很多关于require_once性能比require低很多的数据, 这里就不再做这个试验.
  我们项目中的做法是: 在每个文件起始位置定义一个全局变量, require的时候, 使用isset($xxxxxx) or require 'xxxxx.php';
  这种做法有什么不足呢?
  全局变量以$xxx方式定义的时候, 如果该文件再函数内被require, 该变量会被解析为函数的局部变量, 而不是全局的, 因此, 函数内部的isset($xxx) or require 'xxx.php'这个语法结构会失效, 带来的结果当然是意料不到的, 比如, 类的重定义, 方法的重定义等等.....
  前车之鉴, 所以, 全局变量的定义, 请使用$GLOBALS['xxx'], require的时候, 使用isset($GLOBALS['xxx']) or require 'xxx.php';, 使用GLOBALS会比直接定义稍慢, 但总比错是要好很多的...
  由于我们之前的全局变量是直接定义的, 今天在和同事讨论的过程中, 想到另外一种写法:
  定义的位置仍然使用$xxx方式直接定义, require的方法中进行修改(文件头部定义的全局变量和文件名是有关联的)
  function ud_require($xxx) {
  global $$xxx;
  isset($$xxx) or require $xxx . '.php';
  }
  这种方式使用了动态变量, 经过和直接的GLOBALS方式比较, 有两个显著缺点:
  1. 性能, 由于动态变量的引入, 比GLOBALS方式慢2倍左右
  2. 无法解决间接引用问题, 因为我们无法预知被间接引用的文件名, 也就无法用global去声明那些被间接引用的文件中定义的标记性全局变量了.
  好了....下面是我对GLOBALS方式的require和require_once的测试:
  测试入口文件:
  require_requireonce.php
  <?phpfunction test1($filename) {//pathinfo($filename);isset($filename) or require $filename;}function test2() {require_once 'require_requireonce_requireonce.php';}$start = microtime(true);while($i ++ < 1000000) isset($GLOBALS['require_requireonce_require.php']) or require 'require_requireonce_require.php';$end = microtime(true);echo "不使用方法的isset or require方式: " . ($end - $start) . "<br />/n";$start = microtime(true);while($j ++ < 1000000) test1('require_requireonce_require.php');$end = microtime(true);echo "使用方法的isset or require方式: " . ($end - $start) . "<br />/n";$start = microtime(true);while($k ++ < 1000000) test2();$end = microtime(true);echo "require_once方式: " . ($end - $start) . "<br />/n";?><meta http-equiv="Content-Type: text/html; charset=utf-8" />
  require_requireonce_require.php   (用于测试require的被引入文件)
  <?php$GLOBALS['require_requireonce_require.php'] = 1;class T1 {}?>
  require_requireonce_requireonce.php  (用于测试require_once的被引入文件)
  <?phpclass T2 {}?>
  下面是测试的结果(单位: 秒):
  不使用方法的isset or require方式: 0.22953701019287
使用方法的isset or require方式: 0.23866105079651
require_once方式: 2.3119640350342
  可以看出, 不套一个方法的require速度是比使用方法的略快的, 两者速度都是require_once的10倍左右...
  那么, 性能损耗究竟在哪里呢?
  上面require_requireone.php文件中的test1方法中, 我注释了一句pathinfo($filename), 因为, 我本来意图是使用文件名不带后缀作为标记性的全局变量名的, 但是, 当我使用pathinfo之后, 我发现这种方式的性能消耗和require_once基本一致了......因此, 我在那里单独的加了一个pathinfo的调用, 又做了测试, 果然是pathinfo在捣鬼.......所以, 后面我就修改为了现在的版本, 直接使用文件名作为变量名, 如果你害怕文件名重复, 那不妨加上路径名...
  猜测: 加上pathinfo之后, require和require_once的性能消耗基本一致, 那我们是否可以猜测PHP内部对require_once的处理是基于它的呢? 据说PHP5.3中对require_once做了显著的优化, 但是, 我测试过程中使用的是PHP5.3.5版本, 仍然能够看到和require明显的差距, 难道只是比之前版本较大优化? 这个倒还没有测试....
  本文写完后, 我尝试把test1方法做了如下修改
  isset($GLOBALS[substr($filename, 0, strlen($filename) - 4)]) or require $filename;
  使用手动的字符串截取, 当然, 截取是要耗时的, 不过比pathinfo的版本是要好一点的. 这次的测试结果是:
  不使用方法的isset or require方式: 0.21035599708557
使用方法的isset or require方式: 0.92985796928406
require_once方式: 2.3799331188202
  好了, 不再说废话了, 结论:
  对于require_once修改为isset or require方式, 需要注意以下几方面:
  1. 每个文件头部定义唯一的一个标记性变量, 使用$GLOBALS['XXX'] = 1;的方式定义, 并且, 建议变量名是文件名或带路径的文件名(如果单独的文件名会重复)
  2. 定义一个自定义require方法:
  function ud_require_once($filename) {
  isset($GLOBALS[$filename]) or require $filename;
  }
  完, 谢谢.

运维网声明 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-364466-1-1.html 上篇帖子: Warning Cannot send session cookie 下篇帖子: 考虑 PHP 5.0~5.6 各版本兼容性的 cURL 文件上传--干货【被坑过】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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