php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login go to bug id or search bugs for
Bug #52339 SPL autoloader breaks class_exists()
Submitted: 2010-07-14 21:31 UTC Modified: 2015-09-08 20:14 UTC
Votes: 35 4.4 ± 0.9 31 of 33 (93.9%) 12 (38.7%) 15 (48.4%)
From: dangerous dot ben at gmail dot com Assigned:
Status: Closed Package: SPL related
PHP Version: 5.3.3RC2 OS: any (debian)
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
 Password:
Status: Closed Assigned General Issues Filter related JIT (Just In Time compilation) Opcache Output Control Performance problem PHAR related PHP-GTK related PHP.net Systems Operation problem PHP.net Website problem Reflection related Reproducible crash Scripting Engine problem Session related SPL related Streams related Testing related PDO related PDO Core PDO DBlib PDO Firebird PDO MySQL PDO OCI PDO ODBC PDO PgSQL PDO SQLite Compile Issues Compile Failure Compile Warning Configuration Issues Dynamic loading PHP options/info functions Safe Mode/open_basedir related Windows Installer related Web Server problem Apache related Apache2 related CGI/CLI related FPM related IIS related iPlanet related Other web server PHP built-in web server related PWS related Servlet related Calendar problems Calendar related Date/time related Compression related Bzip2 Related Zip Related Zlib related Directory/Filesystem functions Directory function related Filesystem function related Directory Services problems LDAP related Database Functions Adabas-D related DBM/DBA related DBX related FrontBase related Ingres II related InterBase related mSQL related MSSQL related MySQL related MySQLi related OCI8 related ODBC related Oracle related PostgreSQL related Solid related SQLite related Sybase-ct (ctlib) related Data Exchange functions JSON related WDDX related Extensibility Functions COM related FFI (Foreign Function Interface) Java related ncurses related PCNTL related POSIX functions related Program Execution Readline related Semaphore related Win32API related Graphics related EXIF related GD related GetImageSize related Ming related Languages/Translation Gettext related ICONV related MBstring related Recode related Mail Related IMAP related mail function related Math Functions BC math related GNU MP related Math related Encryption and hash functions hash related mcrypt related mhash related OpenSSL related Network Functions FTP related HTTP related Network related SNMP related Sockets related PDF functions PDF related Programming Data Structures Arrays related Class/Object related Strings related Variables related Regular Expressions PCRE related Regexps related Spelling functions Enchant related Pspell related XML functions DOM XML related SimpleXML related SOAP related Tidy XML Reader XML related XML Writer XMLRPC-EPI related XSLT related URL Functions cURL related URL related Unicode Issues I18N and L10N related Unicode Engine related Unknown/Other Function phpdbg PECL PDO_INFORMIX BugFeature/Change RequestDocumentation ProblemSecurity dangerous dot ben at gmail dot com

[2010-07-14 21:31 UTC] dangerous dot ben at gmail dot com
Description:
------------
Using PHP 5.3 from svn.

When SPL's default autoloader is the only loader in the stack it triggers an error or throws an exception when it can't find a class.  This means that you get an exception when calling class_exists() for a class that doesn't exist.  This behaviour seems pointless anyway since PHP will trigger its own fatal error if the class still doesn't exist after attempting to autoload, so the attached patch simply removes it.

Test script:
---------------
spl_autoload_register();
class_exists('foo\bar');

Expected result:
----------------
No error

Actual result:
--------------
ben@arctor:~/src/php-5.3$sapi/cli/php ~/code/cram/test.php PHP Fatal error: Uncaught exception 'LogicException' with message 'Class foo\bar could not be loaded' in /home/ben/code/cram/test.php:4 Stack trace: #0 [internal function]: spl_autoload('foo\bar') #1 /home/ben/code/cram/test.php(4): class_exists('foo\bar') #2 {main} thrown in /home/ben/code/cram/test.php on line 4  ## Patches spl_autoload.patch (last revision 2010-07-14 19:32 UTC by dangerous dot ben at gmail dot com) Add a Patch ## Pull Requests Add a Pull Request ## History AllCommentsChangesGit/SVN commitsRelated reports [2010-07-14 21:54 UTC] dangerous dot ben at gmail dot com On further investigation, it appears that the error is meant to happen only if spl_autoload is called directly, and not via spl_autoload_call. Unfortunately when spl_autoload is the only autoloader in the stack it gets called directly and spl_autoload_call doesn't get a look in.  [2010-07-15 05:11 UTC] kalle@php.net -Status: Open +Status: Bogus [2010-07-15 05:11 UTC] kalle@php.net You are calling class_exists() with just a class name, which leaves the second parameter ($autoload) set to true, which then invokes SPL and throws the exception, so no bug here

[2010-07-15 08:18 UTC] dangerous dot ben at gmail dot com
I beg to differ.  As you say, class_exists() attempts to autoload if there second param is true, but if autoloading fails it should simply return false as usual rather than throw an exception.  Otherwise it is rather useless.

The fact that this only occurs when there isn't another autoloader in the stack should make it clear that this is a bug.  For example, the following code does not throw an exception:

spl_autoload_register();
spl_autoload_register(function(){});
class_exists('foo\bar');

[2010-10-11 21:37 UTC] james at nearlysensical dot com
I 100% agree with dangerous dot ben. class_exists should return false if the class
can't be autoloaded. Allowing it to do so would make it much easier to use an
autoloader in contexts where you're interacting with an existing codebase that may
not be so spl_autoload friendly. Bump.

