2013-10-11 8 views
4

Il semble que les développeurs php se demandent depuis longtemps s'il est préférable d'utiliser file_exists() ou stream_resolve_include_path() pour vérifier si un fichier existe (que ce soit pour les inclure, les systèmes de cache, etc.). Il m'a fait me demander si quelqu'un a fait un test de benchmark sur lequel est le meilleur choix, à la fois pour le temps de chargement de la page, les performances du serveur et l'utilisation de la mémoire.PHP: file_exists vs stream_resolve_include_path - Quoi de mieux?

Je ne pouvais rien trouver ici à SO qui a résolu ce problème, donc pensé qu'il serait temps pour nous de le faire.

Répondre

12

J'ai fait un petit benchmark, mais avant les résultats, voyons comment fonctionnent ces fonctions. Vous pouvez lire le code source PHP here. Il ya un french version of this answer, écrit plus tôt dans la semaine, bon timing;).

Je parlerai aussi de is_file(), car il est défini dans la même fonction de base dans la source. Par fonction de base, je dis la source C, pas accessible depuis le langage PHP dans vos scripts. De ce que je comprends, file_exists() et is_file() sont les enfants de la fonction de base php_stat() deC'est le pseudo-code très simplifiée du processus:

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 
} 

Et le pseudo-code du processus stream_resolve_include_path():

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

A partir de là, sans résultat numérique d'une référence, vous pouvez voir comment une fonction est chère en ressource.


Le code de la référence:

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

} 

test Let avec un fichier existante (1) et un inexistant (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 

Les résultats parlent d'eux-mêmes;)


Benchmark v2 - juste un moyen plus facile d'ajouter de nouvelles fonctions à tester.

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>'; 

Résultats:

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 

Il y a un peu de frais pour appeler $funct(), ce qui explique le nombre légèrement plus élevé.