强烈声明: 不要使用(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编程最快明白》第七讲:php图片验证码与缩略图
Nov 01 PHP
php中在PDO中使用事务(Transaction)
May 14 PHP
php写的带缓存数据功能的mysqli类
Sep 06 PHP
php实现utf-8转unicode函数分享
Jan 06 PHP
php编写批量生成不重复的卡号密码代码
May 14 PHP
php实现paypal 授权登录
May 28 PHP
php中动态变量用法实例
Jun 10 PHP
php实现通过cookie换肤的方法
Jul 13 PHP
php使用Jpgraph创建3D饼形图效果示例
Feb 15 PHP
laravel手动创建数组分页的实现代码
Jun 07 PHP
PHP封装mysqli基于面向对象的mysql数据库操作类与用法示例
Feb 25 PHP
php实现JWT(json web token)鉴权实例详解
Nov 05 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获取mysql数据库中的所有表名的代码
2011/04/23 PHP
模板引擎正则表达式调试小技巧
2011/07/20 PHP
PHP在获取指定目录下的目录,在获取的目录下面再创建文件,多平台
2011/08/03 PHP
PHP生成RSS文件类实例
2014/12/05 PHP
php打包压缩文件之ZipArchive方法用法分析
2016/04/30 PHP
php数据访问之增删改查操作
2016/05/09 PHP
thinkPHP简单导入和使用阿里云OSSsdk的方法
2017/03/15 PHP
Laravel Validator 实现两个或多个字段联合索引唯一
2019/05/08 PHP
php 多继承的几种常见实现方法示例
2019/11/18 PHP
使一个函数作为另外一个函数的参数来运行的javascript代码
2007/08/13 Javascript
jQuery Ajax之load()方法
2009/10/12 Javascript
jquery选择器(常用选择器说明)
2010/09/28 Javascript
文本框获得焦点和失去焦点的判断代码
2012/03/18 Javascript
九种js弹出对话框的方法总结
2013/03/12 Javascript
JavaScript 学习笔记之语句
2015/01/14 Javascript
JavaScript动态数量的文件上传控件
2016/11/18 Javascript
angular双向绑定模拟探索
2016/12/26 Javascript
JavaScript变量作用域_动力节点Java学院整理
2017/06/27 Javascript
详解vue项目中调用百度地图API使用方法
2019/04/25 Javascript
webpack中如何加载静态文件的方法步骤
2019/05/18 Javascript
跟老齐学Python之有点简约的元组
2014/09/24 Python
PyTorch上实现卷积神经网络CNN的方法
2018/04/28 Python
Python3爬虫学习之爬虫利器Beautiful Soup用法分析
2018/12/12 Python
对Python之gzip文件读写的方法详解
2019/02/08 Python
详解Python3注释知识点
2019/02/19 Python
pytorch 预训练层的使用方法
2019/08/20 Python
详解Python+Selenium+ChromeDriver的配置和问题解决
2021/01/19 Python
英国时尚饰品和发饰购物网站:Claire’s
2017/07/04 全球购物
国家励志奖学金获奖感言
2014/01/09 职场文书
2014年小学植树节活动方案
2014/03/02 职场文书
食品流通安全承诺书
2014/05/22 职场文书
公共机构节能宣传周活动总结
2014/07/09 职场文书
物业接待员岗位职责
2015/04/15 职场文书
2015年安全生产月工作总结
2015/07/27 职场文书
三年级作文之趣事作文
2019/11/04 职场文书
对象析构函数__del__在Python中何时使用
2022/03/22 Python