强烈声明: 不要使用(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用数组返回无限分类的列表数据的代码
Aug 08 PHP
PHP类与对象中的private访问控制的疑问
Nov 01 PHP
10个超级有用值得收藏的PHP代码片段
Jan 22 PHP
PHP中is_dir()函数使用指南
May 08 PHP
四个常见html网页乱码问题及解决办法
Sep 08 PHP
php如何控制用户对图片的访问 PHP禁止图片盗链
Mar 25 PHP
java微信开发之上传下载多媒体文件
Jun 24 PHP
PHP获取当前URL路径的处理方法(适用于多条件筛选列表)
Feb 10 PHP
Yii2下点击验证码的切换实例代码
Mar 14 PHP
Laravel5.4框架使用socialite实现github登录的方法
Mar 20 PHP
php输出反斜杠的实例方法
Sep 19 PHP
确保Laravel网站不会被嵌入到其他站点中的方法
Oct 18 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
TP5框架请求响应参数实例分析
2019/10/17 PHP
jquery的ajax请求全面了解
2013/03/20 Javascript
javascript实现可改变滚动方向的无缝滚动实例
2013/06/17 Javascript
JavaScript实现按Ctrl键打开新页面
2014/09/04 Javascript
javascript正则表达式之search()用法实例
2015/01/19 Javascript
JS实现屏蔽shift,Ctrl,alt等功能键的方法
2015/06/01 Javascript
Jquery实现$.fn.extend和$.extend函数
2016/04/14 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
2016/04/28 Javascript
Jquery和Js获得元素标签名称的方法总结
2016/10/08 Javascript
jquery实现异步加载图片(懒加载图片一种方式)
2017/04/24 jQuery
angular中ui calendar的一些使用心得(推荐)
2017/11/03 Javascript
vue2.0 自定义 饼状图 (Echarts)组件的方法
2018/03/02 Javascript
jQuery 实现批量提交表格多行数据的方法
2018/08/09 jQuery
JavaScript对象的特性与实践应用深入详解
2018/12/30 Javascript
在Create React App中使用CSS Modules的方法示例
2019/01/15 Javascript
详解JS浏览器事件循环机制
2019/03/27 Javascript
详解React的回调渲染模式
2020/09/10 Javascript
Angular处理未可知异常错误的方法详解
2021/01/17 Javascript
win7安装python生成随机数代码分享
2013/12/27 Python
python执行等待程序直到第二天零点的方法
2015/04/23 Python
总结Python中逻辑运算符的使用
2015/05/13 Python
Python使用sorted排序的方法小结
2017/07/28 Python
python对list中的每个元素进行某种操作的方法
2018/06/29 Python
对Pandas DataFrame缺失值的查找与填充示例讲解
2018/11/06 Python
python读取csv和txt数据转换成向量的实例
2019/02/12 Python
利用Storage Event实现页面间通信的示例代码
2018/07/26 HTML / CSS
prAna官网:瑜伽、旅行和冒险服装
2019/03/10 全球购物
三星加拿大官方网上商店:Samsung CA
2020/12/18 全球购物
数学专业推荐信范文
2013/11/21 职场文书
语文教学随笔感言
2014/02/18 职场文书
2014年重阳节老干部座谈会局领导发言稿
2014/09/25 职场文书
公安机关党的群众路线教育实践活动剖析材料
2014/10/10 职场文书
乡镇科协工作总结2015
2015/05/19 职场文书
Python办公自动化之教你用Python批量识别发票并录入到Excel表格中
2021/06/26 Python
四十九个javascript小知识实用技巧
2021/11/20 Javascript
Python实现照片卡通化
2021/12/06 Python