请离开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 相关文章推荐
批量获取memcache值并按key的顺序返回的实现代码
Jun 14 PHP
php中取得文件的后缀名?
Feb 20 PHP
三个类概括PHP的五种设计模式
Sep 05 PHP
说说PHP的autoLoad自动加载机制
Sep 27 PHP
PHP批量检测并去除文件BOM头代码实例
May 08 PHP
PHP数组与对象之间使用递归实现转换的方法
Jun 24 PHP
CodeIgniter配置之database.php用法实例分析
Jan 20 PHP
PHP中静态变量的使用方法实例分析
Dec 01 PHP
php基于dom实现读取图书xml格式数据的方法
Feb 03 PHP
php中Ioc(控制反转)和Di(依赖注入)
May 07 PHP
PHP实现合并两个排序链表的方法
Jan 19 PHP
php查看一个变量的占用内存的实例代码
Mar 29 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
2.PHP入门
2006/10/09 PHP
php根据操作系统转换文件名大小写的方法
2014/02/24 PHP
php中Session的生成机制、回收机制和存储机制探究
2014/08/19 PHP
php实现背景图上添加圆形logo图标的方法
2016/11/17 PHP
PHP给源代码加密的几种方法汇总(推荐)
2018/02/06 PHP
PHP7中I/O模型内核剖析详解
2019/04/14 PHP
jQuery获取Radio,CheckBox选择的Value值(示例代码)
2013/12/12 Javascript
node.js中的buffer.Buffer.isBuffer方法使用说明
2014/12/14 Javascript
jquery.qtip提示信息插件用法简单实例
2016/06/17 Javascript
js动态添加的DIV中的onclick事件简单实例
2016/07/25 Javascript
javascript设计模式之中介者模式学习笔记
2017/02/15 Javascript
深入浅析Vue全局组件与局部组件的区别
2018/06/15 Javascript
基于Angularjs-router动态改变Title值的问题
2018/08/30 Javascript
Javascript通过控制类名更改样式
2019/05/24 Javascript
用JS实现选项卡
2020/03/23 Javascript
jQuery 实现DOM元素拖拽交换位置的实例代码
2020/07/14 jQuery
python远程登录代码
2008/04/29 Python
python进阶教程之词典、字典、dict
2014/08/29 Python
酷! 程序员用Python带你玩转冲顶大会
2018/01/17 Python
使用Python画股票的K线图的方法步骤
2019/06/28 Python
Pycharm 安装 idea VIM插件的图文教程详解
2020/02/21 Python
Python编程快速上手——正则表达式查找功能案例分析
2020/02/28 Python
Python中求对数方法总结
2020/03/10 Python
python实现爱奇艺登陆密码RSA加密的方法示例详解
2020/05/27 Python
详解pycharm2020.1.1专业版安装指南(推荐)
2020/08/07 Python
Python使用tkinter实现小时钟效果
2021/02/22 Python
Daisy London官网:英国最大的首饰集团IBB旗下
2019/02/28 全球购物
写给老师的表扬信
2014/01/21 职场文书
党员承诺书格式
2014/05/21 职场文书
春游踏青活动方案
2014/08/14 职场文书
主持人开幕词
2015/01/29 职场文书
离婚财产分割协议书
2015/08/11 职场文书
幼儿园音乐教学反思
2016/02/18 职场文书
导游词之镇江-金山寺
2019/10/14 职场文书
导游词之宿迁乾隆行宫
2019/10/15 职场文书
Go缓冲channel和非缓冲channel的区别说明
2021/04/25 Golang