请离开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版(3)
Oct 09 PHP
php adodb连接不同数据库
Mar 19 PHP
php中将图片gif,jpg或mysql longblob或blob字段值转换成16进制字符串
Aug 23 PHP
JSON在PHP中的应用介绍
Sep 08 PHP
php数组转换js数组操作及json_encode的用法详解
Oct 26 PHP
php判断正常访问和外部访问的示例
Feb 10 PHP
PHP实现算式验证码和汉字验证码实例
Mar 09 PHP
标准PHP的AES加密算法类
Mar 12 PHP
php生成酷炫的四个字符验证码
Apr 22 PHP
PHP实现原生态图片上传封装类方法
Nov 08 PHP
ThinkPHP实现转换数据库查询结果数据到对应类型的方法
Nov 16 PHP
php-app开发接口加密详解
Apr 18 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
完美实现GIF动画缩略图的php代码
2011/01/02 PHP
PHP使用GETDATE获取当前日期时间作为一个关联数组的方法
2015/03/19 PHP
PHP中让json_encode不自动转义斜杠“/”的方法
2017/02/28 PHP
PHP批量删除jQuery操作
2017/07/23 PHP
thinkphp框架表单数组实现图片批量上传功能示例
2020/04/04 PHP
ASP.NET jQuery 实例14 在ASP.NET form中校验时间范围
2012/02/03 Javascript
js模仿jquery的写法示例代码
2013/06/16 Javascript
打造个性化的功能强大的Jquery虚拟键盘(VirtualKeyboard)
2014/10/11 Javascript
JavaScript中诡异的delete操作符
2015/03/12 Javascript
JS实现漂亮的淡蓝色滑动门效果代码
2015/09/23 Javascript
js判断PC端与移动端跳转
2020/12/24 Javascript
微信小程序实现皮肤功能(夜间模式)
2017/06/18 Javascript
使用jQuery 操作table 完成单元格合并的实例
2017/12/27 jQuery
Vuejs 2.0 子组件访问/调用父组件的方法(示例代码)
2018/02/08 Javascript
Vue-cli项目获取本地json文件数据的实例
2018/03/07 Javascript
JavaScript 扩展运算符用法实例小结【基于ES6】
2019/06/17 Javascript
vant实现购物车功能
2020/06/29 Javascript
js实现拖拽与碰撞检测
2020/09/18 Javascript
[02:43]中国五虎出征TI3视频
2013/08/02 DOTA
Python中super的用法实例
2015/05/28 Python
Python编写电话薄实现增删改查功能
2016/05/07 Python
django-allauth入门学习和使用详解
2019/07/03 Python
python基于FTP实现文件传输相关功能代码实例
2019/09/28 Python
使用keras实现BiLSTM+CNN+CRF文字标记NER
2020/06/29 Python
在keras中对单一输入图像进行预测并返回预测结果操作
2020/07/09 Python
bonprix荷兰网上商店:便宜的服装、鞋子和家居用品
2020/07/04 全球购物
高中生家长会演讲稿
2014/01/14 职场文书
宣传策划类求职信范文
2014/01/31 职场文书
金融事务专业求职信
2014/04/25 职场文书
企业安全生产标语
2014/06/06 职场文书
党员个人党性分析材料
2014/12/18 职场文书
2015毕业设计工作总结
2015/07/24 职场文书
三八红旗手主要事迹材料
2015/11/04 职场文书
2016年教师党员公开承诺书
2016/03/24 职场文书
Go语言设计模式之结构型模式
2021/06/22 Golang
spring注解 @PropertySource配置数据源全流程
2022/03/25 Java/Android