php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65317 spl autoload won't work inside an autoload
Submitted: 2013-07-23 16:26 UTC Modified: 2013-07-24 08:57 UTC
From: tyrael@php.net Assigned:
Status: Duplicate Package: Scripting Engine problem
PHP Version: 5.4.17 OS: linux
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 you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: tyrael@php.net
New email:
PHP Version: OS:

 

 [2013-07-23 16:26 UTC] tyrael@php.net
Description:
------------
I just bumped into an issue, where we had a Strict error triggered about an 
abstract class, which caused our autoloader to fail.
It seems that the autoloader won't be called when you try to reference a not-yet-
loaded class from an error handler triggered by an autoloader function.
I think that the attached test script makes the scenario more clear(sorry for the 
eval part, I didn't wanted to upload multiple scripts), but feel free to ask me if 
you need more info.

ps: it seems that this never worked http://3v4l.org/AQCue but I couldn't find any 
previous reports or notes/docs on the topic.

Test script:
---------------
<?php
spl_autoload_register(function($class){
        if ($class == 'MyConcrete') {
                eval('
                        class MyConcrete extends MyAbstract {
                                public static function createInstance() {}
                        }
                ');
        } elseif ($class == 'MyAbstract') {
                eval('
                        abstract class MyAbstract {
                                public abstract static function createInstance();
                        }
                ');
        } else {
                eval('class '.$class.'{}');
        }
});

set_error_handler(function($errno, $errstr, $errfile, $errline){
        $myclass = new MyClass;
});

$concrete = new MyConcrete;
$myclass = new MyClass;

Expected result:
----------------
trigger the autoloader from the error handler and load the class

Actual result:
--------------
Fatal error: Class 'MyClass' not found in index.php(14) : eval()'d code on line 3

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-07-23 16:51 UTC] laruence@php.net
Hey, it should be a intention behavior:


zend_class_entry *zend_fetch_class_by_name(const char *class_name, uint 
class_name_len, const zend_literal *key, int fetch_type TSRMLS_DC) /* {{{ */
{
    zend_class_entry **pce;
    int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0;


it seems try to prevent some recursive autoload, then stack overflow 

so.... won't fix IMO (it's really a edge case :))

maybe document it instead?

thanks
 [2013-07-23 17:05 UTC] tyrael@php.net
it was introduced by Dmitry:
http://git.php.net/?p=php-
src.git;a=commitdiff;h=9305339d94c701e8eda93dbf0231d70918ef4a6a
"Changed "instanceof" and "catch" operators, is_a() and is_subclass_of() 
functions to not call __autoload()."

so nothing about generic recursion protection or explicitly talking about calls 
from another autloader method.
I would guess this specific scenario wasn't really intentional, but let's ask 
Dmitry about his thoughts.

Personally I think that it is rather surprising and unintuitive and it was a 
little bit tricky to figure it out why the code didn't worked as I've expected.
 [2013-07-23 17:09 UTC] laruence@php.net
my previous comment is not right.

it real reason is here, in (zend_lookup_class_ex):


    /* The compiler is not-reentrant. Make sure we __autoload() only during run-
time
     * (doesn't impact fuctionality of __autoload()
    */
    if (!use_autoload || zend_is_compiling(TSRMLS_C)) {
        if (!key) {
            free_alloca(lc_free, use_heap);
        }
        return FAILURE;
    }


so, the error is trigged in compiling MyAbstract... 

so is in compile time...

so,,
 [2013-07-23 17:13 UTC] tyrael@php.net
hm, that explains why nobody really reported it.
as far as I can remember most compile time errors are fatal which won't trigger 
the error handler anyways, and the others are E_STRICT, which wasn't really used 
before we included it to E_ALL in 5.4.
maybe we should reconsider adding new compile time non-fatal errors until we can 
properly support it?
 [2013-07-23 17:29 UTC] tyrael@php.net
Btw. isn't the fact that the error handler is called proves that the compiler is eiher reentrants or 
that the compilation is done?
 [2013-07-24 06:21 UTC] tyrael@php.net
-Package: SPL related +Package: Scripting Engine problem
 [2013-07-24 08:57 UTC] tyrael@php.net
-Status: Open +Status: Duplicate
 [2013-07-24 08:57 UTC] tyrael@php.net
I've created a new report with the updated info and testcase to avoid confusion, 
see https://bugs.php.net/bug.php?id=65322
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Oct 12 21:01:26 2024 UTC