强烈声明: 不要使用(include/require)_once


Posted in PHP onJune 06, 2013

关于使用include还是include_once(以下,都包含require_once), 这个讨论很长了, 结论也一直有, 就是尽量使用include, 而不是include_once, 以前最多的理由的是, include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载.

诚然, 这个理由是对的, 不过, 我今天要说的, 是另外一个的原因.

我们知道, 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 b

排除这些技术因素, 我也一直认为, 我们应该使用include, 而不是include_once, 因为我们完全能做到自己规划, 一个文件只被加载一次. 还可以借助自动加载, 来做到这一点.

你使用include_once, 只能证明, 你对自己的代码没信心.

所以, 建议大家, 不要再使用include_once

PHP 相关文章推荐
php中记录用户访问过的产品,在cookie记录产品id,id取得产品信息
May 04 PHP
调整优化您的LAMP应用程序的5种简单方法
Jun 26 PHP
php数组函数序列之array_slice() - 在数组中根据条件取出一段值,并返回
Nov 07 PHP
PHP error_log()将错误信息写入一个文件(定义和用法)
Oct 25 PHP
php异常处理使用示例
Feb 25 PHP
php计算程序运行时间的简单例子分享
May 10 PHP
PHP常用技术文之文件操作和目录操作总结
Sep 27 PHP
php文件扩展名判断及获取文件扩展名的N种方法
Sep 12 PHP
php foreach如何跳出两层循环(详解)
Nov 05 PHP
ThinkPHP 整合Bootstrap Ajax分页样式
Dec 23 PHP
Linux下源码包安装Swoole及基本使用操作图文详解
Apr 02 PHP
PHP时间类完整代码实例
Feb 26 PHP
探讨PHP调用时间格式的参数详解
Jun 06 #PHP
探讨多键值cookie(php中cookie存取数组)的详解
Jun 06 #PHP
深入密码加salt原理的分析
Jun 06 #PHP
深入理解PHP几个算法:PHP冒泡、PHP二分法、PHP求素数、PHP乘法表
Jun 06 #PHP
php定时计划任务的实现方法详解
Jun 06 #PHP
PHP使用DES进行加密与解密的方法详解
Jun 06 #PHP
php xml常用函数的集合(比较详细)
Jun 06 #PHP
You might like
浅析PHP中的字符串编码转换(自动识别原编码)
2013/07/02 PHP
帝国CMS留言板回复后发送EMAIL通知客户
2015/07/06 PHP
简单实现php上传文件功能
2017/09/21 PHP
php操作mongodb封装类与用法实例
2018/09/01 PHP
javascript显示隐藏层比较不错的方法分析
2008/09/30 Javascript
DIV菜单层实现代码
2010/11/19 Javascript
基于Jquery的表格隔行换色,移动换色,点击换色插件
2010/12/22 Javascript
jquery 跨域访问问题解决方法(笔记)
2011/06/08 Javascript
JS实现简单的Canvas画图实例
2013/07/04 Javascript
js控制iframe的高度/宽度让其自适应内容
2014/04/09 Javascript
javascript鼠标滑动评分控件完整实例
2015/05/13 Javascript
jQuery实现表单步骤流程导航代码分享
2015/08/28 Javascript
基于jquery实现图片上传本地预览功能
2016/01/08 Javascript
javascript实现根据函数名称字符串动态执行函数的方法示例
2016/12/28 Javascript
用move.js库实现百叶窗特效
2017/02/08 Javascript
Vue.js:使用Vue-Router 2实现路由功能介绍
2017/02/22 Javascript
用jQuery实现圆点图片轮播效果
2017/03/19 Javascript
利用C/C++编写node.js原生模块的方法教程
2017/07/07 Javascript
Three.js入门之hello world以及如何绘制线
2017/09/25 Javascript
解决axios发送post请求返回400状态码的问题
2018/08/11 Javascript
JS实现点击下拉列表文本框中出现对应的网址,点击跳转按钮实现跳转
2019/11/25 Javascript
vue中上传视频或图片或图片和文字一起到后端的解决方法
2019/12/01 Javascript
Python数据类型学习笔记
2016/01/13 Python
Python 使用SMTP发送邮件的代码小结
2016/09/21 Python
Python中标准模块importlib详解
2017/04/16 Python
几个适合python初学者的简单小程序,看完受益匪浅!(推荐)
2019/04/16 Python
python使用pandas处理大数据节省内存技巧(推荐)
2019/05/05 Python
html5新特性与用法大全
2018/09/13 HTML / CSS
农田水利实习自我鉴定
2013/09/19 职场文书
婚纱摄影师求职信范文
2014/04/17 职场文书
2014年校务公开工作总结
2014/12/18 职场文书
违反纪律检讨书范文
2015/05/07 职场文书
运动会闭幕式通讯稿
2015/07/18 职场文书
超市啤酒狂欢夜策划方案范文!
2019/07/03 职场文书
python 遍历磁盘目录的三种方法
2021/04/02 Python
用python自动生成日历
2021/04/24 Python