强烈声明: 不要使用(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 相关文章推荐
怎样在UNIX系统下安装php3
Oct 09 PHP
PHP学习 变量使用总结
Mar 24 PHP
php的urlencode()URL编码函数浅析
Aug 09 PHP
php的chr和ord函数实现字符加减乘除运算实现代码
Dec 05 PHP
9条PHP编程小知识及易犯的小错误
Jan 22 PHP
PHP统计当前在线用户数实例讲解
Oct 21 PHP
joomla数据库操作示例代码
Jan 06 PHP
PHP的压缩函数实现:gzencode、gzdeflate和gzcompress的区别
Jan 27 PHP
使用JavaScript创建新样式表和新样式规则
Jun 14 PHP
使用Zttp简化Guzzle 调用
Jul 02 PHP
Laravel构建即时应用的一种实现方法详解
Aug 31 PHP
Thinkphp整合阿里云OSS图片上传实例代码
Apr 28 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安全编程之加密功能
2006/10/09 PHP
学习discuz php 引入文件的方法DISCUZ_ROOT
2009/06/21 PHP
PHP 上传文件的方法(类)
2009/07/30 PHP
php引用返回与取消引用的详解
2013/06/08 PHP
php使用mkdir创建多级目录入门例子
2014/05/10 PHP
thinkPHP订单数字提醒功能的实现方法
2016/12/01 PHP
来自国外的14个图片放大编辑的jQuery插件整理
2010/10/20 Javascript
javascript hashtable 修正版 下载
2010/12/30 Javascript
ExtJS自定义主题(theme)样式详解
2013/11/18 Javascript
javascript打印html内容功能的方法示例
2013/11/28 Javascript
jQuery的选择器中的通配符使用介绍
2014/03/20 Javascript
使用jquery animate创建平滑滚动效果(可以是到顶部、到底部或指定地方)
2014/05/27 Javascript
JS简单操作select和dropdownlist实例
2014/11/26 Javascript
JavaScript制作windows经典扫雷小游戏
2015/03/31 Javascript
Jquery+Ajax+PHP+MySQL实现分类列表管理(上)
2015/10/28 Javascript
仅9张思维导图帮你轻松学习Javascript 就这么简单
2016/06/01 Javascript
jQuery实现的自动加载页面功能示例
2016/09/04 Javascript
AngularJS封装$http.post()实例详解
2017/05/06 Javascript
vue打包后显示空白正确处理方法
2017/11/01 Javascript
taro小程序添加骨架屏的实现代码
2019/11/15 Javascript
js实现上传按钮并显示缩略图小轮子
2020/05/04 Javascript
在react-antd中弹出层form内容传递给父组件的操作
2020/10/24 Javascript
Element-ui 自带的两种远程搜索(模糊查询)用法讲解
2021/01/29 Javascript
Python遍历zip文件输出名称时出现乱码问题的解决方法
2015/04/08 Python
Python数据拟合与广义线性回归算法学习
2017/12/22 Python
Django中的Model操作表的实现
2018/07/24 Python
python爬虫 urllib模块反爬虫机制UA详解
2019/08/20 Python
Ratchet 模态框的实现
2020/08/19 HTML / CSS
Contém1g官网:巴西彩妆品牌
2020/01/17 全球购物
学习十八大精神心得体会
2013/12/31 职场文书
大学班长的职责
2014/01/27 职场文书
会展策划与管理专业求职信
2014/06/09 职场文书
2014年绿化工作总结
2014/12/09 职场文书
南湾猴岛导游词
2015/02/09 职场文书
大一新生军训新闻稿
2015/07/17 职场文书
python index() 与 rindex() 方法的使用示例详解
2022/12/24 Python