inlcude和require

发布于 2019-03-15  196 次阅读


起因:

一朋友面试被问到,php的include和require的区别,这个可能是面试中出现机率比较高的问题。网上众说纷云,各种include和require的几大区别,实在误人子弟。

手册上的说明:

require 和 include  几乎完全一样,除了处理失败的方式不同之外。require  在出错时产生 E_COMPILE_ERROR  级别的错误。换句话说将导致脚本中止而 include  只产生警告(E_WARNING),脚本会继续运行。

从手册上明确知道他们之间的唯一区别就是,require出错会中止脚本,那为什么网上还有各种版本的区别,所以必需从源码上来终结。

 

源码追踪:

要进行源码追踪,先了解下php的大概的运行原理:php代码 ->代码扫描 ->代码翻译 -> zend vm执行 -> 输出

1、找到 require 在代码扫描文件在(Zend/zend_language_scanner.l)中 1262 - 1264行:

<ST_IN_SCRIPTING>"require" {
return T_REQUIRE;
}

2、T_REQUIRE的翻译在, 在 (Zend/zend_language_parser.y)中的 1259行

 

T_REQUIRE expr            { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }

发现 zend_do_include_or_eval 这个函数

 

3、 继续找 zend_do_include_or_eval的定义, 在 (Zend/zend_compile.c)中的 6186行:

opline->opcode = ZEND_INCLUDE_OR_EVAL;

发现把opcode设置为 ZEND_INCLUDE_OR_EVAL,

 

4、继续找ZEND_INCLUDE_OR_EVAL的定义,在 (Zend/zend_vm_def.h)中的 3935行开始,发现目标在4002-4005,(3963-4001是include_once require_once的判断,发现这两也走的同一套逻辑,这里段代码里也可以明显看出 _once的处理逻辑)

              case ZEND_INCLUDE:
              case ZEND_REQUIRE:
                       new_op_array = compile_filename(opline->extended_value, inc_filename TSRMLS_CC);
              break;

 

 

5、继续找compile_filename,定义在(Zend/zend_language_scanner.c)中的 612行中:

 

retval = zend_compile_file(&file_handle, type TSRMLS_CC);

 

6、继续找zend_compile_file, 在zend.c 689行:

zend_compile_file = compile_file;

 

7、 继续找zend api定义的compile_file方法,在(Zend/zend_language_scanner.l)中553行找到这个方法定义:

 

 if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) {
       if (type==ZEND_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;
 }

 

在这里终于发现  include和require的区别了,明显可以看出没有找到文件的话,require,会执行zend_bailout(); ,继续看zend_bailout();会发现,最终会退出脚本执行。

 

结论:

在1~6 步中 ,include和require始终走的是同一逻辑,只有在第7步才有区别判断,从代码中可以得出结论和手册中一致。希望这篇文章能够给这个命题下一个最终结论。

 

不信我的朋友们可以去看看PHP官方说明

http://php.net/manual/zh/function.require.php


公交车司机终于在众人的指责中将座位让给了老太太