强烈声明: 不要使用(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 相关文章推荐
一个可以删除字符串中HTML标记的PHP函数
Oct 09 PHP
php部分常见问题总结
Mar 27 PHP
在字符串指定位置插入一段字符串的php代码
Feb 16 PHP
php查看请求头信息获取远程图片大小的方法分享
Dec 25 PHP
一个图片地址分解程序(用于PHP小偷程序)
Aug 23 PHP
PHP图像处理之imagecreate、imagedestroy函数介绍
Nov 19 PHP
php生成4位数字验证码的实现代码
Nov 23 PHP
PHP上传文件参考配置大文件上传
Dec 16 PHP
php array_pop 删除数组最后一个元素实例
Nov 02 PHP
PHP搭建大文件切割分块上传功能示例
Jan 04 PHP
PHP在linux上执行外部命令的方法
Feb 06 PHP
Laravel网站打开速度优化的方法汇总
Jul 16 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简单获取目录列表的方法
2015/03/24 PHP
浅谈PHP中的
2016/04/23 PHP
Yii配置与使用memcached缓存的方法
2016/07/13 PHP
js实现的网页颜色代码表全集
2007/07/17 Javascript
10款新鲜出炉的 jQuery 插件(Ajax 插件,有幻灯片、图片画廊、菜单等)
2011/06/08 Javascript
左右悬浮可分组的网站QQ在线客服代码(可谓经典)
2012/12/21 Javascript
jquery实现邮箱自动补全功能示例分享
2014/02/17 Javascript
JQuery动画与特效实例分析
2015/02/02 Javascript
JS利用正则表达式实现简单的密码强弱判断实例
2017/06/16 Javascript
js学习心得_一个简单的动画库封装tween.js
2017/07/14 Javascript
vue-router路由与页面间导航实例解析
2017/11/07 Javascript
webpack之引入图片的实现及问题
2018/10/08 Javascript
详解Vue 全局变量,局部变量
2019/04/17 Javascript
Nodejs使用archiver-zip-encrypted库加密压缩文件时报错(解决方案)
2019/11/18 NodeJs
使用Element的InfiniteScroll 无限滚动组件报错的解决
2020/07/27 Javascript
js 数据类型判断的方法
2020/12/03 Javascript
python使用正则搜索字符串或文件中的浮点数代码实例
2014/07/11 Python
Python爬虫模拟登录带验证码网站
2016/01/22 Python
python将ansible配置转为json格式实例代码
2017/05/15 Python
django 按时间范围查询数据库实例代码
2018/02/11 Python
详解Python3.6安装psutil模块和功能简介
2018/05/30 Python
Python基于sklearn库的分类算法简单应用示例
2018/07/09 Python
Python使用paramiko操作linux的方法讲解
2019/02/25 Python
python 实现在一张图中绘制一个小的子图方法
2019/07/07 Python
Pandas实现dataframe和np.array的相互转换
2019/11/30 Python
python如何把字符串类型list转换成list
2020/02/18 Python
完美解决Django2.0中models下的ForeignKey()问题
2020/05/19 Python
一款纯css3实现的颜色渐变按钮的代码教程
2014/11/12 HTML / CSS
html5 的a标签 Href 拨电话的写法
2013/11/04 HTML / CSS
经理秘书岗位职责
2013/11/14 职场文书
大四毕业生自荐书
2014/07/05 职场文书
法制演讲稿
2014/09/10 职场文书
民政局副局长民主生活会个人整改措施
2014/10/04 职场文书
导游词之徐州云龙湖
2019/11/19 职场文书
导游词之唐山景点
2019/12/18 职场文书
MyBatis 动态SQL全面详解
2021/10/05 MySQL