侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

从php核心代码分析require和include的区别

php  /  管理员 发布于 7年前   358

深入理解PHP之require/include顺序 25867.htm
普及
在php手册中:

require() is identical to include() except upon failure it will also produce a fatal E_ERROR level error. In other words, it will halt the script whereas include() only emits a warning (E_WARNING) which allows the script to continue.

就是说在失败的时候,require是会中止php运行的,而include是可以继续运行的。
倒底有什么样的区别呢?我们带着这个疑问来一起进入PHP的核心代码。
下面是一个PHP运行过程的图(这个图是出自哪里的?鸟哥画的?)

补习一下:lex是代码扫描器,扫描代码用的,yacc是Yet Another Compiler Compiler,作用是把任何一种代码的语法转成yacc语法,yacc就是解析器(真TMD绕)。
lex在c下的后缀是*.l yacc是*.y

正题
下面看操作记录:

cc@cc-laptop:/opt/workspace$ svn checkout http://svn.php.net/repository/php/php-src/branches/PHP_5_3 php-src-5.3
从svn取最新的php源代码。

开始深入:

cc@cc-laptop:/opt/workspace/php-src-5.3$ find . -type f -name “*.l” -exec grep -Hn “require_once” {} \;
./Zend/zend_language_scanner.l:1093:”require_once” {
寻找lex代码扫描器文件中出现require_once的地方,zend_language_scanner.l的1093行。
1093 “require_once” {
1094 return T_REQUIRE_ONCE;
1095 }

然后再搜一下T_REQUIRE_ONCE,

cc@cc-laptop:/opt/workspace/php-src-5.3$ find . -type f -name “*.y” -exec grep -Hn “T_INCLUDE” {} \;
./Zend/zend_language_parser.y:52:%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
./Zend/zend_language_parser.y:985: | T_INCLUDE expr { zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }
./Zend/zend_language_parser.y:986: | T_INCLUDE_ONCE expr { zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }

在985行附近,有这样一群代码:

internal_functions_in_yacc:
T_ISSET ‘(‘ isset_variables ‘)' { $$ = $3; }
| T_EMPTY ‘(‘ variable ‘)' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }
| T_INCLUDE expr { zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }
| T_INCLUDE_ONCE expr { zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }
| T_EVAL ‘(‘ expr ‘)' { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }
| T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }
| T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); }
;

于是乎,我们需要继续深入寻找zend_do_include_or_eval,

cc@cc-laptop:/opt/workspace/php-src-5.3$ find . -type f -name “*.c” -exec grep -Hn “zend_do_include_or_eval” {} \;
./Zend/zend_compile.c:4317:void zend_do_include_or_eval(int type, znode *result, const znode *op1 TSRMLS_DC) /* {{{ */

zend_do_include_or_eval中组装了一个结构体,ZEND_INCLUDE_OR_EVAL。

再在zend_vm_def.h中找到ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY):
switch (Z_LVAL(opline->op2.u.constant)) {代码略}

中间关键的一句是:
new_op_array = compile_filename(Z_LVAL(opline->op2.u.constant), inc_filename TSRMLS_CC);

在zend_complie.h文件中:
ZEND_API zend_op_array *compile_filename(int type, zval *filename TSRMLS_DC);

这个函数定义在zend_language_scaner.l文件中,找出最核心的代码:

if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) {
// require与include的差别:错误信息的显示级别(有bailout和无bailout)
if (type==ZEND_REQUIRE) { //require时
zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
zend_bailout();
} else {
zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
}
compilation_successful=0;
} else {代码略}

继续追踪zend_message_dispatcher可以在main/main.c文件中找到php_message_handler_for_zend函数:

//include输出错误信息时的级别为:E_WARNING
case ZMSG_FAILED_INCLUDE_FOPEN:
php_error_docref(“function.include” TSRMLS_CC, E_WARNING, “Failed opening ‘%s' for inclusion (include_path='%s')”, php_strip_url_passwd((char *) data), STR_PRINT(PG(include_path)));
break;
//require输出错误信息时的级别为:E_COMPILE_ERROR
代码略

总结
和开头PHP手册所说完全一致,require和include的区别在于,出现错误时,一个是error一个是warning。

您可能感兴趣的文章:

  • PHP中include()与require()的区别说明
  • PHP中require和include路径问题详解
  • PHP中include与require使用方法区别详解
  • PHP包含文件函数include、include_once、require、require_once区别总结
  • 深入理解PHP之require/include顺序 推荐
  • php include,include_once,require,require_once
  • PHP中include和require的区别实例分析


  • 上一条:
    PHP 设置MySQL连接字符集的方法
    下一条:
    深入理解PHP之require/include顺序 推荐
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 用Time Warden监控PHP中的代码处理时间(0个评论)
    • 在PHP中使用array_pop + yield实现读取超大型目录功能示例(0个评论)
    • Property Hooks RFC在PHP 8.4中越来越接近现实(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-11
    • 2017-12
    • 2018-01
    • 2018-02
    • 2018-03
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-09
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-09
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客