强烈声明: 不要使用(include/require)_once


Posted in PHP onJune 06, 2013

关于使用include还是include_once(以下,都包含require_once), 这个讨论很长了, 结论也一直有, 就是尽量使用include, 而不是include_once, 以前最多的理由的是, include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载.

诚然, 这个理由是对的, 不过, 我今天要说的, 是另外一个的原因.

我们知道, PHP去判断一个文件是否被加载, 是需要得到这个文件的opened_path的, 意思是说, 比如:

<?php
set_include_path("/tmp/:/tmp2/");
include_once("2.php");
?>

当PHP看到include_once “2.php”的时候, 他并不知道这个文件的实际路径是什么, 也就无法从已加载的文件列表去判断是否已经加载, 所以在include_once的实现中, 会首先尝试解析这个文件的真实路径(对于普通文件这个解析仅仅类似是检查getcwd和文件路径, 所以如果是相对路径, 一般是不会成功), 如果解析成功, 则查找EG(include_files), 如果存在则说明包含过了, 返回, 否则open这个文件, 从而得到这个文件的opened_path. 比如上面的例子, 这个文件存在于 “/tmp2/2.php”.

然后, 得到了这个opened_path以后, PHP去已加载的文件列表去查找, 是否已经包含, 如果没有包含, 那么就直接compile, 不再需要open file了.

1. 尝试解析文件的绝对路径, 如果能解析成功, 则检查EG(included_files), 存在则返回, 不存在继续
2. 打开文件, 得到文件的打开路径(opened path)
3. 拿opened path去EG(included_files)查找, 是否存在, 如果存在则返回, 不存在继续
4. 编译文件(compile_file)

这个在大多数情况下, 不是问题, 然而问题出在当你使用APC的时候…

在使用APC的时候, APC劫持了compile_file这个编译文件的指针, 从而直接从cache中得到编译结果, 避免了对实际文件的open, 避免了对open的system call.

然而, 当你在代码中使用include_once的时候, 在compile_file之前, PHP已经尝试去open file了, 然后才进入被APC劫持的compile file中, 这样一来, 就会产生一次额外的open操作. 而APC正是为了解决这个问题, 引入了include_once_override, 在include_once_override开启的情况下, APC会劫持PHP的ZEND_INCLUDE_OR_EVAL opcode handler, 通过stat来确定文件的绝对路径, 然后如果发现没有被加载, 就改写opcode为include, 做一个tricky解决方案.

但是, 很可惜, 如我所说, APC的include_once_override实现的一直不好, 会有一些未定义的问题, 比如:

<?php
set_include_path("/tmp");
function a($arg = array()) {
    include_once("b.php");
}
a();
a();
?>

然后, 我们的b.php放置在”/tmp/b.php”, 内容如下:
<?php
  class B {}
?>

那么在打开apc.include_once_override的情况下, 连续访问就会得到如下错误:

Fatal error - include() : Cannot redeclare class b

排除这些技术因素, 我也一直认为, 我们应该使用include, 而不是include_once, 因为我们完全能做到自己规划, 一个文件只被加载一次. 还可以借助自动加载, 来做到这一点.

你使用include_once, 只能证明, 你对自己的代码没信心.

所以, 建议大家, 不要再使用include_once

PHP 相关文章推荐
php adodb连接带密码access数据库实例,测试成功
May 14 PHP
PHP伪静态页面函数附使用方法
Jun 20 PHP
破解图片防盗链的代码(asp/php)测试通过
Jul 02 PHP
PHP学习之字符串比较和查找
Apr 17 PHP
解析php php_openssl.dll的作用
Jul 01 PHP
PHP输出缓存ob系列函数详解
Mar 11 PHP
浅谈PHP调用Webservice思路及源码分享
Jun 04 PHP
thinkphp使用literal防止模板标签被解析的方法
Nov 22 PHP
PHP实现的登录,注册及密码修改功能分析
Nov 25 PHP
利用phpexcel对数据库数据的导入excel(excel筛选)、导出excel
Apr 27 PHP
PHP多个图片压缩成ZIP的方法
Aug 18 PHP
Yii 框架使用Forms操作详解
May 18 PHP
探讨PHP调用时间格式的参数详解
Jun 06 #PHP
探讨多键值cookie(php中cookie存取数组)的详解
Jun 06 #PHP
深入密码加salt原理的分析
Jun 06 #PHP
深入理解PHP几个算法:PHP冒泡、PHP二分法、PHP求素数、PHP乘法表
Jun 06 #PHP
php定时计划任务的实现方法详解
Jun 06 #PHP
PHP使用DES进行加密与解密的方法详解
Jun 06 #PHP
php xml常用函数的集合(比较详细)
Jun 06 #PHP
You might like
PHP环境搭建最新方法
2006/09/05 PHP
JS代码放在head和body中的区别分析
2011/12/01 Javascript
jquery制作弹窗提示窗口代码分享
2014/03/02 Javascript
js使用DOM设置单选按钮、复选框及下拉菜单的方法
2015/01/20 Javascript
JQuery分屏指示器图片轮换效果实例
2015/05/21 Javascript
基于jQuery通过jQuery.form.js插件使用ajax提交form表单
2015/08/17 Javascript
jQuery+ajax实现实用的点赞插件代码
2016/07/06 Javascript
深入解析桶排序算法及Node.js上JavaScript的代码实现
2016/07/06 Javascript
AngularJS入门教程之AngularJS 模板
2016/08/18 Javascript
jquery实现图片平滑滚动详解
2017/03/22 jQuery
Linux CentOS系统下安装node.js与express的方法
2017/04/01 Javascript
Ext JS 实现建议词模糊动态搜索功能
2017/05/13 Javascript
基于vue.js中关于下拉框的值默认及绑定问题
2018/08/22 Javascript
js中int和string数据类型互相转化实例
2019/01/16 Javascript
Vue CLI3基础学习之pages构建多页应用
2019/06/02 Javascript
解决vuex刷新状态初始化的方法实现
2019/08/15 Javascript
详解elementui之el-image-viewer(图片查看器)
2019/08/30 Javascript
通过实例解析JavaScript常用排序算法
2020/09/02 Javascript
[01:30:55]VG vs Mineski Supermajor 败者组 BO3 第三场 6.6
2018/06/07 DOTA
[00:15]天涯墨客终极技能展示
2018/08/25 DOTA
Python实现读取文件最后n行的方法
2017/02/23 Python
浅谈python socket函数中,send与sendall的区别与使用方法
2017/05/09 Python
python用户管理系统的实例讲解
2017/12/23 Python
详解使用Python下载文件的几种方法
2019/10/13 Python
CSS实现雨滴动画效果的实例代码
2019/10/08 HTML / CSS
生物有机护肤品:Aurelia Probiotic Skincare
2018/01/31 全球购物
企业内部培训方案
2014/02/04 职场文书
会计求职信范文
2014/05/24 职场文书
爱护公共设施演讲稿
2014/09/13 职场文书
2015年国税春训心得体会
2015/03/09 职场文书
2015年安康杯竞赛活动总结
2015/03/26 职场文书
2015年煤矿安全工作总结
2015/05/23 职场文书
音乐剧猫观后感
2015/06/04 职场文书
致男子1500米运动员的广播稿
2019/11/08 职场文书
python中的3种定义类方法
2021/11/27 Python
MySQL控制流函数(-if ,elseif,else,case...when)
2022/07/07 MySQL