Hi Lukas,

> If issues are found/fixed please send the patches to internals for
> review. Based on the importance and risk of the patch will then be
> applied, however the next 2 days should really be focused on testing to
> make sure we do not have critical issues, minor issues can always be
> fixed in 5.3.1 and we better release with known minor issues than big
> unknown issues caused by a last minute fix.

I have a minor issue with regard to spl_autoload_unregister /
spl_autoload_functions and closures in my backlog. I already committed
the patch & tests to HEAD [1]. I see this as extremely minor (since
spl_autoload_register was fixed a while ago and that is the only
*really* important use case in my eyes) so I'm perfectly happy to wait
until after 5.3.0 to merge it from HEAD. But just in case I've attached
the patch for 5.3 (NEWS file update not included in patch).

[1] http://news.php.net/php.cvs/58900

Regards,
Christian
Index: ext/spl/php_spl.c
===================================================================
RCS file: /repository/php-src/ext/spl/php_spl.c,v
retrieving revision 1.52.2.28.2.17.2.38
diff -u -p -r1.52.2.28.2.17.2.38 php_spl.c
--- ext/spl/php_spl.c   13 Jun 2009 17:30:50 -0000      1.52.2.28.2.17.2.38
+++ ext/spl/php_spl.c   22 Jun 2009 18:14:56 -0000
@@ -509,10 +509,10 @@ PHP_FUNCTION(spl_autoload_register)
                        alfi.closure = zcallable;
                        Z_ADDREF_P(zcallable);
 
-                       lc_name = erealloc(lc_name, func_name_len + 2 + 
sizeof(zcallable->value.obj.handle));
-                       memcpy(lc_name + func_name_len, 
&(zcallable->value.obj.handle),
-                               sizeof(zcallable->value.obj.handle));
-                       func_name_len += sizeof(zcallable->value.obj.handle);
+                       lc_name = erealloc(lc_name, func_name_len + 2 + 
sizeof(zend_object_handle));
+                       memcpy(lc_name + func_name_len, 
&Z_OBJ_HANDLE_P(zcallable),
+                               sizeof(zend_object_handle));
+                       func_name_len += sizeof(zend_object_handle);
                        lc_name[func_name_len] = '\0';
                }
 
@@ -579,6 +579,7 @@ PHP_FUNCTION(spl_autoload_unregister)
 {
        char *func_name, *error = NULL;
        int func_name_len;
+       char *lc_name = NULL;
        zval *zcallable;
        int success = FAILURE;
        zend_function *spl_func_ptr;
@@ -604,10 +605,20 @@ PHP_FUNCTION(spl_autoload_unregister)
                efree(error);
        }
 
-       zend_str_tolower(func_name, func_name_len);
+       lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1);
+       zend_str_tolower_copy(lc_name, func_name, func_name_len);
+       efree(func_name);
+
+       if (Z_TYPE_P(zcallable) == IS_OBJECT) {
+               lc_name = erealloc(lc_name, func_name_len + 2 + 
sizeof(zend_object_handle));
+               memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable),
+                       sizeof(zend_object_handle));
+               func_name_len += sizeof(zend_object_handle);
+               lc_name[func_name_len] = '\0';
+       }
 
        if (SPL_G(autoload_functions)) {
-               if (func_name_len == sizeof("spl_autoload_call")-1 && 
!strcmp(func_name, "spl_autoload_call")) {
+               if (func_name_len == sizeof("spl_autoload_call")-1 && 
!strcmp(lc_name, "spl_autoload_call")) {
                        /* remove all */
                        zend_hash_destroy(SPL_G(autoload_functions));
                        FREE_HASHTABLE(SPL_G(autoload_functions));
@@ -616,16 +627,16 @@ PHP_FUNCTION(spl_autoload_unregister)
                        success = SUCCESS;
                } else {
                        /* remove specific */
-                       success = zend_hash_del(SPL_G(autoload_functions), 
func_name, func_name_len+1);
+                       success = zend_hash_del(SPL_G(autoload_functions), 
lc_name, func_name_len+1);
                        if (success != SUCCESS && obj_ptr) {
-                               func_name = erealloc(func_name, func_name_len + 
1 + sizeof(zend_object_handle));
-                               memcpy(func_name + func_name_len, 
&Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
+                               lc_name = erealloc(lc_name, func_name_len + 2 + 
sizeof(zend_object_handle));
+                               memcpy(lc_name + func_name_len, 
&Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
                                func_name_len += sizeof(zend_object_handle);
-                               func_name[func_name_len] = '\0';
-                               success = 
zend_hash_del(SPL_G(autoload_functions), func_name, func_name_len+1);
+                               lc_name[func_name_len] = '\0';
+                               success = 
zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1);
                        }
                }
-       } else if (func_name_len == sizeof("spl_autoload")-1 && 
!strcmp(func_name, "spl_autoload")) {
+       } else if (func_name_len == sizeof("spl_autoload")-1 && 
!strcmp(lc_name, "spl_autoload")) {
                /* register single spl_autoload() */
                zend_hash_find(EG(function_table), "spl_autoload", 
sizeof("spl_autoload"), (void **) &spl_func_ptr);
 
@@ -635,7 +646,7 @@ PHP_FUNCTION(spl_autoload_unregister)
                }
        }
 
-       efree(func_name);
+       efree(lc_name);
        RETURN_BOOL(success == SUCCESS);
 } /* }}} */
 
