stream_resolve_include_path() als Alternative zu file_exists()

Vor ungefähr einer Woche bin ich über ein paar Zeilen Code gestolpert, die für die Existenzprüfung einer Datei stream_resolve_include_path() statt file_exists() verwendeten. Bis dahin kannte ich die Funktion nicht. Ein Blick in die PHP-Dokumentation zeigte mir, dass ein string mit dem absoluten Pfad zur Datei zurückgegeben wird, wenn diese existiert, sonst false. Auf einigen Internetseiten wird die Funktion als die schnellere Alternative gefeiert.

Um diese Meinung nachvollziehen zu können, habe ich die Funktionen getestet und verglichen. Der Test erfolgte auf Windows 11 mit PHP 8.1.5. Ziel war es, die Ausführungszeiten zu ermitteln und zu vergleichen. Das Verhalten sollte für die Fälle geprüft werden in denen eine Datei existiert, nicht existiert oder mehrere unterschiedliche Dateien existieren. Für den letzten Fall wurden die Dateien vorher erstellt.

Für die nachfolgenden Ergebnisse wurden die Funktionen jeweils 100.000-mal aufgerufen. Die Angaben der Zeiten erfolgt in Sekunden.

FunktionDatei existiertDatei existiert nichtUnterschiedliche Dateien (alle existieren)
stream_resolve_include_path()0,0415,0922,687
file_exists()1,3882,1474,793
Testergebnisse für stream_resolve_include_path() und file_exists()

Die Ergebnisse zeigen uns folgendes: Existiert die Datei und wird immer die gleiche geprüft, so ist stream_resolve_include_path() deutlich schneller als file_exists(). Das Ergebnis wird zwischengespeichert und es erfolgt nicht immer eine echte Prüfung auf dem Dateisystem. Existiert die geprüfte Datei nicht, so ist file_exists() schneller. Werden unterschiedliche Dateien einmalig geprüft, so ist stream_resolve_include_path() wiederum performanter.

Achtung, Cache!

Nach diesen brisanten Ergebnissen, habe ich mich mit dem Caching-Mechanismus von stream_resolve_include_path() befasst. Ein Kommentar in der Dokumentation deutet darauf hin, dass ein solcher existiert. Das nachfolgende Testskript erstellt eine Datei, prüft, ob diese existiert, löscht sie und prüft abschließend erneut. Im ersten Testdurchlauf erfolgte das Löschen mit unlink() und im zweiten Testdurchlauf mit exec('del test.php').

Das ist der verwendete Code:

<?php function checkIfFileExists() { global $filename; printf("%s returns %s\n", 'stream_resolve_include_path()', var_export(stream_resolve_include_path($filename), true)); printf("%s returns %s\n", 'file_exists()', var_export(file_exists($filename), true)); } // Create the file $filename = __DIR__ . '\\' . 'test.php'; file_put_contents($filename, ''); // Check #1 checkIfFileExists(); // Remove the file. Use either unlink or exec. // unlink($filename); // exec('del test.php'); echo 'Delete file' . PHP_EOL; // Check #2 checkIfFileExists();
Code-Sprache: HTML, XML (xml)

Ausgabe bei Löschen mit unlink():

stream_resolve_include_path() returns 'C:\\Users\\angel\\tests\\test.php' file_exists() returns true Delete file stream_resolve_include_path() returns false file_exists() returns false
Code-Sprache: JavaScript (javascript)

Ausgabe bei Löschen mit exec():

stream_resolve_include_path() returns 'C:\\Users\\angel\\tests\\test.php' file_exists() returns true Delete file stream_resolve_include_path() returns 'C:\\Users\\angel\\tests\\test.php' file_exists() returns false
Code-Sprache: JavaScript (javascript)

Wie wir sehen können, wird das Ergebnis bei stream_resolve_include_path() zwischengespeichert. Wird das Löschen nicht über unlink() durchgeführt, liefert es ein falsches/unerwünschtes Ergebnis.

Meiner Meinung nach sollte man die Funktion stream_resolve_include_path() nur sehr vorsichtig und gezielt einsetzen. Man könnte damit eine deutliche Leistungssteigerung erzielen. Das Caching jedoch kann eine Ursache für unerwartete Fehler sein. Darüber hinaus ist diese Funktion möglicherweise nicht ganz so geläufig und bringt etwas Rechercheaufwand mit sich. Deswegen werde ich für meine Datei-Existenzprüfungen erstmal die wohlbekannte und weitverbreitete file_exists()-Funktion verwenden, bis man mich von der Alternative überzeugen kann.

Wie prüft ihr, ob eine Datei existiert und kanntet ihr stream_resolve_include_path() schon?

Ein Kommentar

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.