TL;DR: if you want to read a file, use is_readable, not file_exists.

Over the last year or so, I think I reviewed about a dozen PRs—both Human Made and external—with something like this PHP code snippet:

if ( file_exists( $file ) ) {
    include $file;

    // OR:
    // file_get_contents( $file );

    // OR:
    // fopen( $file, 'r' );

While this code works like 99% of the time, it’s not really doing what people thought it did.

What happens if the file does exist, but it’s not readable?
Correct, you run into some error or at least warning, depending on what exactly you want to do with the file contents.

Instead, you might want to use is_readable (link), which checks if a file exists and is readable. Both file_exists() and is_readable() use the stat cache, so performance should be equivalent.

Looking into the PHP source, you can find both is_readable and file_exists defined as FS_IS_R (link) and FS_EXISTS (link), respectively. Searching for either identifier in that same file, you can see how their behavior, on a code level, differs. (It does not.) Also, considering Zend OPCache, both functions are being optimized the same way.

However, if all you need is to check the existence of a file, for example, when you need to reason about Yarn vs. NPM, based on a lock file or something—yeah, that’s a made-up example, I know—you are good with file_exists.

Leave a Reply

Your email address will not be published. Required fields are marked *