FAQ
Hi,

I didn't mark http://bugs.php.net/48541 as critical because it is not a
critical bug, but it is critical that this thing be fixed in PHP 5.3.

I can do it if someone can answer this question: how do closures
uniquely identify themselves? spl_autoload_register is mistakenly
treating all closures as if they were a single copy of the static method
"Closure::__invoke", and so only the first registered closure is ever
called (plus it leaks the other closures at shutdown). If the system
can be made to better identify the closure, then spl_autoload_register
can use that (and also properly free the refcount on a dupe).

Greg

Search Discussions

  • Christian Seiler at Jun 13, 2009 at 11:18 am
    Hi Greg,
    I can do it if someone can answer this question: how do closures
    uniquely identify themselves? spl_autoload_register is mistakenly
    treating all closures as if they were a single copy of the static method
    "Closure::__invoke", and so only the first registered closure is ever
    called (plus it leaks the other closures at shutdown). If the system
    can be made to better identify the closure, then spl_autoload_register
    can use that (and also properly free the refcount on a dupe).
    A closure can only be uniquely identified by the object storage id the
    object has. You cannot assume any identity with regard to, for example,
    file name and line where it was defined, since one could imagine the
    following:

    foreach ($dirs as $dir) {
    spl_autoload_register (function ($class) use ($dir) {
    include $dir.'/'.$class.'.php';
    });
    }

    (or something like it)

    If nobody else does it I'll fix this later today.

    Regards,
    Christian
  • Greg Beaver at Jun 13, 2009 at 4:50 pm

    Christian Seiler wrote:
    Hi Greg,
    I can do it if someone can answer this question: how do closures
    uniquely identify themselves? spl_autoload_register is mistakenly
    treating all closures as if they were a single copy of the static method
    "Closure::__invoke", and so only the first registered closure is ever
    called (plus it leaks the other closures at shutdown). If the system
    can be made to better identify the closure, then spl_autoload_register
    can use that (and also properly free the refcount on a dupe).
    A closure can only be uniquely identified by the object storage id the
    object has. You cannot assume any identity with regard to, for example,
    file name and line where it was defined, since one could imagine the
    following:

    foreach ($dirs as $dir) {
    spl_autoload_register (function ($class) use ($dir) {
    include $dir.'/'.$class.'.php';
    });
    }

    (or something like it)

    If nobody else does it I'll fix this later today.
    Hi,

    Thanks Christian, I've got a patch and a test I'm about to commit, would
    be great if you can review it.

    Thanks,
    Greg
  • Christian Seiler at Jun 13, 2009 at 5:55 pm
    Hi Greg,
    (I meant commit when I said patch, sorry :)

    http://news.php.net/php.cvs/58696
    and
    http://news.php.net/php.cvs/58697
    Thanks, looks fine to me. However, I noticed that closures don't work
    with spl_autoload_unregister() and spl_autoload_functions(). Also,
    classes that define __invoke work with spl_autoload_functions() but not
    with spl_autoload_unregister() - unless array ($o, '__invoke') is given
    to spl_autoload_register() directly, then the same will work for unregister.

    Or, to sum it up:

    i) Real Closures

    $c = function ($class) { var_dump ('foo'); }
    spl_autoload_register ($c);

    var_dump (spl_autoload_functions ()); // '{closure}'

    spl_autoload_unregister ($c); // no effect

    ii) Invokables

    WORKS:

    <?php

    class Autoloader {
    private $dir;
    public function __construct ($dir) {
    $this->dir = $dir;
    }
    public function __invoke ($class) {
    var_dump ("{$this->dir}/$class.php");
    }
    }

    $al1 = new Autoloader ('d1');
    $al2 = new Autoloader ('d2');

    spl_autoload_register (array ($al1, '__invoke'));
    spl_autoload_register (array ($al2, '__invoke'));

    var_dump (spl_autoload_functions ());

    spl_autoload_unregister (array ($al1, '__invoke'));

    $x = new Test;

    ?>

    SEMI-WORKS:

    <?php

    class Autoloader {
    private $dir;
    public function __construct ($dir) {
    $this->dir = $dir;
    }
    public function __invoke ($class) {
    var_dump ("{$this->dir}/$class.php");
    }
    }

    $al1 = new Autoloader ('d1');
    $al2 = new Autoloader ('d2');

    spl_autoload_register ($al1);
    spl_autoload_register ($al2);

    var_dump (spl_autoload_functions ());
    // gives array ($object, '__invoke') instead of
    // directly $object - but that's at least equivalent

    spl_autoload_unregister ($al1);
    // no effect
    spl_autoload_unregister (array ($al1, '__invoke'));
    // no effect

    $x = new Test;

    ?>

    Regards,
    Christian
  • Greg Beaver at Jun 13, 2009 at 6:12 pm

    Christian Seiler wrote:
    Hi Greg,

    (I meant commit when I said patch, sorry :)

    http://news.php.net/php.cvs/58696
    and
    http://news.php.net/php.cvs/58697
    Thanks, looks fine to me. However, I noticed that closures don't work
    with spl_autoload_unregister() and spl_autoload_functions(). Also,
    classes that define __invoke work with spl_autoload_functions() but not
    with spl_autoload_unregister() - unless array ($o, '__invoke') is given
    to spl_autoload_register() directly, then the same will work for unregister.
    Hi,

    I first replied off-list accidentally. I wonder if the problem is that
    spl_autoload_register should not just be checking to see if zcallable is
    IS_OBJECT, but also if it is an instance of Closure. That should clear
    up the examples below (spl_autoload_register($blah) where $blah is not a
    closure should not work). spl_autoload_unregister probably just needs a
    cut/paste of the code I committed to spl_autoload_register for munging a
    closure name with the addition of Closure instanceof check.

    Also, those examples would make great .phpt tests :).

    Greg
    Or, to sum it up:

    i) Real Closures

    $c = function ($class) { var_dump ('foo'); }
    spl_autoload_register ($c);

    var_dump (spl_autoload_functions ()); // '{closure}'

    spl_autoload_unregister ($c); // no effect

    ii) Invokables

    WORKS:

    <?php

    class Autoloader {
    private $dir;
    public function __construct ($dir) {
    $this->dir = $dir;
    }
    public function __invoke ($class) {
    var_dump ("{$this->dir}/$class.php");
    }
    }

    $al1 = new Autoloader ('d1');
    $al2 = new Autoloader ('d2');

    spl_autoload_register (array ($al1, '__invoke'));
    spl_autoload_register (array ($al2, '__invoke'));

    var_dump (spl_autoload_functions ());

    spl_autoload_unregister (array ($al1, '__invoke'));

    $x = new Test;

    ?>

    SEMI-WORKS:

    <?php

    class Autoloader {
    private $dir;
    public function __construct ($dir) {
    $this->dir = $dir;
    }
    public function __invoke ($class) {
    var_dump ("{$this->dir}/$class.php");
    }
    }

    $al1 = new Autoloader ('d1');
    $al2 = new Autoloader ('d2');

    spl_autoload_register ($al1);
    spl_autoload_register ($al2);

    var_dump (spl_autoload_functions ());
    // gives array ($object, '__invoke') instead of
    // directly $object - but that's at least equivalent

    spl_autoload_unregister ($al1);
    // no effect
    spl_autoload_unregister (array ($al1, '__invoke'));
    // no effect

    $x = new Test;

    ?>

    Regards,
    Christian
  • Christian Seiler at Jun 13, 2009 at 8:26 pm
    Hi,

    [quote from off-list:]
    I am in way over my head and would not do a good job
    fixing these (or have the time), care to take a crack at it?
    Ok, I'll do that tomorrow morning.
    I wonder if the problem is that
    spl_autoload_register should not just be checking to see if zcallable is
    IS_OBJECT, but also if it is an instance of Closure. That should clear
    up the examples below (spl_autoload_register($blah) where $blah is not a
    closure should not work).
    No, actually it should definitely work, since $blah () works when the
    class defined __invoke and objects of this class are thus callable.

    Regards,
    Christian

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedJun 13, '09 at 6:14a
activeJun 13, '09 at 8:26p
posts6
users2
websitephp.net

2 users in discussion

Greg Beaver: 3 posts Christian Seiler: 3 posts

People

Translate

site design / logo © 2021 Grokbase