Friday, December 2, 2011

Does File Exist in PHP Include Path?

We built a wrapper script around PHPUnit that loads and configures our application for testing so that test authors need not pepper their test files with redundant lines like "require_once dirname(...) . '/setup/file/included/in/all/tests.php'". This in itself is actually pretty cool, but that's fodder for another post =) The wrapper is a big time saver, but it comes at the price of a little consumption of internal PHPUnit implementation, most importantly how it starts itself up.

The start up invocation changed between 3.5 and 3.6 and one of those changes involved how PHPUnit autoloads classes. This introduced a problem because we needed to be able to support both versions of PHPUnit while the upgrade was underway. Fortunately it turned out that a determining factor between 3.5 and 3.6 was the presence of the "Autoload.php" file in the root of the PHPUnit extension module. Unfortunately, it turned out to be nontrivial to check for the existence of the file using the standard file_exists() method. The problem is that file_exists() doesn't check PHP's include path for relative file paths (unlike the logic of require_once()).

After a little research, we were able to solve the issue by a little bit of fun with file_get_contents, which takes an additional parameter to let it know that you'd like to check the include path for the presence of the file. Additionally, in the interest of performance, it lets you load only the first byte of the file, rather the entire thing.

// Support for newer version of PHPUnit during rollout to all VMs                                                                                         
// This will load the first byte of the file from the include path                                                                                         
// ...if it exists                                                                                                                                        
if (@file_get_contents('PHPUnit/Autoload.php', true, null, 0, 1))                                                                                          
    // File exists, we're on 3.6...
    require 'PHPUnit/Autoload.php';                                                                                                                        
    // ... other stuff
    // Do stuff for 3.5

Check out the docs on file_get_contents for a description of the params.

UPDATE: The function stream_resolve_include_path may do the trick with much less hassle.

1 comment:

  1. Great entry. I was looking for that. You helped me a lot.