请离开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数组函数序列之rsort() - 对数组的元素值进行降序排序
Nov 02 PHP
php eval函数用法总结
Oct 31 PHP
ubuntu10.04配置 nginx+php-fpm模式的详解
Jun 03 PHP
php根据日期显示所在星座的方法
Jul 13 PHP
WordPress中注册菜单与调用菜单的方法详解
Dec 18 PHP
PHP中功能强大却很少使用的函数实例小结
Nov 10 PHP
PHP多维数组指定多字段排序的示例代码
May 16 PHP
Yii2.0建立公共方法简单示例
Jan 29 PHP
laravel使用Faker数据填充的实现方法
Apr 12 PHP
PHP使用Session实现上传进度功能详解
Aug 06 PHP
Laravel 集成微信用户登录和绑定的实现
Dec 27 PHP
php的instanceof和判断闭包Closure操作示例
Jan 26 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
dedecms后台验证码总提示错误的解决方法
2007/03/21 PHP
php面向对象 字段的声明与使用
2012/06/14 PHP
php删除文本文件中重复行的方法
2015/04/28 PHP
自制PHP框架之设计模式
2017/05/07 PHP
PHP结合Vue实现滚动底部加载效果
2017/12/17 PHP
javascript实现的像java、c#之类的sleep暂停的函数代码
2010/03/04 Javascript
js+css在交互上的应用
2010/07/18 Javascript
extjs中grid中嵌入动态combobox的应用
2011/01/01 Javascript
jquery easyui滚动条部分设置介绍
2013/09/12 Javascript
使用javascript实现json数据以csv格式下载
2015/01/09 Javascript
JavaScript使用concat连接数组的方法
2015/04/06 Javascript
AngularJS中$interval的用法详解
2016/02/02 Javascript
JS控制伪元素的方法汇总
2016/04/06 Javascript
Jquery给当前页或者跳转后页面的导航栏添加选中后样式的实例
2016/12/08 Javascript
浅谈JavaScript的闭包函数
2016/12/08 Javascript
ES6中参数的默认值语法介绍
2017/05/03 Javascript
详解如何将 Vue-cli 改造成支持多页面的 history 模式
2017/11/20 Javascript
angular2中使用第三方js库的实例
2018/02/26 Javascript
JavaScript中window和document用法详解
2020/07/28 Javascript
[04:11]2014DOTA2国际邀请赛 CIS遗憾出局梦想不灭
2014/07/09 DOTA
[01:31:03]DOTA2完美盛典全回顾 见证十五项大奖花落谁家
2017/11/28 DOTA
Python获取暗黑破坏神3战网前1000命位玩家的英雄技能统计
2016/07/04 Python
使用Python进行二进制文件读写的简单方法(推荐)
2016/09/12 Python
python实现微信跳一跳辅助工具步骤详解
2018/01/04 Python
python+django+sql学生信息管理后台开发
2018/01/11 Python
python如何重载模块实例解析
2018/01/25 Python
Python3数字求和的实例
2019/02/19 Python
python计算Content-MD5并获取文件的Content-MD5值方式
2020/04/03 Python
tensorflow实现残差网络方式(mnist数据集)
2020/05/26 Python
Lookfantastic俄罗斯:欧洲在线化妆品零售商
2019/08/06 全球购物
美国艺术和工艺品商店:Hobby Lobby
2020/12/09 全球购物
美国购买韩国护肤和美容产品网站:Althea Korea
2020/11/16 全球购物
颇特女士香港官网:NET-A-PORTER香港
2021/03/08 全球购物
IT工程师岗位职责
2014/07/04 职场文书
电影开国大典观后感
2015/06/04 职场文书
MySQL 如何限制一张表的记录数
2021/09/14 MySQL