]> granicus.if.org Git - php/commitdiff
MFH: Fixed bug #48533 (__callStatic is not invoked for private/protected methods)
authorFelipe Pena <felipe@php.net>
Fri, 12 Jun 2009 01:05:25 +0000 (01:05 +0000)
committerFelipe Pena <felipe@php.net>
Fri, 12 Jun 2009 01:05:25 +0000 (01:05 +0000)
NEWS
Zend/tests/bug48533.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c

diff --git a/NEWS b/NEWS
index d1fbb0f023aff23070aa327f49e7fd385b9a9ad0..8ef25092e64b98330fe5c528413157bc8974e510 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,9 @@ PHP                                                                        NEWS
 ?? ??? 2009, PHP 5.3.0 RC 4
 - Added phar.phar generation for Windows. (Greg)
 
+- Fixed bug #48533 (__callStatic is not invoked for private/protected methods).
+  (Felipe)
+
 11 Jun 2009, PHP 5.3.0 RC 3
 - Upgraded bundled sqlite to version 3.6.14.2. (Scott, Ilia)
 - Upgraded bundled libmagic to 5.03 in the fileinfo extension. (Scott)
diff --git a/Zend/tests/bug48533.phpt b/Zend/tests/bug48533.phpt
new file mode 100644 (file)
index 0000000..274013c
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+Bug #48533 (__callStatic is not invoked for private/protected methods)
+--FILE--
+<?php
+
+class foo {
+       private function a() {
+               var_dump(1);    
+       }
+       public function b() {
+               var_dump(2);
+       }
+       protected function c() {
+               var_dump(3);
+       }
+       static function __callstatic($a, $b) {
+               var_dump('__callStatic::'. $a);
+       }
+       public function __call($a, $b) {
+               var_dump('__call::'. $a);
+       }
+}
+
+$x = new foo;
+$x->a();
+$x->b();
+$x->c();
+$x::a();
+$x::b();
+$x::c();
+
+?>
+--EXPECTF--
+%unicode|string%(9) "__call::a"
+int(2)
+%unicode|string%(9) "__call::c"
+%unicode|string%(15) "__callStatic::a"
+
+Strict Standards: Non-static method foo::b() should not be called statically in %s on line %d
+int(2)
+%unicode|string%(15) "__callStatic::c"
index e04bcb14472fd9330a4d8ab25b1a5b16be70be75..97e8065e7e5042a12f4aa1039f33442b370e651c 100644 (file)
@@ -777,15 +777,15 @@ static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc
 }
 /* }}} */
 
-static inline union _zend_function *zend_get_user_call_function(zend_object *zobj, char *method_name, int method_len) /* {{{ */
+static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, char *method_name, int method_len) /* {{{ */
 {
        zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
        call_user_call->type = ZEND_INTERNAL_FUNCTION;
-       call_user_call->module = zobj->ce->module;
+       call_user_call->module = ce->module;
        call_user_call->handler = zend_std_call_user_call;
        call_user_call->arg_info = NULL;
        call_user_call->num_args = 0;
-       call_user_call->scope = zobj->ce;
+       call_user_call->scope = ce;
        call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
        call_user_call->function_name = estrndup(method_name, method_len);
        call_user_call->pass_rest_by_reference = 0;
@@ -811,7 +811,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method
        if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) {
                free_alloca(lc_method_name, use_heap);
                if (zobj->ce->__call) {
-                       return zend_get_user_call_function(zobj, method_name, method_len);
+                       return zend_get_user_call_function(zobj->ce, method_name, method_len);
                } else {
                        return NULL;
                }
@@ -829,7 +829,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method
                        fbc = updated_fbc;
                } else {
                        if (zobj->ce->__call) {
-                               fbc = zend_get_user_call_function(zobj, method_name, method_len);
+                               fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
                        } else {
                                zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
                        }
@@ -855,7 +855,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method
                         */
                        if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
                                if (zobj->ce->__call) {
-                                       fbc = zend_get_user_call_function(zobj, method_name, method_len);
+                                       fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
                                } else {
                                        zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
                                }
@@ -912,6 +912,24 @@ ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{
 }
 /* }}} */
 
+static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, char *method_name, int method_len) /* {{{ */
+{
+       zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function));
+       callstatic_user_call->type     = ZEND_INTERNAL_FUNCTION;
+       callstatic_user_call->module   = ce->module;
+       callstatic_user_call->handler  = zend_std_callstatic_user_call;
+       callstatic_user_call->arg_info = NULL;
+       callstatic_user_call->num_args = 0;
+       callstatic_user_call->scope    = ce;
+       callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
+       callstatic_user_call->function_name = estrndup(method_name, method_len);
+       callstatic_user_call->pass_rest_by_reference = 0;
+       callstatic_user_call->return_reference       = ZEND_RETURN_VALUE;
+
+       return (zend_function *)callstatic_user_call;
+}
+/* }}} */
+
 /* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
 
 ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */
@@ -935,35 +953,9 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *f
                    EG(This) &&
                    Z_OBJ_HT_P(EG(This))->get_class_entry &&
                    instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
-                       zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
-
-                       call_user_call->type = ZEND_INTERNAL_FUNCTION;
-                       call_user_call->module = ce->module;
-                       call_user_call->handler = zend_std_call_user_call;
-                       call_user_call->arg_info = NULL;
-                       call_user_call->num_args = 0;
-                       call_user_call->scope = ce;
-                       call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
-                       call_user_call->function_name = estrndup(function_name_strval, function_name_strlen);
-                       call_user_call->pass_rest_by_reference = 0;
-                       call_user_call->return_reference = ZEND_RETURN_VALUE;
-
-                       return (union _zend_function *)call_user_call;
+                       return zend_get_user_call_function(ce, function_name_strval, function_name_strlen);
                } else if (ce->__callstatic) {
-                       zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function));
-
-                       callstatic_user_call->type     = ZEND_INTERNAL_FUNCTION;
-                       callstatic_user_call->module   = ce->module;
-                       callstatic_user_call->handler  = zend_std_callstatic_user_call;
-                       callstatic_user_call->arg_info = NULL;
-                       callstatic_user_call->num_args = 0;
-                       callstatic_user_call->scope    = ce;
-                       callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
-                       callstatic_user_call->function_name = estrndup(function_name_strval, function_name_strlen);
-                       callstatic_user_call->pass_rest_by_reference = 0;
-                       callstatic_user_call->return_reference       = ZEND_RETURN_VALUE;
-
-                       return (zend_function *)callstatic_user_call;
+                       return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
                } else {
                        return NULL;
                }
@@ -985,14 +977,21 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *f
                /* Ensure that if we're calling a private function, we're allowed to do so.
                 */
                updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC);
-               if (!updated_fbc) {
+               if (updated_fbc) {
+                       fbc = updated_fbc;
+               } else {
+                       if (ce->__callstatic) {
+                               return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
+                       }
                        zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : "");
                }
-               fbc = updated_fbc;
        } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
                /* Ensure that if we're calling a protected function, we're allowed to do so.
                 */
                if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
+                       if (ce->__callstatic) {
+                               return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
+                       }
                        zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : "");
                }
        }