请离开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写出自己的BLOG系统 2
Apr 12 PHP
php采集时被封ip的解决方法
Aug 29 PHP
php类的定义与继承用法实例
Jul 07 PHP
PHP程序中使用adodb连接不同数据库的代码实例
Dec 19 PHP
WordPress开发中用于获取近期文章的PHP函数使用解析
Jan 05 PHP
PHP+MySql+jQuery实现的&quot;顶&quot;和&quot;踩&quot;投票功能
May 21 PHP
将PHP的session数据存储到数据库中的代码实例
Jun 24 PHP
php微信公众号开发(2)百度BAE搭建和数据库使用
Dec 15 PHP
解决出现SoapFault (looks like we got no XML document)的问题
Jun 24 PHP
Laravel中日期时间处理包Carbon的简单使用
Sep 21 PHP
Laravel下生成验证码的类
Nov 15 PHP
PHP执行linux命令6个函数代码实例
Nov 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
php输入数据统一类实例
2015/02/23 PHP
PHP IDE PHPStorm配置支持友好Laravel代码提示方法
2015/05/12 PHP
laravel migrate初学常见错误的解决方法
2017/10/11 PHP
JavaScript删除指定子元素代码实例
2015/01/13 Javascript
JavaScript使用push方法添加一个元素到数组末尾用法实例
2015/04/06 Javascript
JS动态插入并立即执行回调函数的方法
2016/04/21 Javascript
json与jsonp知识小结(推荐)
2016/08/16 Javascript
利用JS实现页面删除并重新排序功能
2016/12/09 Javascript
JavaScript轻松创建级联函数的方法示例
2017/02/10 Javascript
angularjs路由传值$routeParams详解
2020/09/05 Javascript
使用cookie绕过验证码登录的实现代码
2017/10/12 Javascript
vue与iframe之间的信息交互的实现
2020/04/08 Javascript
vue项目实现设置根据路由高亮对应的菜单项操作
2020/08/06 Javascript
vue实现下拉菜单树
2020/10/22 Javascript
全面解析Vue中的$nextTick
2020/12/24 Vue.js
python语言使用技巧分享
2016/05/31 Python
利用python生成一个导出数据库的bat脚本文件的方法
2016/12/30 Python
python 全局变量的import机制介绍
2017/09/07 Python
Python随机生成均匀分布在单位圆内的点代码示例
2017/11/13 Python
Python基于sklearn库的分类算法简单应用示例
2018/07/09 Python
APIStar:一个专为Python3设计的API框架
2018/09/26 Python
关于 Python opencv 使用中的 ValueError: too many values to unpack
2019/06/28 Python
python实现超级玛丽游戏
2020/03/18 Python
HTML5的革新 结构之美
2011/06/20 HTML / CSS
N:Philanthropy官网:美国洛杉矶基础款服装
2020/06/09 全球购物
护士自荐信
2013/10/25 职场文书
高级方案规划工程师岗位职责
2013/11/29 职场文书
大学社团活动总结
2014/04/26 职场文书
爱与责任师德演讲稿
2014/08/26 职场文书
党员自我剖析材料(群众路线)
2014/10/06 职场文书
廉政承诺书
2015/01/19 职场文书
辞职信标准格式
2015/02/27 职场文书
2015小学语文教师个人工作总结
2015/05/20 职场文书
2015年税务稽查工作总结
2015/05/26 职场文书
《自己去吧》教学反思
2016/02/16 职场文书
六年级语文教学反思
2016/03/03 职场文书