[2012-02-03 00:01 UTC] frozenfire@php.net
-Status: Not a bug +Status: Re-Opened
[2012-02-03 00:01 UTC] frozenfire@php.net
Re-opening, as there still exists the conflict of class_exists() generating an
error when autoloading fails, which is a chicken and the egg sort of issue. If
one wants to try autoloading if the class doesn't exist, but autoloading fails,
it should be possible to recover from that failure.

My understanding of the underlying code is that it generates an error in this
case. Perhaps it should generate an exception, which can be caught an handled.

[2012-03-16 22:02 UTC] pwolfenden at qualys dot com
Although I have not yet migrated to 5.3, I care about this bug because I'm using
an autoload function (in 5.2) which contains some directory traversal logic and
uses class_exists() to decide whether or not to keep looking. I need to do this
because I'm in the scenario described by james (and so cannot assume that all the
package files in my codebase follow my preferred naming convention), and I would
much prefer class_exists() to continue to return false rather than having it throw
a new Exception.

[2012-08-08 16:02 UTC] kilbyc at bellsouth dot net
PHP 5.3.8 (cli) (built: Aug 23 2011 11:50:20)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies
<?php
print_r(class_exists('asdfasdf'));//no error, just false
spl_autoload_register();
print_r(class_exists('asdfasdf'));//LogicException.
?>

<?php
class_exists('asdfasdf');//no error, just false.
spl_autoload_register('spl_autoload');
class_exists('asdfasdf');//no error, just false.
?>

spl_autoload is inconsistent with itself.

[2012-08-08 16:18 UTC] kilbyc at bellsouth dot net
Even worse. The no arg register is inconsistent.
<?php
print_r(class_exists('asdfasdf'));//no error, just false.
spl_autoload_register();
print_r(class_exists('asdfasdf'));//LogicException
?>

<?php
print_r(class_exists('asdfasdf'));//no error, just false.
spl_autoload_register('spl_autoload');
spl_autoload_unregister('spl_autoload');
spl_autoload_register();
print_r(class_exists('asdfasdf'));//no error, just false.
?>
If the autoload stack is empty by the time the no arg registered is called, how can it function differently than if the autoload stack has been emptied by the time the no arg register is called?

This is nonsensical behavior, and manual for spl_autoload say nothing about it throwing. Let alone LogicException. I would have expected this to be a RuntimeException. As it depends on the specific environment it is run in as to whether or not spl_autoload will find something.

[2012-11-24 20:29 UTC] ciantic at oksidi dot com
Is this bug still happening in PHP5.4 and greater? I'm using 5.3.8.

If one uses class_exists it should never throw error, only true or false. It makes
no sense otherwise. This is one of those where setting of some other application
can totally broke functionality elsewhere. Should everyone using class_exists
catch try LogicException too? I'd argue not.

Though the workaround (empty function for spl) is kind of nice, as dangerous dot
ben mentioned.

[2013-01-17 13:41 UTC] php at maisqi dot com
This is clearly a bug. We're testing if a class exists not asserting it.
There's seam to be a patch for this. Any chance it will be accepted?

[2014-01-13 12:34 UTC] matthew dot bonner at gmail dot com
Still broke in 5.4 and 5.5 3 years on!

[2014-10-08 06:51 UTC] john dot fragkoulis at gmail dot com
v5.5.3 still broken

[2014-10-13 10:33 UTC] aden at fraserjilani dot com
v5.5.9 - still broken.

[2015-09-08 20:14 UTC] cmb@php.net
> My understanding of the underlying code is that it generates an
> error in this case. Perhaps it should generate an exception,
> which can be caught an handled.

The code already throws an exception, see <https://3v4l.org/AaURG>.

[2015-09-08 20:22 UTC] cmb@php.net
Automatic comment from SVN on behalf of cmb
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=337786
Log: spl_autoload() may throw LogicException (related to #52339)

[2015-09-09 18:35 UTC] matthew dot bonner at gmail dot com
It shouldn't throw an exception or cause an error. This is exactly why people move to C# because we don't have to put up with any of this bullshit for 5 years. An exception should be thrown when something happens that is not expected to happen, you expect class_exists to return false when the class does not exist, it is bonkers to think that we want to be wasting our lives catching stupid exceptions that should not be thrown in the first place, either that or catch the bloody exception in the body of the class_exists function for crying out loud. How hard is it really?

[2015-09-09 20:20 UTC] wolfen at gmail dot com
I echo the sentiments of matthew dot bonner if not his choice of words. If the purpose of class_exists() is to indicate whether or not a given class has been defined in the current scope or loaded into the current scope via include/require directives, then I simply cannot imagine a scenario in which it is acceptable for this function to throw an Exception.

[2016-03-18 19:30 UTC] nikic@php.net
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8023204d219d353b83f19edb0133483d67aedcfb
Log: Fixed bug #52339

[2016-03-18 19:30 UTC] nikic@php.net
-Status: Re-Opened +Status: Closed
[2016-07-20 11:32 UTC] davey@php.net
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8023204d219d353b83f19edb0133483d67aedcfb
Log: Fixed bug #52339

 Copyright © 2001-2022 The PHP Group All rights reserved. Last updated: Mon Jan 17 23:03:42 2022 UTC