请离开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程序员的技术瓶颈分析
Jul 17 PHP
PHPThumb PHP 图片缩略图库
Mar 11 PHP
php写的带缓存数据功能的mysqli类
Sep 06 PHP
PHP cdata 处理(详细介绍)
Jul 05 PHP
php导出word文档与excel电子表格的简单示例代码
Mar 08 PHP
两千行代码的PHP学习笔记汇总
Oct 05 PHP
微信公众平台开发关注及取消关注事件的方法
Dec 23 PHP
PHP实现支持SSL连接的SMTP邮件发送类
Mar 05 PHP
CI分页类首页、尾页不显示的解决方法
Mar 28 PHP
PHP简单读取PDF页数的实现方法
Jul 21 PHP
Yii 2.0在Grid中格式化时间方法示例
Jun 06 PHP
Yii2框架操作数据库的方法分析【以mysql为例】
May 27 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分多步骤填写发布信息的简单方法实例代码
2012/09/23 PHP
php封装json通信接口详解及实例
2017/03/07 PHP
详解PHP中的外观模式facade pattern
2018/02/05 PHP
解密效果
2006/06/23 Javascript
你必须知道的Javascript知识点之&quot;单线程事件驱动&quot;的使用
2013/04/23 Javascript
纯css实现窗户玻璃雨滴逼真效果
2015/08/23 Javascript
jQuery实现遮罩层登录对话框
2016/12/29 Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
2017/02/18 Javascript
JsChart组件使用详解
2018/03/04 Javascript
vue中子组件的methods中获取到props中的值方法
2018/08/27 Javascript
JavaScript使用indexOf()实现数组去重的方法分析
2018/09/04 Javascript
详解Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
2018/10/12 Javascript
详解vue中多个有顺序要求的异步操作处理
2019/10/29 Javascript
javscript 数组扁平化的实现
2020/02/03 Javascript
vue npm install 安装某个指定的版本操作
2020/08/11 Javascript
[04:02]DOTA2上海特锦赛小组赛第二日recap精彩回顾
2016/02/28 DOTA
[10:21]2018DOTA2国际邀请赛寻真——Winstrike
2018/08/11 DOTA
python生成指定尺寸缩略图的示例
2014/05/07 Python
Python实现发送email的几种常用方法
2014/08/18 Python
Python 3.x 新特性及10大变化
2015/06/12 Python
基于python中pygame模块的Linux下安装过程(详解)
2017/11/09 Python
对TensorFlow的assign赋值用法详解
2018/07/30 Python
详解python Todo清单实战
2018/11/01 Python
详解python中的hashlib模块的使用
2019/04/22 Python
python 5个顶级异步框架推荐
2020/09/09 Python
CSS3基础(RGBa、text-shadow、box-shadow、border-radius)
2012/11/13 HTML / CSS
CSS3制作苹果风格键盘特效
2015/02/26 HTML / CSS
Mybag美国/加拿大:英国奢华包包和名牌手袋网站
2020/02/16 全球购物
歌唱比赛主持词
2014/03/18 职场文书
毕业生实习期转正自我鉴定
2014/09/26 职场文书
免职证明样本
2014/10/23 职场文书
个人借款协议书范本
2014/11/17 职场文书
婚内分居协议书范文
2014/11/26 职场文书
辞职离别感言
2015/08/04 职场文书
大学学生会主席竞选稿怎么写?
2019/08/19 职场文书
Python Pandas数据分析之iloc和loc的用法详解
2021/11/11 Python