@@ -663,7 +674,10 @@ PHP_FUNCTION(spl_autoload_functions)
                zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), 
&function_pos);
                while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), 
&function_pos) == SUCCESS) {
                        
zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, 
&function_pos);
-                       if (alfi->func_ptr->common.scope) {
+                       if (alfi->closure) {
+                               Z_ADDREF_P(alfi->closure);
+                               add_next_index_zval(return_value, 
alfi->closure);
+                       } else if (alfi->func_ptr->common.scope) {
                                zval *tmp;
                                MAKE_STD_ZVAL(tmp);
                                array_init(tmp);
Index: ext/spl/tests/spl_autoload_013.phpt
===================================================================
RCS file: ext/spl/tests/spl_autoload_013.phpt
diff -N ext/spl/tests/spl_autoload_013.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ext/spl/tests/spl_autoload_013.phpt 22 Jun 2009 18:14:58 -0000
@@ -0,0 +1,51 @@
+--TEST--
+SPL: spl_autoload_functions() with closures and invokables
+--FILE--
+<?php
+$closure = function($class) {
+  echo "a called\n";
+};
+
+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($closure);
+spl_autoload_register($al1);
+spl_autoload_register($al2);
+
+var_dump(spl_autoload_functions());
+
+?>
+===DONE===
+--EXPECTF--
+array(3) {
+  [0]=>
+  object(Closure)#%d (1) {
+    ["parameter"]=>
+    array(1) {
+      ["$class"]=>
+      string(10) "<required>"
+    }
+  }
+  [1]=>
+  object(Autoloader)#%d (1) {
+    ["dir":"Autoloader":private]=>
+    string(2) "d1"
+  }
+  [2]=>
+  object(Autoloader)#%d (1) {
+    ["dir":"Autoloader":private]=>
+    string(2) "d2"
+  }
+}
+===DONE===
\ No newline at end of file
Index: ext/spl/tests/spl_autoload_014.phpt
===================================================================
RCS file: ext/spl/tests/spl_autoload_014.phpt
diff -N ext/spl/tests/spl_autoload_014.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ext/spl/tests/spl_autoload_014.phpt 22 Jun 2009 18:14:58 -0000
@@ -0,0 +1,47 @@
+--TEST--
+SPL: spl_autoload_unregister() with closures and invokables
+--FILE--
+<?php
+$closure = function($class) {
+  echo "closure called with class $class\n";
+};
+
+class Autoloader {
+  private $dir;
+  public function __construct($dir) {
+    $this->dir = $dir;
+  }
+  public function __invoke($class) {
+    echo ("Autoloader('{$this->dir}') called with $class\n");
+  }
+}
+
+class WorkingAutoloader {
+  public function __invoke($class) {
+    echo ("WorkingAutoloader() called with $class\n");
+    eval("class $class { }");
+  }
+}
+
+$al1 = new Autoloader('d1');
+$al2 = new WorkingAutoloader('d2');
+
+spl_autoload_register($closure);
+spl_autoload_register($al1);
+spl_autoload_register($al2);
+
+$x = new TestX;
+
+spl_autoload_unregister($closure);
+spl_autoload_unregister($al1);
+
+$y = new TestY;
+
+?>
+===DONE===
+--EXPECT--
+closure called with class TestX
+Autoloader('d1') called with TestX
+WorkingAutoloader() called with TestX
+WorkingAutoloader() called with TestY
+===DONE===
\ No newline at end of file
Index: ext/spl/tests/spl_autoload_bug48541.phpt
===================================================================
RCS file: /repository/php-src/ext/spl/tests/spl_autoload_bug48541.phpt,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 spl_autoload_bug48541.phpt
--- ext/spl/tests/spl_autoload_bug48541.phpt    13 Jun 2009 17:30:50 -0000      
1.1.2.2
+++ ext/spl/tests/spl_autoload_bug48541.phpt    22 Jun 2009 18:14:58 -0000
@@ -2,23 +2,38 @@
 SPL: spl_autoload_register() Bug #48541: registering multiple closures fails 
with memleaks
 --FILE--
 <?php
+
+class X {
+  public function getClosure() {
+    return function($class) {
+      echo "a2 called\n";
+    };
+  }
+}
+
 $a = function ($class) {
     echo "a called\n";
 };
+$x = new X;
+$a2 = $x->getClosure();
 $b = function ($class) {
     eval('class ' . $class . '{function __construct(){echo "foo\n";}}');
     echo "b called\n";
 };
 spl_autoload_register($a);
+spl_autoload_register($a2);
 spl_autoload_register($b);
 
 $c = $a;
+$c2 = $a2;
 spl_autoload_register($c);
+spl_autoload_register($c2);
 $c = new foo;
 ?>
 ===DONE===
 --EXPECT--
 a called
+a2 called
 b called
 foo
 ===DONE===
\ No newline at end of file
-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to