Page 1 of 1

require vs include

Posted: Fri Oct 27, 2006 9:20 pm
by BDKR
I know the functional difference so the two but I'm curious about the something else here. I had an interview the other day with a company in Santa Clara where an unusual question was asked. In particular, have I noticed any performance differences between require and include? I've done my share of benchmarking, but that question knocked me back on my heels as I've never had occasion to test or worry about it.

Any ideas?

Cheers,
BDKR

Posted: Fri Oct 27, 2006 9:43 pm
by feyd
I would predict that the difference is negligible if any. Although looking at their underlying source code would probably suggest a winner readily.

Posted: Fri Oct 27, 2006 9:45 pm
by s.dot
Wow, odd question.

My absolute guess would be that if there is any difference, require would be faster.

Posted: Fri Oct 27, 2006 9:53 pm
by printf
It really will depend on the system, but by default require, is a touch faster, but it's not even worth noting unless your using over 1000 includes, which would be very silly. include has a condition on error, require does not.

printf

Posted: Fri Oct 27, 2006 10:06 pm
by BDKR
Yeah, it would've been my guess that the differences were negligible as well. That's why this question knocked me back on my heels.

However, if there are notable differences, how much so? Is it enough to negate it's use? If they (the potential employers are that worried about
performance, I suspect they should be looking in places other then the performance of include vs require.

And I suspect that they do have some performance issues based on the number of questions they asked me about profiling and cache management. It's prolly a
data modeling issue. :roll:

Posted: Sat Oct 28, 2006 1:11 am
by Christopher
I think the answer may depend on the version of PHP used. I recall reading that in PHP5 (an possibly current versions of PHP4) there is really no difference. To quote from the manual:
PHP Manual wrote:The two constructs are identical in every way except how they handle failure. include() produces a Warning while require() results in a Fatal Error. In other words, use require() if you want a missing file to halt processing of the page. include() does not behave this way, the script will continue regardless.

Posted: Sat Oct 28, 2006 4:22 am
by timvw
If i'm not mistaken require is defined as an alias of include, so the only possible overhead would be in the stuff that the ZEND_FALIAS generates....

Posted: Sat Oct 28, 2006 8:59 am
by feyd
timvw wrote:If i'm not mistaken require is defined as an alias of include, so the only possible overhead would be in the stuff that the ZEND_FALIAS generates....
Doing a bit of digging, they certainly call the same underlying function, however with slightly different arguments.

Code: Select all

					switch (EX(opline)->op2.u.constant.value.lval) {
						case ZEND_INCLUDE_ONCE:
						case ZEND_REQUIRE_ONCE: {
								int dummy = 1;
								zend_file_handle file_handle = {0};

								if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS
										&& ZEND_IS_VALID_FILE_HANDLE(&file_handle)) {

									file_handle.filename = inc_filename->value.str.val;
									file_handle.free_filename = 0;

									if( !file_handle.opened_path ) {
										file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len);
									}

									if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
										new_op_array = zend_compile_file(&file_handle, (EX(opline)->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC);
										zend_destroy_file_handle(&file_handle TSRMLS_CC);
									} else {
										zend_file_handle_dtor(&file_handle);
										failure_retval=1;
									}
								} else {
									if (EX(opline)->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) {
										zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val);
									} else {
										zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val);
									}
								}
								break;
							}
							break;
						case ZEND_INCLUDE:
						case ZEND_REQUIRE:
							new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC);
							break;
						case ZEND_EVAL: {
								char *eval_desc = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC);

								new_op_array = compile_string(inc_filename, eval_desc TSRMLS_CC);
								efree(eval_desc);
							}
							break;
						EMPTY_SWITCH_DEFAULT_CASE()
					}
which calls

Code: Select all

zend_op_array *compile_filename(int type, zval *filename TSRMLS_DC)
{
	zend_file_handle file_handle = {0};
	zval tmp;
	zend_op_array *retval;
	char *opened_path = NULL;

	if (filename->type != IS_STRING) {
		tmp = *filename;
		zval_copy_ctor(&tmp);
		convert_to_string(&tmp);
		filename = &tmp;
	}
	file_handle.filename = filename->value.str.val;
	file_handle.free_filename = 0;
	file_handle.type = ZEND_HANDLE_FILENAME;
	file_handle.opened_path = NULL;

	retval = zend_compile_file(&file_handle, type TSRMLS_CC);
	if (retval && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) {
		int dummy = 1;
	
		if (!file_handle.opened_path) {
			file_handle.opened_path = opened_path = estrndup(filename->value.str.val, filename->value.str.len);
		}
		
		zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL);
		
		if (opened_path) {
			efree(opened_path);
		}
	}
	zend_destroy_file_handle(&file_handle TSRMLS_CC);

	if (filename==&tmp) {
		zval_dtor(&tmp);
	}
	return retval;
}
which leads to zend_compile_file()

