diff --git a/UPGRADING b/UPGRADING index fcdf38d9a7bba..6d58ba57e1594 100644 --- a/UPGRADING +++ b/UPGRADING @@ -134,11 +134,10 @@ PHP 8.2 UPGRADE NOTES [new Foo, "Bar::method"] This does not affect normal method callables like "A::method" or - ["A", "method"]. A deprecation notice is only emitted on call. Both - is_callable() and the callable type will silently accept these callables - until support for them is removed entirely. + ["A", "method"]. RFC: https://wiki.php.net/rfc/deprecate_partially_supported_callables + RFC: https://wiki.php.net/rfc/partially-supported-callables-expand-deprecation-notices . The "${var}" and "${expr}" style string interpolations are deprecated and will be removed in PHP 9. Use "$var"/"{$var}" or "{${expr}}", respectively. diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index e0aebcbb6b522..a52196dc60997 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -46,6 +46,11 @@ PHP 8.2 INTERNALS UPGRADE NOTES smart_str_trim_to_size() before returning the string. * It is recommended to use smart_str_extract() or smart_str_trim_to_size() when using the smart_str API. +* zend_is_callable_ex, and functions which call it such as zend_is_callable and + zend_fcall_info_init, will issue deprecation notices if passed values which + are deprecated (see main UPGRADING notes). To suppress the notice, e.g. to + avoid duplicates when processing the same value multiple times, pass or add + IS_CALLABLE_SUPPRESS_DEPRECATIONS to the check_flags parameter. ======================== 2. Build system changes diff --git a/Zend/tests/bug48899-deprecated.phpt b/Zend/tests/bug48899-deprecated.phpt new file mode 100644 index 0000000000000..d731d57849c3e --- /dev/null +++ b/Zend/tests/bug48899-deprecated.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #48899 (is_callable returns true even if method does not exist in parent class) [original test with deprecated syntax] +--FILE-- +testIsCallable(); +$child->testIsCallable2(); + +?> +--EXPECTF-- +Deprecated: Callables of the form ["ChildClass", "parent::testIsCallable"] are deprecated in %s on line %d +bool(false) + +Deprecated: Callables of the form ["ChildClass", "static::testIsCallable2"] are deprecated in %s on line %d +bool(true) diff --git a/Zend/tests/bug48899.phpt b/Zend/tests/bug48899.phpt index 2cbf308c3eddc..6edf3076ab09f 100644 --- a/Zend/tests/bug48899.phpt +++ b/Zend/tests/bug48899.phpt @@ -7,10 +7,10 @@ class ParentClass { } class ChildClass extends ParentClass { public function testIsCallable() { - var_dump(is_callable(array($this, 'parent::testIsCallable'))); + var_dump(is_callable(array('ParentClass', 'testIsCallable'))); } public function testIsCallable2() { - var_dump(is_callable(array($this, 'static::testIsCallable2'))); + var_dump(is_callable(array('ChildClass', 'testIsCallable2'))); } } diff --git a/Zend/tests/bug71622.phpt b/Zend/tests/bug71622.phpt index c23547788a034..59d4101df6837 100644 --- a/Zend/tests/bug71622.phpt +++ b/Zend/tests/bug71622.phpt @@ -17,7 +17,7 @@ class Abc { public static function run() { $method = "foobar"; getMethodName($method); - var_dump(is_callable("self::$method")); + var_dump(is_callable("Abc::$method")); self::$method(); } } diff --git a/Zend/tests/callable_self_parent_static_deprecation.phpt b/Zend/tests/callable_self_parent_static_deprecation.phpt index a6696d234bc50..d01713d429f7e 100644 --- a/Zend/tests/callable_self_parent_static_deprecation.phpt +++ b/Zend/tests/callable_self_parent_static_deprecation.phpt @@ -9,27 +9,52 @@ class A { class B extends A { public function test() { // Different callables using self/parent/static - echo "Test different callables\n"; - call_user_func("self::foo"); - call_user_func("parent::foo"); - call_user_func("static::foo"); - call_user_func(["self", "foo"]); - call_user_func(["parent", "foo"]); - call_user_func(["static", "foo"]); - call_user_func(["B", "self::foo"]); - call_user_func(["B", "parent::foo"]); - call_user_func(["B", "static::foo"]); - call_user_func(["B", "A::foo"]); + $variants = [ + '"self::foo"' => "self::foo", + '"parent::foo"' => "parent::foo", + '"static::foo"' => "static::foo", + '["self", "foo"]' => ["self", "foo"], + '["parent", "foo"]' => ["parent", "foo"], + '["static", "foo"]' => ["static", "foo"], + '["B", "self::foo"]' => ["B", "self::foo"], + '["B", "parent::foo"]' => ["B", "parent::foo"], + '["B", "static::foo"]' => ["B", "static::foo"], + '["B", "A::foo"]' => ["B", "A::foo"], + '[$this, "self::foo"]' => [$this, "self::foo"], + '[$this, "parent::foo"]' => [$this, "parent::foo"], + '[$this, "static::foo"]' => [$this, "static::foo"], + '[$this, "A::foo"]' => [$this, "A::foo"], + ]; + + echo "==> Test call_user_func\n"; + foreach ($variants as $description => $callable) { + echo "$description\n"; + call_user_func($callable); + } + echo "\n==> Test call_user_func_array\n"; + foreach ($variants as $description => $callable) { + echo "$description\n"; + call_user_func_array($callable, []); + } // Also applies to other things performing calls - echo "Test array_map()\n"; - array_map("self::foo", [1]); + echo "\n==> Test array_map\n"; + foreach ($variants as $description => $callable) { + echo "$description\n"; + array_map($callable, [1]); + } - echo "Test is_callable() -- should be silent\n"; - var_dump(is_callable("self::foo")); + echo "\n==> Test is_callable()\n"; + foreach ($variants as $description => $callable) { + echo "$description\n"; + var_dump(is_callable($callable)); + } - echo "Test callable type hint -- should be silent\n"; - $this->callableTypeHint("self::foo"); + echo "\n==> Test callable type hint\n"; + foreach ($variants as $description => $callable) { + echo "$description\n"; + $this->callableTypeHint($callable); + } } public function callableTypeHint(callable $c) {} @@ -40,30 +65,236 @@ $b->test(); ?> --EXPECTF-- -Test different callables +==> Test call_user_func +"self::foo" + +Deprecated: Use of "self" in callables is deprecated in %s on line %d +"parent::foo" + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +"static::foo" + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +["self", "foo"] + +Deprecated: Use of "self" in callables is deprecated in %s on line %d +["parent", "foo"] + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +["static", "foo"] + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +["B", "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +["B", "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +["B", "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +["B", "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d +[$this, "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +[$this, "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +[$this, "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +[$this, "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d + +==> Test call_user_func_array +"self::foo" + +Deprecated: Use of "self" in callables is deprecated in %s on line %d +"parent::foo" + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +"static::foo" + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +["self", "foo"] + +Deprecated: Use of "self" in callables is deprecated in %s on line %d +["parent", "foo"] + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +["static", "foo"] + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +["B", "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +["B", "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +["B", "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +["B", "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d +[$this, "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +[$this, "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +[$this, "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +[$this, "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d + +==> Test array_map +"self::foo" Deprecated: Use of "self" in callables is deprecated in %s on line %d +"parent::foo" Deprecated: Use of "parent" in callables is deprecated in %s on line %d +"static::foo" Deprecated: Use of "static" in callables is deprecated in %s on line %d +["self", "foo"] Deprecated: Use of "self" in callables is deprecated in %s on line %d +["parent", "foo"] Deprecated: Use of "parent" in callables is deprecated in %s on line %d +["static", "foo"] Deprecated: Use of "static" in callables is deprecated in %s on line %d +["B", "self::foo"] Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +["B", "parent::foo"] Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +["B", "static::foo"] Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +["B", "A::foo"] Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d -Test array_map() +[$this, "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +[$this, "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +[$this, "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +[$this, "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d + +==> Test is_callable() +"self::foo" Deprecated: Use of "self" in callables is deprecated in %s on line %d -Test is_callable() -- should be silent bool(true) -Test callable type hint -- should be silent +"parent::foo" + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +bool(true) +"static::foo" + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +bool(true) +["self", "foo"] + +Deprecated: Use of "self" in callables is deprecated in %s on line %d +bool(true) +["parent", "foo"] + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +bool(true) +["static", "foo"] + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +bool(true) +["B", "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +bool(true) +["B", "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +bool(true) +["B", "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +bool(true) +["B", "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d +bool(true) +[$this, "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +bool(true) +[$this, "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +bool(true) +[$this, "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +bool(true) +[$this, "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d +bool(true) + +==> Test callable type hint +"self::foo" + +Deprecated: Use of "self" in callables is deprecated in %s on line %d +"parent::foo" + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +"static::foo" + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +["self", "foo"] + +Deprecated: Use of "self" in callables is deprecated in %s on line %d +["parent", "foo"] + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +["static", "foo"] + +Deprecated: Use of "static" in callables is deprecated in %s on line %d +["B", "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +["B", "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +["B", "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +["B", "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d +[$this, "self::foo"] + +Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d +[$this, "parent::foo"] + +Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d +[$this, "static::foo"] + +Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d +[$this, "A::foo"] + +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d diff --git a/Zend/tests/is_callable_trampoline_uaf-deprecated.phpt b/Zend/tests/is_callable_trampoline_uaf-deprecated.phpt new file mode 100644 index 0000000000000..fc853e471973c --- /dev/null +++ b/Zend/tests/is_callable_trampoline_uaf-deprecated.phpt @@ -0,0 +1,28 @@ +--TEST-- +is_callable() with trampoline should not caused UAF [original test with deprecated syntax] +--FILE-- +bar('foo')); + +?> +--EXPECTF-- +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +bool(false) diff --git a/Zend/tests/is_callable_trampoline_uaf.phpt b/Zend/tests/is_callable_trampoline_uaf.phpt index 2410864410ab4..a36a995b8d673 100644 --- a/Zend/tests/is_callable_trampoline_uaf.phpt +++ b/Zend/tests/is_callable_trampoline_uaf.phpt @@ -6,7 +6,7 @@ is_callable() with trampoline should not caused UAF class B {} class A extends B { public function bar($func) { - var_dump(is_callable(array('parent', 'foo'))); + var_dump(is_callable(array('B', 'foo'))); } public function __call($func, $args) { diff --git a/Zend/tests/lsb_013.phpt b/Zend/tests/lsb_013.phpt index 3af7f1bea7eb0..c973db9059633 100644 --- a/Zend/tests/lsb_013.phpt +++ b/Zend/tests/lsb_013.phpt @@ -17,8 +17,15 @@ class Test2 extends Test1 { Test1::test(); Test2::test(); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Use of "static" in callables is deprecated in %s on line %d bool(false) + +Deprecated: Use of "static" in callables is deprecated in %s on line %d bool(false) + +Deprecated: Use of "static" in callables is deprecated in %s on line %d bool(true) + +Deprecated: Use of "static" in callables is deprecated in %s on line %d bool(true) diff --git a/Zend/tests/traits/bug76773-deprecated.phpt b/Zend/tests/traits/bug76773-deprecated.phpt new file mode 100644 index 0000000000000..e6dac201fc758 --- /dev/null +++ b/Zend/tests/traits/bug76773-deprecated.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #76773 (Traits used on the parent are ignored for child classes) [original test with deprecated syntax] +--FILE-- +hello(); +?> +--EXPECTF-- +ChildClass + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d +ParentClass diff --git a/Zend/tests/traits/bug76773.phpt b/Zend/tests/traits/bug76773.phpt index 4ab53bf6d11d2..50b314794291d 100644 --- a/Zend/tests/traits/bug76773.phpt +++ b/Zend/tests/traits/bug76773.phpt @@ -9,7 +9,7 @@ trait MyTrait { echo __CLASS__, "\n"; - if (\is_callable(array('parent', __FUNCTION__))) { + if (get_parent_class(__CLASS__) !== false) { parent::hello(); } } diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e2a77704733c3..6fa5e62dcd090 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3412,7 +3412,7 @@ static bool zend_is_callable_check_class(zend_string *name, zend_class_entry *sc if (!scope) { if (error) *error = estrdup("cannot access \"self\" when no class scope is active"); } else { - if (error && !suppress_deprecation) { + if (!suppress_deprecation) { zend_error(E_DEPRECATED, "Use of \"self\" in callables is deprecated"); } fcc->called_scope = zend_get_called_scope(frame); @@ -3431,7 +3431,7 @@ static bool zend_is_callable_check_class(zend_string *name, zend_class_entry *sc } else if (!scope->parent) { if (error) *error = estrdup("cannot access \"parent\" when current class scope has no parent"); } else { - if (error && !suppress_deprecation) { + if (!suppress_deprecation) { zend_error(E_DEPRECATED, "Use of \"parent\" in callables is deprecated"); } fcc->called_scope = zend_get_called_scope(frame); @@ -3451,7 +3451,7 @@ static bool zend_is_callable_check_class(zend_string *name, zend_class_entry *sc if (!called_scope) { if (error) *error = estrdup("cannot access \"static\" when no class scope is active"); } else { - if (error && !suppress_deprecation) { + if (!suppress_deprecation) { zend_error(E_DEPRECATED, "Use of \"static\" in callables is deprecated"); } fcc->called_scope = called_scope; @@ -3500,7 +3500,7 @@ ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc) { } } -static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_execute_data *frame, zend_fcall_info_cache *fcc, bool strict_class, char **error) /* {{{ */ +static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_execute_data *frame, zend_fcall_info_cache *fcc, bool strict_class, char **error, bool suppress_deprecation) /* {{{ */ { zend_class_entry *ce_org = fcc->calling_scope; bool retval = 0; @@ -3586,7 +3586,7 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_ fcc->called_scope = fcc->object ? fcc->object->ce : fcc->calling_scope; } strict_class = 1; - } else if (!zend_is_callable_check_class(cname, scope, frame, fcc, &strict_class, error, ce_org != NULL)) { + } else if (!zend_is_callable_check_class(cname, scope, frame, fcc, &strict_class, error, suppress_deprecation || ce_org != NULL)) { zend_string_release_ex(cname, 0); return 0; } @@ -3597,7 +3597,7 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_ if (error) zend_spprintf(error, 0, "class %s is not a subclass of %s", ZSTR_VAL(ce_org->name), ZSTR_VAL(fcc->calling_scope->name)); return 0; } - if (ce_org && error) { + if (ce_org && !suppress_deprecation) { zend_error(E_DEPRECATED, "Callables of the form [\"%s\", \"%s\"] are deprecated", ZSTR_VAL(ce_org->name), Z_STRVAL_P(callable)); @@ -3838,7 +3838,7 @@ ZEND_API bool zend_is_callable_at_frame( } check_func: - ret = zend_is_callable_check_func(callable, frame, fcc, strict_class, error); + ret = zend_is_callable_check_func(callable, frame, fcc, strict_class, error, check_flags & IS_CALLABLE_SUPPRESS_DEPRECATIONS); if (fcc == &fcc_local) { zend_release_fcall_info_cache(fcc); } @@ -3875,7 +3875,7 @@ ZEND_API bool zend_is_callable_at_frame( return 1; } - if (!zend_is_callable_check_class(Z_STR_P(obj), get_scope(frame), frame, fcc, &strict_class, error, false)) { + if (!zend_is_callable_check_class(Z_STR_P(obj), get_scope(frame), frame, fcc, &strict_class, error, check_flags & IS_CALLABLE_SUPPRESS_DEPRECATIONS)) { return 0; } } else { @@ -3938,7 +3938,7 @@ ZEND_API bool zend_make_callable(zval *callable, zend_string **callable_name) /* { zend_fcall_info_cache fcc; - if (zend_is_callable_ex(callable, NULL, 0, callable_name, &fcc, NULL)) { + if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, callable_name, &fcc, NULL)) { if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) { zval_ptr_dtor_str(callable); array_init(callable); diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 5796c4f472ca4..af844d0a87ba7 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -393,6 +393,7 @@ ZEND_API zend_result zend_disable_class(const char *class_name, size_t class_nam ZEND_API ZEND_COLD void zend_wrong_param_count(void); #define IS_CALLABLE_CHECK_SYNTAX_ONLY (1<<0) +#define IS_CALLABLE_SUPPRESS_DEPRECATIONS (1<<1) ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc); ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *object); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 6891ab7b9eb80..46f88a1dbe6b4 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1099,7 +1099,8 @@ static zend_always_inline bool zend_check_type_slow( } type_mask = ZEND_TYPE_FULL_MASK(*type); - if ((type_mask & MAY_BE_CALLABLE) && zend_is_callable(arg, 0, NULL)) { + if ((type_mask & MAY_BE_CALLABLE) && + zend_is_callable(arg, is_internal ? IS_CALLABLE_SUPPRESS_DEPRECATIONS : 0, NULL)) { return 1; } if ((type_mask & MAY_BE_STATIC) && zend_value_instanceof_static(arg)) { diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 9822ef692a83d..1ac9712938d4e 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1050,7 +1050,7 @@ ZEND_API zend_result zend_call_method_if_exists( fci.named_params = NULL; zend_fcall_info_cache fcc; - if (!zend_is_callable_ex(&fci.function_name, fci.object, 0, NULL, &fcc, NULL)) { + if (!zend_is_callable_ex(&fci.function_name, fci.object, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL)) { ZVAL_UNDEF(retval); return FAILURE; } diff --git a/ext/filter/callback_filter.c b/ext/filter/callback_filter.c index 290fdf26fe3c1..067f16a03ea24 100644 --- a/ext/filter/callback_filter.c +++ b/ext/filter/callback_filter.c @@ -22,7 +22,7 @@ void php_filter_callback(PHP_INPUT_FILTER_PARAM_DECL) zval args[1]; int status; - if (!option_array || !zend_is_callable(option_array, 0, NULL)) { + if (!option_array || !zend_is_callable(option_array, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL)) { zend_type_error("%s(): Option must be a valid callback", get_active_function_name()); zval_ptr_dtor(value); ZVAL_NULL(value); diff --git a/ext/session/session.c b/ext/session/session.c index cbfbda1941bba..75668d53e546c 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -2098,7 +2098,7 @@ PHP_FUNCTION(session_set_save_handler) /* At this point argc can only be between 6 and PS_NUM_APIS */ for (i = 0; i < argc; i++) { - if (!zend_is_callable(&args[i], 0, NULL)) { + if (!zend_is_callable(&args[i], IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL)) { zend_string *name = zend_get_callable_name(&args[i]); zend_argument_type_error(i + 1, "must be a valid callback, function \"%s\" not found or invalid function name", ZSTR_VAL(name)); zend_string_release(name); diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 839e978ec61ad..a1ae90367a22c 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -521,7 +521,7 @@ PHP_FUNCTION(spl_autoload_register) /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal * with it outselves. It is important that it is not refetched on every call, * because calls may occur from different scopes. */ - zend_is_callable_ex(&fci.function_name, NULL, 0, NULL, &fcc, NULL); + zend_is_callable_ex(&fci.function_name, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL); } if (fcc.function_handler->type == ZEND_INTERNAL_FUNCTION && diff --git a/ext/standard/tests/bug75220.phpt b/ext/standard/tests/bug75220.phpt index f0ba55a702380..cdc88d4c98c6f 100644 --- a/ext/standard/tests/bug75220.phpt +++ b/ext/standard/tests/bug75220.phpt @@ -22,7 +22,11 @@ class A extends B }; ?> ---EXPECT-- +--EXPECTF-- string(3) "foo" + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d bool(false) + +Deprecated: Use of "parent" in callables is deprecated in %s on line %d bool(false) diff --git a/ext/standard/tests/general_functions/is_callable_abstract_method-deprecated.phpt b/ext/standard/tests/general_functions/is_callable_abstract_method-deprecated.phpt new file mode 100644 index 0000000000000..4853523993424 --- /dev/null +++ b/ext/standard/tests/general_functions/is_callable_abstract_method-deprecated.phpt @@ -0,0 +1,20 @@ +--TEST-- +is_callable() on abstract method via object should return false [original test with deprecated syntax] +--FILE-- + +--EXPECTF-- +Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d +bool(false) diff --git a/ext/standard/tests/general_functions/is_callable_abstract_method.phpt b/ext/standard/tests/general_functions/is_callable_abstract_method.phpt index 0f3d1a6cb10df..4cc9c6957f03a 100644 --- a/ext/standard/tests/general_functions/is_callable_abstract_method.phpt +++ b/ext/standard/tests/general_functions/is_callable_abstract_method.phpt @@ -9,11 +9,13 @@ abstract class A { class B extends A { function foo() {} -} -$foo = [new B, 'A::foo']; -var_dump(is_callable($foo)); + function test() { + var_dump(is_callable(['A', 'foo'])); + } +} +(new B)->test(); ?> --EXPECT-- bool(false) diff --git a/main/streams/userspace.c b/main/streams/userspace.c index 7114f09d6bdab..1b113423d7140 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -953,7 +953,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value switch (value) { case PHP_STREAM_TRUNCATE_SUPPORTED: - if (zend_is_callable_ex(&func_name, Z_OBJ(us->object), 0, NULL, NULL, NULL)) + if (zend_is_callable_ex(&func_name, Z_OBJ(us->object), IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, NULL, NULL)) ret = PHP_STREAM_OPTION_RETURN_OK; else ret = PHP_STREAM_OPTION_RETURN_ERR;