强烈声明: 不要使用(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 相关文章推荐
屏蔽浏览器缓存另类方法
Oct 09 PHP
关于session在PHP5的配置文件中的详细设置参数说明
Apr 20 PHP
php5.3中连接sqlserver2000的两种方法(com与ODBC)
Dec 29 PHP
怎样使用php与jquery设置和读取cookies
Aug 08 PHP
php循环创建目录示例分享(php创建多级目录)
Mar 04 PHP
php生成二维码时出现中文乱码的解决方法
Dec 18 PHP
php实现有趣的人品测试程序实例
Jun 08 PHP
PHP使用NuSOAP调用Web服务的方法
Jul 18 PHP
php ajax数据传输和响应方法
Aug 21 PHP
Laravel 微信小程序后端搭建步骤详解
Nov 26 PHP
laravel框架数据库操作、查询构建器、Eloquent ORM操作实例分析
Dec 20 PHP
PHP高并发和大流量解决方案整理
Dec 24 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多层数组与对象的转换实例代码
2013/08/05 PHP
ThinkPHP基于PHPExcel导入Excel文件的方法
2014/10/15 PHP
PHP面向对象程序设计重载(overloading)操作详解
2019/06/13 PHP
laravel Task Scheduling(任务调度)在windows下的使用详解
2019/10/22 PHP
PHP设计模式(七)组合模式Composite实例详解【结构型】
2020/05/02 PHP
jquery 单击li防止重复加载的实现代码
2010/12/24 Javascript
关于Jquery操作Cookie取值错误的解决方法
2013/08/26 Javascript
Javascript图片上传前的本地预览实例
2014/06/16 Javascript
nodejs 搭建简易服务器的图文教程(推荐)
2017/07/18 NodeJs
简单实现vue验证码60秒倒计时功能
2017/10/11 Javascript
webpack多页面开发实践
2017/12/18 Javascript
用Axios Element实现全局的请求loading的方法
2018/03/15 Javascript
mpvue中配置vuex并持久化到本地Storage图文教程解析
2018/03/15 Javascript
JavaScript基础之this和箭头函数详析
2019/09/05 Javascript
javascript Canvas动态粒子连线
2020/01/01 Javascript
[57:16]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS VG第二场
2014/05/26 DOTA
利用python画一颗心的方法示例
2017/01/31 Python
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容
2018/02/23 Python
在pycharm上mongodb配置及可视化设置方法
2018/11/30 Python
如何使用Python进行OCR识别图片中的文字
2019/04/01 Python
为何人工智能(AI)首选Python?读完这篇文章你就知道了(推荐)
2019/04/06 Python
Ubuntu+python将nii图像保存成png格式
2019/07/18 Python
pandas按行按列遍历Dataframe的几种方式
2019/10/23 Python
Python 文件数据读写的具体实现
2020/01/24 Python
HTML5+CSS3实现无插件拖拽上传图片(支持预览与批量)
2017/01/05 HTML / CSS
Alba Moda德国网上商店:意大利时尚女装销售
2016/11/14 全球购物
简单说下OSPF的操作过程
2014/08/13 面试题
2014爱耳日宣传教育活动总结
2014/03/09 职场文书
城市规划应届生推荐信
2014/09/08 职场文书
2016年“5.12”护士节致辞
2015/07/31 职场文书
医护人员继续教育学习心得体会
2016/01/19 职场文书
浅谈:电影《孔子》观后感(范文)
2019/10/14 职场文书
教你怎么用Python实现多路径迷宫
2021/04/29 Python
vue使用节流函数的踩坑实例指南
2021/05/20 Vue.js
MySQL中distinct和count(*)的使用方法比较
2021/05/26 MySQL
Go语言设计模式之结构型模式
2021/06/22 Golang