Code: Select all

	zend_message_dispatcher_p = utility_functions->message_handler;
	zend_block_interruptions = utility_functions->block_interruptions;
	zend_unblock_interruptions = utility_functions->unblock_interruptions;
	zend_get_configuration_directive_p = utility_functions->get_configuration_directive;
	zend_ticks_function = utility_functions->ticks_function;
	zend_on_timeout = utility_functions->on_timeout;

	zend_compile_file = compile_file;
	zend_execute = execute;
	zend_execute_internal = NULL; /* saves one function call if the zend_execute_internal is not used */

	/* set up version */
	zend_version_info = strdup(ZEND_CORE_VERSION_INFO);
	zend_version_info_length = sizeof(ZEND_CORE_VERSION_INFO)-1;
which is a C level alias of compile_file() :roll:

Code: Select all

ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
{
	zend_lex_state original_lex_state;
	zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
	zend_op_array *original_active_op_array = CG(active_op_array);
	zend_op_array *retval=NULL;
	int compiler_result;
	zend_bool compilation_successful=0;
	znode retval_znode;
	zend_bool original_in_compilation = CG(in_compilation);

	retval_znode.op_type = IS_CONST;
	retval_znode.u.constant.type = IS_LONG;
	retval_znode.u.constant.value.lval = 1;
	retval_znode.u.constant.is_ref = 0;
	retval_znode.u.constant.refcount = 1;

	zend_save_lexical_state(&original_lex_state TSRMLS_CC);

	retval = op_array; /* success oriented */

	if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) {
		if (type==ZEND_REQUIRE) {
			zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
			zend_bailout();		
		} else {
			zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
		}
		compilation_successful=0;
	} else {
		init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
		CG(in_compilation) = 1;
		CG(active_op_array) = op_array;
		compiler_result = zendparse(TSRMLS_C);
		zend_do_return(&retval_znode, 0 TSRMLS_CC);
		CG(in_compilation) = original_in_compilation;
		if (compiler_result==1) { /* parser error */
			zend_bailout();
		}
		compilation_successful=1;
#ifdef ZEND_MULTIBYTE
		if (SCNG(code)) {
			efree(SCNG(code));
			SCNG(code) = NULL;
		}
		if (SCNG(current_code)) {
			efree(SCNG(current_code));
			SCNG(current_code) = NULL;
		}
#endif /* ZEND_MULTIBYTE */
	}

	if (retval) {
		CG(active_op_array) = original_active_op_array;
		if (compilation_successful) {
			pass_two(op_array TSRMLS_CC);
		} else {
			efree(op_array);
			retval = NULL;
		}
	}
	if (compilation_successful) {
		zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
	}
	return retval;
}
Noting the "type==ZEND_REQUIRE" line, it will only call one additional function (zend_bailout()) if the scan fails.

Code: Select all

#define zend_bailout()		_zend_bailout(__FILE__, __LINE__)
Having fun yet?

Code: Select all

BEGIN_EXTERN_C()
ZEND_API void _zend_bailout(char *filename, uint lineno)
{
	TSRMLS_FETCH();

	if (!EG(bailout_set)) {
		zend_output_debug_string(1, "%s(%d) : Bailed out without a bailout address!", filename, lineno);
		exit(-1);
	}
	CG(unclean_shutdown) = 1;
	CG(in_compilation) = EG(in_execution) = 0;
	EG(current_execute_data) = NULL;
	longjmp(EG(bailout), FAILURE);
}
END_EXTERN_C()
In conclusion:
  1. internally, include() and require() are identical for the vast majority of their execution.
  2. If you value your sanity, don't look at PHP's internal C code too deeply.

Posted: Sat Oct 28, 2006 10:22 am
by BDKR
feyd wrote: Noting the "type==ZEND_REQUIRE" line, it will only call one additional function (zend_bailout()) if the scan fails.

Code: Select all

#define zend_bailout()		_zend_bailout(__FILE__, __LINE__)
Having fun yet?
Yeah, that's exactly what I figured.
feyd wrote: In conclusion:
  1. internally, include() and require() are identical for the vast majority of their execution.
  2. If you value your sanity, don't look at PHP's internal C code too deeply.
Now there is also the possibility that his words were poorly chosen. He had a very thick accent that was difficult to deal with on a phone interview. Especially considering that his voice kept trailing off as though he was getting quieter and quieter. There is also the possibility that he was wondering what my preference between the two were. There is the fact (unless something has changed) that require doesn't really provide an oppurtunity for a graceful bailout. Something that's caused me to begin to lean back in favor of using include() again.

Cheers