Index: Zend/zend_object_handlers.c===================================================================RCS file: /repository/ZendEngine2/zend_object_handlers.c,vretrieving revision 1.135.2.6.2.31diff -u -w -p -r1.135.2.6.2.31 zend_object_handlers.c--- Zend/zend_object_handlers.c 8 Jan 2009 00:39:15 -0000 1.135.2.6.2.31+++ Zend/zend_object_handlers.c 11 Jan 2009 12:33:05 -0000@@ -849,33 +849,29 @@ static union _zend_function *zend_std_ge }+/* Checks whether __call() should be used in the case where a method invocation has+ * been made using the Scope Resolution Operator (::), but the method was not found+ * or is not visible. */+static inline int zend_use_user_call_with_SRO(zend_class_entry *ce TSRMLS_DC) /* {{{ */+{+ // Return true if the target class has a __call() method and+ // the current object context is compatible with the target class. + return ce->__call &&+ EG(This) &&+ Z_OBJ_HT_P(EG(This))->get_class_entry &&+ instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC);+}+ /* 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) { zend_function *fbc; if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==FAILURE) {- if (ce->__call &&- 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 = 0;- 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;+ if (zend_use_user_call_with_SRO(ce TSRMLS_CC)) { + return zend_get_user_call_function(Z_OBJ_P(EG(This)), function_name_strval, function_name_strlen); } else { char *class_name = ce->name;- if (!class_name) { class_name = ""; }@@ -891,13 +887,19 @@ ZEND_API zend_function *zend_std_get_sta */ updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC); if (!updated_fbc) {+ if (zend_use_user_call_with_SRO(ce TSRMLS_CC)) { + return zend_get_user_call_function(Z_OBJ_P(EG(This)), function_name_strval, function_name_strlen);+ } 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), 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))) {+ // No need to check zend_use_user_call_with_SRO(): if the protected method isn't visible,+ // the scopes are not compatible, so we will not fall back to __call(). 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 : ""); } }Index: Zend/tests/access_modifiers_013.phpt===================================================================RCS file: Zend/tests/access_modifiers_013.phptdiff -N Zend/tests/access_modifiers_013.phpt--- /dev/null 1 Jan 1970 00:00:00 -0000+++ Zend/tests/access_modifiers_013.phpt 11 Jan 2009 11:27:55 -0000@@ -0,0 +1,22 @@+--TEST--+Trigger __call() when attempting to access a private in parent with scope resolution operator.+--FILE--+<?php+Class C {+ private function priv() {}+ function __call($name, $args) { echo "In C::__call($name)\n"; }+}++class D extends C {+ function test() {+ C::none();+ C::priv();+ }+}++$d = new D;+$d->test();+?>+--EXPECTF--+In C::__call(none)+In C::__call(priv)\ No newline at end of file