require vs include

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

require vs include

Post 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
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post 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.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

Wow, odd question.

My absolute guess would be that if there is any difference, require would be faster.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
printf
Forum Contributor
Posts: 173
Joined: Wed Jan 12, 2005 5:24 pm

Post 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
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

Post 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:
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post 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.
(#10850)
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post 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....
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post 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.
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

Post 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
Post Reply