请离开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 相关文章推荐
ajax php 实现写入数据库
Sep 02 PHP
smarty巧妙处理iframe中内容页的代码
Mar 07 PHP
PHP APC的安装与使用详解
Jun 13 PHP
JSON用法之将PHP数组转JS数组,JS如何接收PHP数组
Oct 08 PHP
PHP实现发送邮件的方法(基于简单邮件发送类)
Dec 17 PHP
php获取远程图片并下载保存到本地的方法分析
Oct 08 PHP
php加密之discuz内容经典加密方式实例详解
Feb 04 PHP
ThinkPHP3.2框架使用addAll()批量插入数据的方法
Mar 16 PHP
PHP函数积累总结
Mar 19 PHP
PHP+redis实现的限制抢购防止商品超发功能详解
Sep 19 PHP
使用PHP+Redis实现延迟任务,实现自动取消订单功能
Nov 21 PHP
one.php 多项目、函数库、类库 统一为一个版本的方法
Aug 24 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格式输出文件var_export函数实例
2014/11/15 PHP
PHP最常用的正则表达式
2017/02/13 PHP
php7函数,声明,返回值等新特性介绍
2018/05/25 PHP
PHP实现的解汉诺塔问题算法示例
2018/08/06 PHP
PHP面向对象程序设计之多态性的应用示例
2018/12/19 PHP
PHP封装的数据库模型Model类完整示例【基于PDO】
2019/03/14 PHP
jQuery 前的按键判断代码
2010/03/19 Javascript
一个简单的js树形菜单
2011/12/09 Javascript
JS操作JSON要领详细总结
2013/08/25 Javascript
javascript禁用键盘功能键让右击及其他键无效
2013/10/09 Javascript
jQuery中的jQuery()方法用法分析
2014/12/27 Javascript
javascript+css3 实现动态按钮菜单特效
2016/02/06 Javascript
微信小程序授权登录及解密unionId出错的方法
2018/09/26 Javascript
详解Angular Forms中自定义ngModel绑定值的方式
2018/12/10 Javascript
Vuepress 搭建带评论功能的静态博客的实现
2019/02/17 Javascript
vue模块拖拽实现示例代码
2019/03/09 Javascript
Python实现的一个自动售饮料程序代码分享
2014/08/25 Python
跟老齐学Python之数据类型总结
2014/09/24 Python
Python入门之三角函数atan2()函数详解
2017/11/08 Python
Python进阶之尾递归的用法实例
2018/01/31 Python
python+influxdb+shell编写区域网络状况表
2018/07/27 Python
python在html中插入简单的代码并加上时间戳的方法
2018/10/16 Python
Pytorch实现GoogLeNet的方法
2019/08/18 Python
python元组的概念知识点
2019/11/19 Python
Python Numpy中数据的常用保存与读取方法
2020/04/01 Python
关于python 的legend图例,参数使用说明
2020/04/17 Python
为2021年的第一场雪锦上添花:用matplotlib绘制雪花和雪景
2021/01/05 Python
纽约通行卡:The New York Pass(免费游览纽约90多个景点)
2017/07/29 全球购物
公司业务员岗位职责
2014/03/18 职场文书
班子四风对照检查材料
2014/08/21 职场文书
学雷锋主题班会教案
2015/08/13 职场文书
《自己去吧》教学反思
2016/02/16 职场文书
Python基础详解之描述符
2021/04/28 Python
分布式架构Redis中有哪些数据结构及底层实现原理
2022/03/13 Redis
详细介绍python操作RabbitMq
2022/04/12 Python
Elasticsearch Recovery 详细介绍
2022/04/19 Java/Android