php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76980 Interface gets skipped if autoloader throws an exception
Submitted: 2018-10-06 21:38 UTC Modified: 2019-07-12 14:48 UTC
Votes:15
Avg. Score:4.1 ± 0.9
Reproduced:8 of 12 (66.7%)
Same Version:8 (100.0%)
Same OS:5 (62.5%)
From: martin at auswoeger dot com Assigned: nikic (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 7.2.10 OS:
Private report: No CVE-ID: None
 [2018-10-06 21:38 UTC] martin at auswoeger dot com
Description:
------------
If a class implements an interface for which the registered autoloader throws an exception, the class is actually defined afterwards but without the interface.

Test script:
---------------
<?php

spl_autoload_register(function ($class) {
    if ('Foo' === $class) {
        class Foo implements Foointerface {}
    } elseif ('Foointerface' === $class) {
        throw new Exception();
    }
});

try {
    // First call triggers the autoloader
    new Foo();
} catch (Exception $e) {}

// For the second call Foo is loaded
var_dump(new Foo());

// Even though it’s missing the interface
var_dump(new Foo() instanceof Foointerface);
var_dump((new ReflectionClass('Foo'))->getInterfaces());

Expected result:
----------------
Fatal error: Uncaught Exception in …  
thrown in … on line 7

Actual result:
--------------
object(Foo)#3 (0) {
}
bool(false)
array(0) {
}

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-10-06 21:56 UTC] requinix@php.net
What's the expected *behavior* here? That Foo should not be defined at all since the interface couldn't be loaded? And the second "load" of Foo trigger the autoloader again and raise the exception again?
I think the way it works now is fine: Foo could be mostly defined except the interface, there was no other problem with it, and PHP was quite happy to raise an exception which you totally ignored. At least this way the code has a chance of working.

Or what if the exception was actually an Error? It's semantics, but that way you wouldn't accidentally catch it.
 [2018-10-06 22:17 UTC] nikic@php.net
> What's the expected *behavior* here? That Foo should not be defined at all since the interface couldn't be loaded?

Yes, that would be the expected behavior.

Master has some changes that should make it easier to correctly handle this. Right now the code segfaults though.
 [2018-10-06 22:24 UTC] martin at auswoeger dot com
A partial loaded class is very confusing I think. Most developers probably wouldn’t expect that a class can be loaded without its interfaces.

> What's the expected *behavior* here?

If you change the above test script from `implements` to `extends` it behaves as I would expect it.

There is also a Symfony bug report that shows a real world use case where this behavior was unexpected and causes issues: <https://github.com/symfony/symfony/issues/28748>
 [2018-10-07 01:28 UTC] a at b dot c dot de
Allowing the creation of class Foo to go ahead even if its interface failed to autoload would also bite users who use type declarations in function signatures.

<?php
function dowithfoo(Foointerface $foo)
{
	return;
}

dowithfoo(new Foo());
?>
 [2018-10-09 12:13 UTC] cmb@php.net
-Status: Open +Status: Verified -Package: *General Issues +Package: Scripting Engine problem
 [2018-10-09 12:13 UTC] cmb@php.net
For reference: <https://3v4l.org/s8ti7>
 [2019-05-15 10:50 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=35353dc49a73a58c17c7896c4c4c3997ef2c007d
Log: Fixed bug #76980
 [2019-05-15 10:50 UTC] nikic@php.net
-Status: Verified +Status: Closed
 [2019-07-09 09:07 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=22ed362810c1b3a5ecb54ebd1d50d804c7fc3159
Log: Revert &quot;Fixed bug #76980&quot;
 [2019-07-12 14:44 UTC] pierre dot rineau at makina-corpus dot com
Is that possible that this issue resolution created some regressions ? I'm working with a Symfony application, and since the php 7.2.19 -> 7.2.20 upgrade (on CentOS 7, using Remi repository) Symfony cannot catch \ReflexionException anymore.

I'm trying to reproduce it with a simpler use case, I'll come back at you if I succeed in reproducing it.
 [2019-07-12 14:48 UTC] nikic@php.net
-Assigned To: +Assigned To: nikic
 [2019-07-12 14:48 UTC] nikic@php.net
@pierre: You are looking for https://github.com/symfony/symfony/issues/32395. See especially https://github.com/symfony/symfony/issues/32395#issuecomment-509726046 if you need a quick workaround. (This is unrelated to this particular issue though, which is a change in PHP 7.3 only.)
 [2019-07-12 15:06 UTC] pierre dot rineau at makina-corpus dot com
@nikic Yes I manage to find this issue after I posted my original comment, I started here because it was manifesting itself after the php upgrade.

Thanks a lot.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 17:01:29 2024 UTC