请离开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代码的53条建议
Mar 27 PHP
php,ajax实现分页
Mar 27 PHP
php 中英文语言转换类代码
Aug 11 PHP
基于php设计模式中单例模式的应用分析
May 15 PHP
PHP检测字符串是否为UTF8编码的常用方法
Nov 21 PHP
非常实用的PHP常用函数汇总
Dec 17 PHP
求帮忙修改个php curl模拟post请求内容后并下载文件的解决思路
Sep 20 PHP
twig模板获取全局变量的方法
Feb 05 PHP
php cli模式下获取参数的方法
May 05 PHP
php从数据库中读取特定的行(实例)
Jun 02 PHP
PHP实现求解最长公共子串问题的方法
Nov 17 PHP
PHP使用ActiveMQ实现消息队列的方法详解
May 31 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
getJSON跨域SyntaxError问题分析
2014/08/07 PHP
PHP 正则表达式常用函数
2014/08/17 PHP
mac环境中使用brew安装php5.5.15
2014/08/18 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
javascript 关于# 和 void的区别分析
2009/10/26 Javascript
导入extjs、jquery 文件时$使用冲突问题解决方法
2014/01/14 Javascript
javascript实现输出指定行数正方形图案的方法
2015/08/03 Javascript
Bootstrap每天必学之折叠
2016/04/12 Javascript
javascript实现去除HTML标签的方法
2016/12/26 Javascript
获取当前月(季度/年)的最后一天(set相关操作及应用)
2016/12/27 Javascript
bootstrap daterangepicker双日历时间段选择控件详解
2017/06/15 Javascript
浅谈VUE监听窗口变化事件的问题
2018/02/24 Javascript
Vue分页效果与购物车功能
2019/12/13 Javascript
Vue 事件的$event参数=事件的值案例
2021/01/29 Vue.js
[33:23]VG vs Pain 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
[01:20:47]DOTA2-DPC中国联赛 正赛 Ehome vs Magma BO3 第一场 1月19日
2021/03/11 DOTA
Python使用PyGreSQL操作PostgreSQL数据库教程
2014/07/30 Python
使用python3.5仿微软记事本notepad
2016/06/15 Python
Python中执行存储过程及获取存储过程返回值的方法
2017/10/07 Python
python实现图书管理系统
2018/03/12 Python
Python文件循环写入行时防止覆盖的解决方法
2018/11/09 Python
基于Python计算圆周率pi代码实例
2020/03/25 Python
Python Tornado核心及相关原理详解
2020/06/24 Python
PyCharm 2020.2 安装详细教程
2020/09/25 Python
Sentry错误日志监控使用方法解析
2020/11/12 Python
css3实现3D色子翻转特效
2014/12/23 HTML / CSS
详解CSS3中nth-child与nth-of-type的区别
2017/01/05 HTML / CSS
HTML5中FileReader接口使用方法实例详解
2017/08/26 HTML / CSS
日本一家专门经营各种箱包的大型网站:Traveler Store
2016/08/03 全球购物
怎样拟定创业计划书
2014/05/01 职场文书
质量保证书怎么写
2015/02/27 职场文书
校长师德表现自我评价
2015/03/04 职场文书
花木兰观后感
2015/06/10 职场文书
2016年会领导致辞稿
2015/07/29 职场文书
python字典的元素访问实例详解
2021/07/21 Python
Python OpenCV之常用滤波器使用详解
2022/04/07 Python