diff --git a/Zend/tests/bug48770.phpt b/Zend/tests/bug48770.phpt index 40fa84157b716..4e2794a4ad0f2 100644 --- a/Zend/tests/bug48770.phpt +++ b/Zend/tests/bug48770.phpt @@ -1,7 +1,5 @@ --TEST-- Bug #48770 (call_user_func_array() fails to call parent from inheriting class) ---XFAIL-- -See Bug #48770 --FILE-- run('This should work!'); + +?> +--EXPECTF-- +%unicode|string%(26) "A::func: This should work!" +%unicode|string%(26) "A::func: This should work!" + diff --git a/Zend/tests/call_user_func_007.phpt b/Zend/tests/call_user_func_007.phpt new file mode 100644 index 0000000000000..4ec1af13c4967 --- /dev/null +++ b/Zend/tests/call_user_func_007.phpt @@ -0,0 +1,42 @@ +--TEST-- +Testing scope overwriting with call_user_fun() in dynamic context +This test was written by "smalyshev" in this tread https://github.com/php/php-src/pull/375#issuecomment-20945580 +--FILE-- +who(); +?> +--EXPECTF-- +string(1) "C" +I am C +string(1) "C" +I am C \ No newline at end of file diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 125a1a2564793..4f6088902bd3b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2612,6 +2612,7 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca { int ret = 0; zend_class_entry **pce; + zend_class_entry *scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL; char *lcname = zend_str_tolower_dup(name, name_len); *strict_class = 0; @@ -2621,7 +2622,9 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca if (error) *error = estrdup("cannot access self:: when no class scope is active"); } else { fcc->called_scope = EG(called_scope); - fcc->calling_scope = EG(scope); + fcc->calling_scope = scope && instanceof_function(EG(scope), scope TSRMLS_CC) + ? scope + : EG(scope); if (!fcc->object_ptr) { fcc->object_ptr = EG(This); } @@ -2631,16 +2634,22 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca !memcmp(lcname, "parent", sizeof("parent") - 1)) { if (!EG(scope)) { if (error) *error = estrdup("cannot access parent:: when no class scope is active"); - } else if (!EG(scope)->parent) { - if (error) *error = estrdup("cannot access parent:: when current class scope has no parent"); } else { - fcc->called_scope = EG(called_scope); - fcc->calling_scope = EG(scope)->parent; - if (!fcc->object_ptr) { - fcc->object_ptr = EG(This); + if (!(scope && instanceof_function(EG(scope), scope TSRMLS_CC))) { + scope = EG(scope); + } + + if (!scope->parent) { + if (error) *error = estrdup("cannot access parent:: when current class scope has no parent"); + } else { + fcc->calling_scope = scope->parent; + fcc->called_scope = EG(called_scope); + if (!fcc->object_ptr) { + fcc->object_ptr = EG(This); + } + *strict_class = 1; + ret = 1; } - *strict_class = 1; - ret = 1; } } else if (name_len == sizeof("static") - 1 && !memcmp(lcname, "static", sizeof("static") - 1)) { @@ -2656,8 +2665,6 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca ret = 1; } } else if (zend_lookup_class_ex(name, name_len, NULL, 1, &pce TSRMLS_CC) == SUCCESS) { - zend_class_entry *scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL; - fcc->calling_scope = *pce; if (scope && !fcc->object_ptr && EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), scope TSRMLS_CC) && diff --git a/ext/standard/tests/general_functions/callbacks_001.phpt b/ext/standard/tests/general_functions/callbacks_001.phpt index a58f19d932b8e..8c3a2209bfbb6 100644 --- a/ext/standard/tests/general_functions/callbacks_001.phpt +++ b/ext/standard/tests/general_functions/callbacks_001.phpt @@ -78,6 +78,21 @@ echo "===FOREIGN===\n"; $o = new P; $o->test(); +echo "===WITHOUT SCOPE===\n"; +function call($cb) { + echo join('|', $cb) . "\n"; + call_user_func($cb); +} +call(array($o, 'who')); +call(array($o, 'O::who')); +call(array($o, 'P::who')); +call(array($o, 'B::who')); +call(array($o, 'parent::who')); + +call(array('parent', 'who')); +call(array('C', 'parent::who')); +call(array('C', 'who')); + ?> ===DONE=== --EXPECTF-- @@ -105,4 +120,23 @@ O $this|B::who Warning: call_user_func() expects parameter 1 to be a valid callback, class 'P' is not a subclass of 'B' in %s on line %d -===DONE=== +===WITHOUT SCOPE=== +$this|who +P +$this|O::who +O +$this|P::who +P +$this|B::who + +Warning: call_user_func() expects parameter 1 to be a valid callback, class 'P' is not a subclass of 'B' in %s on line %d +$this|parent::who +O +parent|who + +Warning: call_user_func() expects parameter 1 to be a valid callback, cannot access parent:: when no class scope is active in %s on line %d +C|parent::who +B +C|who +B +===DONE=== \ No newline at end of file