Version française de ma réponse sur Stack Overflow : PHP: file_exists vs stream_resolve_include_path - What Performs Better?

is_file, comme la documentation l'indique, vérifie si le fichier est un véritable fichier, tandis que file_exists vérifie si un fichier ou un dossier existe. À savoir que ces deux fonctions utilisent un système de cache, elles partent donc sur un pied d'égalité.


Les sources

Rien de mieux que le retour aux sources pour voir les entrailles de ces deux fonctions. Il s'avère qu'elles utilisent la même function en interne, seules les routines de vérification diffèrent.

Ci-dessous, le pseudo code très simplifié du processus de vérification :

function php_stat($fichier)
{
'file_exists'
↳ virtual_file_ex($fichier)
↳ virtual_access($fichier)
'Windows'
↳ tsrm_win32_access($fichier)
↳ return access($fichier)
'Autres systèmes'
↳ return access($fichier)
↳ return _php_stream_stat_path($fichier) == FALSE
'is_file'
↳ _php_stream_stat_path($fichier)
↳ return $fichier.st_mode == S_IFREG
}

Pour les curieux, voici les sources des fonctions :

Au premier abord, ça semble clair comme de l'eau de roche, file_exists() nécessite bien plus d'opérations à effectuer. Cependant, _php_stream_stat_path() est lourde puisqu'elle récupère toutes les informations sur un fichier/dossier (appelé inode) : volume, numéro d'inode, droit d'accès à l'inode, nombre de liens, userid du propriétaire, groupid du propriétaire, type du volume, si le volume est une inode, taille en octets, date de dernier accès (Unix timestamp), date de dernière modification (Unix timestamp), date de dernier changement d'inode (Unix timestamp), taille de bloc et le nombre de blocs de 512 octets alloués.

Il faudra attendre de voir le résultat des tests pour se faire une meilleure idée.


Une meilleure alternative ?

Dans ce commentaire, DeyV laisse à penser que stream_resolve_include_path serait une bonne alternative à file_exists(). À priori, cette fonction utiliserait aussi le système de cache.

Great alternative to file_exists() is stream_resolve_include_path() -- DeyV

Toujours d'après les sources, le pseudo code suivant en ressort :

function stream_resolve_include_path($fichier)
{
    zend_resolve_path($fichier)
        ↳ php_resolve_path_for_zend($fichier)
            ↳ php_resolve_path($fichier)
                ↳ tsrm_realpath($fichier)
                    ↳ return estrdup($fichier)
}

Pour les curieux, le détail de chaque fonction :

Notez que le fait d'utiliser des chemins absolus permet un gain non négligeable.


Les tests

Configuration de la machine de test

  • Intel Core i5 CPU 750 @ 2.67GHz ;
  • 4 Go de RAM ;
  • disque dur Seagate STM3500418AS 7200 tr/min ;
  • Debian GNU/Linux 7 64 bit ;
  • noyau 3.10-3-amd64 ;
  • système de fichiers EXT4 ;
  • PHP 5.5.5, options de build : --disable-all --disable-pdo --disable-phar --disable-session --disable-mysqlnd-compression-support --without-pear.

Le benchmark

Deux types de tests : un réaliste où on teste la présence de fichiers différents, et un autre moins parlant dans lequel le même fichier est testé 1 000 000 de fois.
Pour le test réaliste, j'ai créé un dossier test qui contient 1 000 000 fichiers (le premier fichier s'appelant 0 et le dernier 999 999).
D'après le script qui permet de lancer et chronométrer les tests, le graphique suivant en résulte :

Benchmark. Graphique par ChartGo

Observations

  1. is_file() est plus rapide dans tous les cas ;
  2. file_exists() a un léger avantage sur stream_resolve_include_path(), si ce dernier utilise les chemins absolus ;
  3. stream_resolve_include_path() est un gouffre avec les chemins relatifs.

Historique

  • 2016-08-31 : correction des liens pointant vers le code source des fonctions.
  • 2015-05-21 : ajout du lien vers la question originale de Stack Overflow.
  • 2013-10-28 : ajout du script de tests pour ne pas trop encombrer la page.
  • 2013-10-27 : ajout de tests plus réalistes et étoffement des informations.
  • 2013-10-25 : Une meilleure alternative ?.
  • 2013-10-23 : ajout des explications avec les sources PHP.