强烈声明: 不要使用(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 程序员应该使用的10个组件
Oct 31 PHP
php 截取字符串并以零补齐str_pad() 函数
May 07 PHP
php 注释规范
Mar 29 PHP
php 的加密函数 md5,crypt,base64_encode 等使用介绍
Apr 09 PHP
php阻止页面后退的方法分享
Feb 17 PHP
php HTML无刷新提交表单
Apr 05 PHP
PHP中PDO的事务处理分析
Apr 07 PHP
CI框架常用方法小结
May 17 PHP
Yii使用smsto短信接口的函数demo示例
Jul 13 PHP
Zend Framework基于Command命令行建立ZF项目的方法
Feb 18 PHP
Laravel中七个非常有用但很少人知道的Carbon方法
Sep 21 PHP
laravel实现一个上传图片的接口,并建立软链接,访问图片的方法
Oct 12 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中用文本文件做数据库的实现方法
2008/03/27 PHP
php下使用以下代码连接并测试
2008/04/09 PHP
php 设计模式之 工厂模式
2008/12/19 PHP
PHP 第二节 数据类型之数组
2012/04/28 PHP
php处理文件的小例子(解压缩,删除目录)
2013/02/03 PHP
浅析php fwrite写入txt文件的时候用 \r\n不能换行的问题
2013/08/06 PHP
免费的ip数据库淘宝IP地址库简介和PHP调用实例
2014/04/08 PHP
ThinkPHP3.1之D方法实例详解
2014/06/20 PHP
PHP的Yii框架中过滤器相关的使用总结
2016/03/29 PHP
eclipse php wamp配置教程
2016/06/30 PHP
JS 文件传参及处理技巧分析
2010/05/13 Javascript
jQuery源码中的chunker 正则过滤符分析
2012/07/31 Javascript
jquery实现手风琴效果实例代码
2013/11/15 Javascript
Javascript基础教程之比较操作符
2015/01/18 Javascript
JQuery显示、隐藏div的几种方法简明总结
2015/04/16 Javascript
jQuery zTree加载树形菜单功能
2016/02/25 Javascript
jQuery简单动画变换效果实例分析
2016/07/04 Javascript
Highcharts入门之简介
2016/08/02 Javascript
微信小程序实战之运维小项目
2017/01/17 Javascript
js实现适合新闻类图片的轮播效果
2017/02/05 Javascript
MUI 上拉刷新/下拉加载功能实例代码
2017/04/13 Javascript
详解js删除数组中的指定元素
2018/10/31 Javascript
详解Vue项目部署遇到的问题及解决方案
2019/01/11 Javascript
vue页面更新patch的实现示例
2020/03/25 Javascript
[54:45]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 Optic vs OG
2018/04/02 DOTA
[00:10]DOTA2全国高校联赛速递
2018/05/30 DOTA
Python编程二分法实现冒泡算法+快速排序代码示例
2018/01/15 Python
windows下python和pip安装教程
2018/05/25 Python
解决Pycharm运行时找不到文件的问题
2018/10/29 Python
Django 数据库同步操作技巧详解
2019/07/19 Python
python自动分箱,计算woe,iv的实例代码
2019/11/22 Python
python 5个实用的技巧
2020/09/27 Python
css3实例教程 一款纯css3实现的环形导航菜单
2014/10/20 HTML / CSS
英国最大的宝石首饰超市:QP Jewellers
2018/09/23 全球购物
美国智能家居专家:tink
2019/06/04 全球购物
高三毕业感言
2015/07/30 职场文书