Analyze the difference between require and include from the core PHP code

  • 2020-03-31 21:28:36
  • OfStack

In-depth understanding of PHP require/include order (link: #)
universal
In the PHP manual:

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

This means that require will abort PHP when it fails, and include can continue.
What's the difference? Let's take this question with us into the core of PHP code.
The following is a graph of the PHP runtime (where did this graph come from? Bird brother?)
< img Alt = "PHP" border = 0 SRC = "http://files.jb51.net/upload/201101/20110102134908104.jpg" >

A: lex is a code scanner that scans code, and yacc is a Compiler that converts the syntax of any code into yacc, which is a parser.
The suffix for lex under c is *. L yacc is *. Y

To the chase
Here is the operation record:

Cc @ cc - laptop: / opt/workspace $SVN checkout http://svn.php.net/repository/php/php-src/branches/PHP_5_3 PHP - SRC - 5.3
Get the latest PHP source code from SVN.

Start digging in:

Cc @ cc - laptop: / opt/workspace/PHP - SRC - 5.3 $find. -type f -name "*. L" - the exec grep - Hn "require_once" {} \;
. / Zend/zend_language_scanner. L: 1093: require_once "{"
Look for where require_once appears in the lex code scanner file, line 1093 of zend_language_scanner.
1093 "require_once" {
1094 return T_REQUIRE_ONCE;
1095}

And then T_REQUIRE_ONCE,

Cc @ cc - laptop: / opt/workspace/PHP - SRC - 5.3 $find. -type f -name "* y" - the 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); }

Near line 985, there's a bunch of code:

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); }
;

So we need to go further and look for zend_do_include_or_eval,

Cc @ cc - laptop: / opt/workspace/PHP - SRC - 5.3 $find. -type f -name "* c" - the 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)

A structure is assembled in zend_do_include_or_eval, ZEND_INCLUDE_OR_EVAL.

Find zend_vm_def.h in ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) :
The switch (Z_LVAL (opline - > Op2.u.com.ant)) {

The key sentence is:
New_op_array = compile_filename (Z_LVAL (opline - > Op2. The u.c. onstant), inc_filename TSRMLS_CC);

In zend_complie.h:
ZEND_API zend_op_array *compile_filename(int type, zval *filename TSRMLS_DC);

This function is defined in the zend_language_scaner.l file to find the most core code:

If (open_file_for_scanning (file_handle TSRMLS_CC) = = FAILURE) {
// difference between require and include: display level of error message (with bailout and without 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 {code omitted}

Continuing to trace zend_message_dispatcher can be found in the main/main.c file php_message_handler_for_zend function:

//include output error messages at the level of: E_WARNING
Case ZMSG_FAILED_INCLUDE_FOPEN:
Php_error_docref (" function.include "TSRMLS_CC, E_WARNING," Failed to open '%s' for inclusion (include_path='%s') ", php_strip_url_passwd((char *) data), STR_PRINT(PG(include_path));
Break;
// compile_error is the level at which an error message is output from require
The code is slightly

conclusion
The difference between require and include is that when an error occurs, one is an error and the other is a warning.


Related articles: