]> granicus.if.org Git - php/commitdiff
- Fixed spl_autoload_functions/spl_autoload_unregister wrt. closures and
authorChristian Seiler <cseiler@php.net>
Mon, 22 Jun 2009 18:14:14 +0000 (18:14 +0000)
committerChristian Seiler <cseiler@php.net>
Mon, 22 Jun 2009 18:14:14 +0000 (18:14 +0000)
  invokables.

ext/spl/php_spl.c
ext/spl/tests/spl_autoload_013.phpt [new file with mode: 0644]
ext/spl/tests/spl_autoload_014.phpt [new file with mode: 0644]
ext/spl/tests/spl_autoload_bug48541.phpt

index f283156aa377471b6e394dfd82b2ac9f66b8b3e5..bcf79e7de9083306d965a904357a2c68afa539ef 100755 (executable)
@@ -502,6 +502,9 @@ PHP_FUNCTION(spl_autoload_register)
                alfi.ce = fcc.calling_scope;
                alfi.func_ptr = fcc.function_handler;
                obj_ptr = fcc.object_ptr;
+
+               zend_u_str_tolower(Z_TYPE(zfunc_name), Z_UNIVAL(zfunc_name), Z_UNILEN(zfunc_name));
+
                if (Z_TYPE_P(zcallable) == IS_OBJECT) {
                        zstr lc_name;
 
@@ -510,9 +513,9 @@ PHP_FUNCTION(spl_autoload_register)
                        alfi.closure = zcallable;
                        Z_ADDREF_P(zcallable);
 
-                       lc_name.v = Z_UNIVAL(zfunc_name).v = erealloc(Z_UNIVAL(zfunc_name).v, func_name_len + 2 + sizeof(zcallable->value.obj.handle));
-                       memcpy(lc_name.s + func_name_len, &(zcallable->value.obj.handle), sizeof(zcallable->value.obj.handle));
-                       func_name_len += sizeof(zcallable->value.obj.handle);
+                       lc_name.v = Z_UNIVAL(zfunc_name).v = erealloc(Z_UNIVAL(zfunc_name).v, func_name_len + 2 + sizeof(zend_object_handle));
+                       memcpy(lc_name.s + func_name_len, &Z_OBJ_HANDLE_P(zcallable), sizeof(zend_object_handle));
+                       func_name_len += sizeof(zend_object_handle);
                        if (Z_TYPE(zfunc_name) == IS_UNICODE) {
                                func_name_len /= sizeof(UChar);
                                Z_STRLEN(zfunc_name) = func_name_len;
@@ -526,7 +529,6 @@ PHP_FUNCTION(spl_autoload_register)
                        efree(error);
                }
        
-               zend_u_str_tolower(Z_TYPE(zfunc_name), Z_UNIVAL(zfunc_name), Z_UNILEN(zfunc_name));
                if (SPL_G(autoload_functions) && zend_u_hash_exists(SPL_G(autoload_functions), Z_TYPE(zfunc_name), Z_UNIVAL(zfunc_name), Z_UNILEN(zfunc_name)+1)) {
                        if (alfi.closure) {
                                Z_DELREF_P(zcallable);
@@ -601,6 +603,7 @@ PHP_FUNCTION(spl_autoload_unregister)
        zval zfunc_name;
        zval *zcallable;
        zstr lc_name;
+       size_t lc_name_len;
        int success = FAILURE;
        zend_function *spl_func_ptr;
        zval *obj_ptr;
@@ -624,10 +627,24 @@ PHP_FUNCTION(spl_autoload_unregister)
        }
 
        lc_name = zend_u_str_tolower_dup(Z_TYPE(zfunc_name), Z_UNIVAL(zfunc_name), Z_UNILEN(zfunc_name));
+       lc_name_len = Z_UNILEN(zfunc_name);
+
+       if (Z_TYPE_P(zcallable) == IS_OBJECT) {
+               lc_name_len = Z_UNISIZE(zfunc_name);
+               lc_name.v = erealloc(lc_name.v, lc_name_len + 2 + sizeof(zend_object_handle));
+               memcpy(lc_name.s + lc_name_len, &Z_OBJ_HANDLE_P(zcallable), sizeof(zend_object_handle));
+               lc_name_len += sizeof(zend_object_handle);
+               if (Z_TYPE(zfunc_name) == IS_UNICODE) {
+                       lc_name_len /= sizeof(UChar);
+                       lc_name.u[lc_name_len] = 0;
+               } else {
+                       lc_name.s[lc_name_len] = '\0';
+               }
+       }
 
        if (SPL_G(autoload_functions)) {
-               if ((Z_UNILEN(zfunc_name) == sizeof("spl_autoload_call")-1) &&
-                   (ZEND_U_EQUAL(Z_TYPE(zfunc_name), lc_name, Z_UNILEN(zfunc_name), "spl_autoload_call", sizeof("spl_autoload_call")-1))) {
+               if ((lc_name_len == sizeof("spl_autoload_call")-1) &&
+                   (ZEND_U_EQUAL(Z_TYPE(zfunc_name), lc_name, lc_name_len, "spl_autoload_call", sizeof("spl_autoload_call")-1))) {
                        /* remove all */
                        zend_hash_destroy(SPL_G(autoload_functions));
                        FREE_HASHTABLE(SPL_G(autoload_functions));
@@ -636,23 +653,25 @@ PHP_FUNCTION(spl_autoload_unregister)
                        success = SUCCESS;
                } else {
                        /* remove specific */
-                       success = zend_u_hash_del(SPL_G(autoload_functions), Z_TYPE(zfunc_name), lc_name, Z_UNILEN(zfunc_name)+1);
+                       success = zend_u_hash_del(SPL_G(autoload_functions), Z_TYPE(zfunc_name), lc_name, lc_name_len+1);
                        if (success != SUCCESS && obj_ptr) {
-                               size_t func_name_len = Z_UNISIZE(zfunc_name);
-                               lc_name.v = erealloc(lc_name.v, func_name_len + 2 + sizeof(zend_object_handle));
-                               memcpy(lc_name.s + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
-                               func_name_len += sizeof(zend_object_handle);
                                if (Z_TYPE(zfunc_name) == IS_UNICODE) {
-                                       func_name_len /= sizeof(UChar);
-                                       lc_name.u[func_name_len] = 0;
+                                       lc_name_len *= sizeof(UChar);
+                               }
+                               lc_name.v = erealloc(lc_name.v, lc_name_len + 2 + sizeof(zend_object_handle));
+                               memcpy(lc_name.s + lc_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
+                               lc_name_len += sizeof(zend_object_handle);
+                               if (Z_TYPE(zfunc_name) == IS_UNICODE) {
+                                       lc_name_len /= sizeof(UChar);
+                                       lc_name.u[lc_name_len] = 0;
                                } else {
-                                       lc_name.s[func_name_len] = '\0';
+                                       lc_name.s[lc_name_len] = '\0';
                                }
-                               success = zend_u_hash_del(SPL_G(autoload_functions), Z_TYPE(zfunc_name), lc_name, func_name_len+1);
+                               success = zend_u_hash_del(SPL_G(autoload_functions), Z_TYPE(zfunc_name), lc_name, lc_name_len+1);
                        }
                }
-       } else if ((Z_UNILEN(zfunc_name) == sizeof("spl_autoload")-1) &&
-                  (ZEND_U_EQUAL(Z_TYPE(zfunc_name), lc_name, Z_UNILEN(zfunc_name), "spl_autoload", sizeof("spl_autoload")-1))) {
+       } else if ((lc_name_len == sizeof("spl_autoload")-1) &&
+                  (ZEND_U_EQUAL(Z_TYPE(zfunc_name), lc_name, lc_name_len, "spl_autoload", sizeof("spl_autoload")-1))) {
                /* register single spl_autoload() */
                zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr);
 
@@ -692,7 +711,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);
diff --git a/ext/spl/tests/spl_autoload_013.phpt b/ext/spl/tests/spl_autoload_013.phpt
new file mode 100644 (file)
index 0000000..e9df58b
--- /dev/null
@@ -0,0 +1,53 @@
+--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 (2) {
+    ["this"]=>
+    NULL
+    ["parameter"]=>
+    array(1) {
+      ["$class"]=>
+      string(10) "<required>"
+    }
+  }
+  [1]=>
+  object(Autoloader)#%d (1) {
+    [u"dir":u"Autoloader":private]=>
+    unicode(2) "d1"
+  }
+  [2]=>
+  object(Autoloader)#%d (1) {
+    [u"dir":u"Autoloader":private]=>
+    unicode(2) "d2"
+  }
+}
+===DONE===
\ No newline at end of file
diff --git a/ext/spl/tests/spl_autoload_014.phpt b/ext/spl/tests/spl_autoload_014.phpt
new file mode 100644 (file)
index 0000000..a68fcb7
--- /dev/null
@@ -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 eef81bd03b0cd01a63d1beeb585a6e1fa86064ca..9937a7f42c06deb255d8874ff56dc0bb29df14a0 100644 (file)
@@ -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