php include 与 require 起底[转]

转自 http://www.guangla.com/post/2014-01-24/40060857811

 

起因:

一朋友面试被问到,php的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步才有区别判断,从代码中可以得出结论和手册中一致。希望这篇文章能够给这个命题下一个最终结论。

posted @ 2015-04-14 10:04  Debm.Zhang  阅读(281)  评论(0编辑  收藏  举报