请离开include_once和require_once


Posted in PHP onJuly 18, 2013

诚然, 这个理由是对的, 不过, 我今天要说的, 是另外一个的原因.
我们知道, 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

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

你使用include_once,只能证明, 你对自己的代码没信心.
所以, 建议大家, 不要再使用include_once

PHP 相关文章推荐
php set_magic_quotes_runtime() 函数过时解决方法
Jul 08 PHP
PHP中CURL方法curl_setopt()函数的参数分享
Jan 19 PHP
解析PHP工厂模式的好处
Jun 18 PHP
php用正则表达式匹配URL的简单方法
Nov 12 PHP
PHPAnalysis中文分词类详解
Jun 13 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十二)
Jun 25 PHP
PHP遍历XML文档所有节点的方法
Mar 12 PHP
php实现根据IP地址获取其所在省市的方法
Apr 30 PHP
php中smarty变量修饰用法实例分析
Jun 11 PHP
PHP中的命名空间详细介绍
Jul 02 PHP
深入理解PHP中mt_rand()随机数的安全
Oct 12 PHP
在laravel中实现ORM模型使用第二个数据库设置
Oct 24 PHP
解析PHP中的unset究竟会不会释放内存
Jul 18 #PHP
解析php中curl_multi的应用
Jul 17 #PHP
php curl获取网页内容(IPV6下超时)的解决办法
Jul 16 #PHP
ie与session丢失(新窗口cookie丢失)实测及解决方案
Jul 15 #PHP
实测在class的function中include的文件中非php的global全局环境
Jul 15 #PHP
Php output buffering缓存及程序缓存深入解析
Jul 15 #PHP
PHP 转义使用详解
Jul 15 #PHP
You might like
2020最新CPU的性能排名
2020/04/02 数码科技
php判断文件夹是否存在不存在则创建
2015/04/09 PHP
YII2 实现多语言配置的方法分享
2017/01/11 PHP
JSON PHP中,Json字符串反序列化成对象/数组的方法
2018/05/31 PHP
json原理分析及实例介绍
2012/11/29 Javascript
Javascript 颜色渐变效果的实现代码
2013/10/01 Javascript
JQuery记住用户名密码实现下次自动登录功能
2015/04/27 Javascript
JavaScript实现添加及删除事件的方法小结
2015/08/04 Javascript
基于JavaScript实现通用tab选项卡(通用性强)
2016/01/07 Javascript
浅谈js之字面量、对象字面量的访问、关键字in的用法
2016/11/20 Javascript
浅谈jquery的html方法里包含特殊字符的处理
2016/11/30 Javascript
JavaScript之promise_动力节点Java学院整理
2017/07/03 Javascript
vue.js2.0点击获取自己的属性和jquery方法
2018/02/23 jQuery
js中!和!!的区别与用法
2020/05/09 Javascript
vue 页面回退mounted函数不执行的解决方案
2020/07/26 Javascript
el-form 多层级表单的实现示例
2020/09/10 Javascript
wxPython定时器wx.Timer简单应用实例
2015/06/03 Python
Python 正则表达式入门(中级篇)
2016/12/07 Python
Python遍历pandas数据方法总结
2018/02/09 Python
python3实现名片管理系统
2020/11/29 Python
详解numpy的argmax的具体使用
2019/05/27 Python
Python3+PyInstall+Sciter解决报错缺少dll、html等文件问题
2019/07/15 Python
线程安全及Python中的GIL原理分析
2019/10/29 Python
Python如何实现爬取B站视频
2020/05/20 Python
美国最大的在线生存商店:Survival Frog
2020/12/13 全球购物
个人党性剖析材料
2014/02/03 职场文书
员工晚婚的请假条
2014/02/08 职场文书
行政助理的岗位职责
2014/02/18 职场文书
《秋姑娘的信》教学反思
2014/02/28 职场文书
村抢险救灾方案
2014/05/09 职场文书
护士实习求职信
2014/06/22 职场文书
个人四风问题原因分析及整改措施
2014/09/28 职场文书
领导班子整改方案和个人整改措施
2014/10/25 职场文书
亮剑精神观后感
2015/06/05 职场文书
演讲稿之我的初心我的成长
2019/08/12 职场文书
小学生六年级作文之关于感恩
2019/08/16 职场文书