It seems as of late there has been a fair amount of wondering on by php developers on whether it is better to use file_exists() or stream_resolve_include_path() when doing checks of whether or not a file exists (be it for including them, caching systems, etc).
It got me wondering if anybody out there has done any benchmark testing on which of these is a better option, for both page load time, server performance and memory usage.
I could not find anything here at SO that addressed this issue so figured it would be time for us to do so.
I have done a little benchmark, but before results, let's see how these functions work. You can read the PHP source code here. There is a french version of this answer, written earlier in the week, good timing ;).
I will talk about is_file()
too, as it is defined into the same core function in the source. By core function, I say the C source, not accessible from PHP language into your scripts.
Of what I understand, file_exists()
and is_file()
are children of the core function php_stat()
. This is the highly simplified pseudo-code of the process:
function php_stat($file)
{
'file_exists'
↳ virtual_file_ex($file)
↳ virtual_access($file)
'Windows'
↳ tsrm_win32_access($file)
↳ return access($file)
'Other systems'
↳ return access($file)
'is_file'
↳ return $file.st_mode == S_IFREG
}
And the pseudo-code of the stream_resolve_include_path()
process:
function stream_resolve_include_path($file)
{
zend_resolve_path($file)
↳ php_resolve_path_for_zend($file)
↳ php_resolve_path($file)
↳ tsrm_realpath($file)
↳ return estrdup($file)
}
From here, without numeric result of a benchmark, you can see how one function is expensive in resource.
The code for the benchmark:
function bench_file($file) {
$res = array();
$max = 1000000;
// is_file()
$res[] = microtime(1);
for ( $i = 0; $i < $max; ++$i ) {
if ( is_file($file) ) {
//
}
}
$res[] = microtime(1);
clearstatcache();
// file_exists()
$res[] = microtime(1);
for ( $i = 0; $i < $max; ++$i ) {
if ( file_exists($file) ) {
//
}
}
$res[] = microtime(1);
clearstatcache();
// stream_resolve_include_path()
$res[] = microtime(1);
for ( $i = 0; $i < $max; ++$i ) {
if ( stream_resolve_include_path($file) !== false ) {
//
}
}
$res[] = microtime(1);
printf(
'is_file = %f, file_exists = %f, stream_resolve_include_path = %f',
$res[1] - $res[0], $res[3] - $res[2], $res[5] - $res[4]
);
}
Let's test with an existante file (1) and a inexistant one (2):
1 : is_file = 0.218582, file_exists = 0.742195, stream_resolve_include_path = 1.626521
2 : is_file = 0.458983, file_exists = 0.644638, stream_resolve_include_path = 5.623289
Results speak for themselves ;)
Benchmark v2 - just an easier way to add new functions to test.
function micro($func, $file) {
$max = 1000000;
$start = microtime(1);
for ( $i = 0; $i < $max; ++$i ) {
if ( $func($file) ) {
//
}
}
$end = microtime(1);
clearstatcache();
return $end - $start;
}
function bench_file($file) {
$res = array(
'is_file' => micro('is_file', $file),
'file_exists' => micro('file_exists', $file),
'stream_resolve_include_path' => micro('stream_resolve_include_path', $file)
);
$ret = '';
foreach ( $res as $key => $value ) {
$ret .= sprintf('%s = %f, ', $key, $value);
}
return trim($ret, ', ');
}
echo '<pre>', bench_file('file-ok'), "\n", bench_file('file-ko'), '</pre>';
Results:
is_file = 0.295752, file_exists = 0.852082, stream_resolve_include_path = 1.759607
is_file = 0.527770, file_exists = 0.724793, stream_resolve_include_path = 5.916151
There is a little cost to call $funct()
, this explains the slightly higher numbers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With