ZF-2923: Zend_Loader::autoload() causes a file not found warning when unable to include the class

Description

Autoload functions should not cause errors when they can't include the requested class. They may only be one function in the autoload stack, or they may be being used by class_exists() to simply check if a class is available. It isn't the job of any individual autoload to ensure a class is defined, therefore they should fail silently in the event that they cannot include the class.

At present the Zend_Loader::loadClass() method (used by Zend_Loader::autoload()) causes a PHP file not found warning if it cannot include the requested class. (Line 83)

Comments

One obvious solution is to change the {{autoload()}} method to suppress errors on the call to {{self::loadClass()}}, but what happens when the file does exist, and it has a parse error or a warning that the developer should see? Such error suppression solves one problem while causing other potential problems. The complexity of dealing with PHP errors here is a bit like a waterbed... if you push down one side, the other side pops up.

The next step would be to capture the errors and make them available to the calling script (except fatal errors of course), but this may be a performance hog. We'll need some tests and benchmarks, I think.

Maybe someone else has a better idea?

So we have four options:

  1. Don't check the file exists before inclusion and get errors when not found
  2. Don't check the file exists before inclusion and suppress all errors, including parse errors
  3. Don't check the file exists before inclusion but somehow catch the PHP file not found warning and suppress it, at the cost of performance
  4. Check the file exists before inclusion, at the cost of performance

None of them are ideal really. For the time being I've settled on option 4 for my workaround. Although I've got no idea on the actual performance impact of this.

Please see SVN r8903 as a possible solution.

Of course, this solution also suppresses any such "file not found" warnings from user code, such as in the following:


Zend_Loader::registerAutoload();
$foo = new Foo();

In Foo.php:


include_once 'Foo/Exception.php';
class Foo
{}

If '{{Foo/Exception.php}}' is not found, then the warnings generated by this user code are invisible.

We could augment the solution with an accumulation of such warnings rather than suppressing them altogether into the void. I'll commit another version that does this shortly.

Please see SVN 8904 for the augmented solution.

I've just run some (fairly unscientific) benchmarks on my standard application skeleton, here's the results:

Average load time in seconds based on 10 requests:

Using simple error suppression on the include_once (@): 0.3055 Checking file exists before inclusion (Zend_Loader::isReadable()): 0.3442 Using the new error suppression method in incubator: 0.3086

So, there's practically no performance hit with the new method. Looks good to me.

You make a good point regarding the inclusion of other files, but I see that as less of an issue. I guess you could always change the regex in suppressFileNotFoundWarnings() to look for the file name as well, so that only errors related to that file are suppressed? Mind you, you can't parse anything to the error handler can you? So I guess it would complicated things further.

I resolved ZF-2985 today. Please tell me if ZF-2985 causes something wrong.

Resolved in trunk in r12769. However, this is a slight change in behavior, and cannot be released until the next minor release (1.8.0).

Matthew is this still on track to be released in 1.8.0?

Yes -- Zend_Loader_Autoloader is complete in the incubator, and just needs to be documented before I push it to trunk, and that offers the most comprehensive solution.