PHP: file_exists vs stream_resolve_include_path - What Performs Better?

后端 未结 1 503
慢半拍i
慢半拍i 2021-01-13 08:05

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 c

相关标签:
1条回答
  • 2021-01-13 08:14

    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.

    0 讨论(0)
提交回复
热议问题