diff --git a/NEWS b/NEWS index 35f4d174a5f92..6c2db856000e3 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ PHP NEWS . Enacted the follow-up phase of the "Path to Saner Increment/Decrement operators" RFC, meaning that incrementing non-numeric strings is now deprecated. (Girgias). + . Various closure binding issues are now deprecated. (alexandre-daubois) - Filter: . Added support for configuring the URI parser for FILTER_VALIDATE_URL diff --git a/UPGRADING b/UPGRADING index 02cdca916c14c..dd37bb21b4527 100644 --- a/UPGRADING +++ b/UPGRADING @@ -360,6 +360,16 @@ PHP 8.5 UPGRADE NOTES operators" RFC, meaning that incrementing non-numeric strings is now deprecated. Instead the str_increment() function should be used. RFC: https://wiki.php.net/rfc/deprecations_php_8_5#enact_follow-up_phase_of_the_path_to_saner_incrementdecrement_operators_rfc + . The following closure binding issues, which already emit an E_WARNING, are + now deprecated: + - Binding an instance to a static closure + - Binding methods to objects that are not instances of the class + (or subclass) that the method is defined + - Unbinding $this from a method + - Unbinding $this from a closure that uses `$this` + - Binding a closure to the scope of an internal class + - Rebinding the scope of a closure created from a function or method + RFC: https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_closure_binding_issues - Curl: . The curl_close() function has been deprecated, as CurlHandle objects are diff --git a/Zend/tests/bug70681.phpt b/Zend/tests/bug70681.phpt index d0cc9523a94e2..39c10aa236c44 100644 --- a/Zend/tests/bug70681.phpt +++ b/Zend/tests/bug70681.phpt @@ -12,5 +12,5 @@ var_dump($c("foo")); ?> --EXPECTF-- -Warning: Cannot unbind $this of method in %s on line %d +Warning: Cannot unbind $this of method, this will be an error in PHP 9 in %s on line %d int(3) diff --git a/Zend/tests/closures/bug70630.phpt b/Zend/tests/closures/bug70630.phpt index 0e9e5449758f9..c75920899652c 100644 --- a/Zend/tests/closures/bug70630.phpt +++ b/Zend/tests/closures/bug70630.phpt @@ -7,4 +7,4 @@ $x = (new ReflectionFunction("substr"))->getClosure(); $x->call(new a); ?> --EXPECTF-- -Warning: Cannot rebind scope of closure created from function in %s on line %d +Warning: Cannot rebind scope of closure created from function, this will be an error in PHP 9 in %s on line %d diff --git a/Zend/tests/closures/bug70685.phpt b/Zend/tests/closures/bug70685.phpt index 737b4469fdbe4..7cb6aa094de42 100644 --- a/Zend/tests/closures/bug70685.phpt +++ b/Zend/tests/closures/bug70685.phpt @@ -15,8 +15,8 @@ var_dump($c); ?> --EXPECTF-- -Warning: Cannot bind method SplDoublyLinkedList::count() to object of class cls in %s on line %d +Warning: Cannot bind method SplDoublyLinkedList::count() to object of class cls, this will be an error in PHP 9 in %s on line %d NULL -Warning: Cannot rebind scope of closure created from method in %s on line %d +Warning: Cannot rebind scope of closure created from method, this will be an error in PHP 9 in %s on line %d NULL diff --git a/Zend/tests/closures/closure_040.phpt b/Zend/tests/closures/closure_040.phpt index 436c99939b1ee..b733bdbef0537 100644 --- a/Zend/tests/closures/closure_040.phpt +++ b/Zend/tests/closures/closure_040.phpt @@ -36,4 +36,4 @@ $cas->bindTo($a, 'A'); --EXPECTF-- Closure::bindTo(): Argument #2 ($newScope) must be of type object|string|null, array given -Warning: Cannot bind an instance to a static closure in %s on line %d +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d diff --git a/Zend/tests/closures/closure_041.phpt b/Zend/tests/closures/closure_041.phpt index d709257484115..64afde4ea22b1 100644 --- a/Zend/tests/closures/closure_041.phpt +++ b/Zend/tests/closures/closure_041.phpt @@ -80,16 +80,16 @@ bound: no scoped to A: bool(true) bound: no -Warning: Cannot unbind $this of closure using $this in %s on line %d +Warning: Cannot unbind $this of closure using $this, this will be an error in PHP 9 in %s on line %d NULL After binding, with same-class instance for the bound ones -Warning: Cannot bind an instance to a static closure in %s on line %d +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d scoped to A: bool(false) bound: A (should be scoped to dummy class) -Warning: Cannot bind an instance to a static closure in %s on line %d +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d scoped to A: bool(true) bound: A After binding, with different instance for the bound ones diff --git a/Zend/tests/closures/closure_043.phpt b/Zend/tests/closures/closure_043.phpt index bfcd37b38e1f5..8f60bd272469f 100644 --- a/Zend/tests/closures/closure_043.phpt +++ b/Zend/tests/closures/closure_043.phpt @@ -56,9 +56,9 @@ bool(false) After binding, null scope, with instance -Warning: Cannot bind an instance to a static closure in %s on line %d +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d -Warning: Cannot bind an instance to a static closure in %s on line %d +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d After binding, with scope, no instance bool(true) bool(false) @@ -68,7 +68,7 @@ bool(false) After binding, with scope, with instance -Warning: Cannot bind an instance to a static closure in %s on line %d +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d -Warning: Cannot bind an instance to a static closure in %s on line %d +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d Done. diff --git a/Zend/tests/closures/closure_044.phpt b/Zend/tests/closures/closure_044.phpt index 544ad8bee8445..624450c168815 100644 --- a/Zend/tests/closures/closure_044.phpt +++ b/Zend/tests/closures/closure_044.phpt @@ -52,7 +52,7 @@ bool(false) bool(false) -Warning: Cannot unbind $this of closure using $this in %s on line %d +Warning: Cannot unbind $this of closure using $this, this will be an error in PHP 9 in %s on line %d NULL After binding, null scope, with instance @@ -67,7 +67,7 @@ bool(true) bool(false) -Warning: Cannot unbind $this of closure using $this in %s on line %d +Warning: Cannot unbind $this of closure using $this, this will be an error in PHP 9 in %s on line %d NULL After binding, with scope, with instance diff --git a/Zend/tests/closures/closure_046.phpt b/Zend/tests/closures/closure_046.phpt index 9dbcba5ce5442..19dd69e2a6fd2 100644 --- a/Zend/tests/closures/closure_046.phpt +++ b/Zend/tests/closures/closure_046.phpt @@ -50,7 +50,7 @@ bool(false) bool(false) -Warning: Cannot unbind $this of closure using $this in %s on line %d +Warning: Cannot unbind $this of closure using $this, this will be an error in PHP 9 in %s on line %d NULL After binding, with same-class instance for the bound one diff --git a/Zend/tests/closures/closure_061.phpt b/Zend/tests/closures/closure_061.phpt index 240f22e036ef7..23ab2f87a1c5b 100644 --- a/Zend/tests/closures/closure_061.phpt +++ b/Zend/tests/closures/closure_061.phpt @@ -118,13 +118,13 @@ bindTo(new Cls, null): Success! bindTo(new Cls, Cls::class): -Cannot rebind scope of closure created from function +Cannot rebind scope of closure created from function, this will be an error in PHP 9 bindTo(null, Cls::class): -Cannot rebind scope of closure created from function +Cannot rebind scope of closure created from function, this will be an error in PHP 9 bindTo(null, stdClass::class): -Cannot bind closure to scope of internal class stdClass +Cannot bind closure to scope of internal class stdClass, this will be an error in PHP 9 bindTo(new stdClass, null): Success! @@ -139,13 +139,13 @@ bindTo(new Cls, null): Success! bindTo(new Cls, Cls::class): -Cannot rebind scope of closure created from function +Cannot rebind scope of closure created from function, this will be an error in PHP 9 bindTo(null, Cls::class): -Cannot rebind scope of closure created from function +Cannot rebind scope of closure created from function, this will be an error in PHP 9 bindTo(null, stdClass::class): -Cannot bind closure to scope of internal class stdClass +Cannot bind closure to scope of internal class stdClass, this will be an error in PHP 9 bindTo(new stdClass, null): Success! @@ -157,25 +157,25 @@ bindTo(null, Cls::class): Success! bindTo(new Cls, null): -Cannot bind an instance to a static closure +Cannot bind an instance to a static closure, this will be an error in PHP 9 bindTo(new Cls, Cls::class): -Cannot bind an instance to a static closure +Cannot bind an instance to a static closure, this will be an error in PHP 9 bindTo(null, null): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 bindTo(null, ClsChild::class): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 bindTo(null, ClsUnrelated::class): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 (new Cls)->method() ------------------- bindTo(null, Cls::class): -Cannot unbind $this of method +Cannot unbind $this of method, this will be an error in PHP 9 bindTo(new Cls, Cls::class): Success! @@ -184,16 +184,16 @@ bindTo(new ClsChild, Cls::class): Success! bindTo(new ClsUnrelated, Cls::class): -Cannot bind method Cls::method() to object of class ClsUnrelated +Cannot bind method Cls::method() to object of class ClsUnrelated, this will be an error in PHP 9 bindTo(new Cls, null): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 bindTo(new Cls, ClsUnrelated::class): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 bindTo(new Cls, ClsChild::class): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 (new SplDoublyLinkedList)->count() ---------------------------------- @@ -205,19 +205,19 @@ bindTo(new SplStack, SplDoublyLinkedList::class): Success! bindTo(new ClsUnrelated, SplDoublyLinkedList::class): -Cannot bind method SplDoublyLinkedList::count() to object of class ClsUnrelated +Cannot bind method SplDoublyLinkedList::count() to object of class ClsUnrelated, this will be an error in PHP 9 bindTo(null, null): -Cannot unbind $this of method +Cannot unbind $this of method, this will be an error in PHP 9 bindTo(null, SplDoublyLinkedList::class): -Cannot unbind $this of method +Cannot unbind $this of method, this will be an error in PHP 9 bindTo(new SplDoublyLinkedList, null): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 bindTo(new SplDoublyLinkedList, ClsUnrelated::class): -Cannot rebind scope of closure created from method +Cannot rebind scope of closure created from method, this will be an error in PHP 9 (function() {})() ----------------- @@ -235,7 +235,7 @@ bindTo(null, Cls::class): Success! bindTo(null, stdClass::class): -Cannot bind closure to scope of internal class stdClass +Cannot bind closure to scope of internal class stdClass, this will be an error in PHP 9 bindTo(new stdClass, null): Success! diff --git a/Zend/tests/closures/closure_062.phpt b/Zend/tests/closures/closure_062.phpt index b8c0a981be527..d3db7998eea16 100644 --- a/Zend/tests/closures/closure_062.phpt +++ b/Zend/tests/closures/closure_062.phpt @@ -48,7 +48,7 @@ Test::staticMethod(); --EXPECTF-- instance scoped, non-static, $this used -Warning: Cannot unbind $this of closure using $this in %s on line %d +Warning: Cannot unbind $this of closure using $this, this will be an error in PHP 9 in %s on line %d instance scoped, static, $this used instance scoped, non-static, $this not used static scoped, non-static, $this used diff --git a/Zend/tests/closures/closure_call.phpt b/Zend/tests/closures/closure_call.phpt index f665c67ff691f..cfc5f51af9661 100644 --- a/Zend/tests/closures/closure_call.phpt +++ b/Zend/tests/closures/closure_call.phpt @@ -61,7 +61,7 @@ int(0) int(0) int(3) -Warning: Cannot bind closure to scope of internal class stdClass in %s line %d +Warning: Cannot bind closure to scope of internal class stdClass, this will be an error in PHP 9 in %s line %d NULL int(21) int(3) diff --git a/Zend/tests/closures/closure_from_callable_rebinding.phpt b/Zend/tests/closures/closure_from_callable_rebinding.phpt index 6fb5c6ffc1d0c..c23841a30c3ae 100644 --- a/Zend/tests/closures/closure_from_callable_rebinding.phpt +++ b/Zend/tests/closures/closure_from_callable_rebinding.phpt @@ -17,4 +17,4 @@ $fn->call(new B); ?> --EXPECTF-- -Warning: Cannot bind method A::method() to object of class B in %s on line %d +Warning: Cannot bind method A::method() to object of class B, this will be an error in PHP 9 in %s on line %d diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index bdcdc329647ca..22fd30463726f 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -81,14 +81,14 @@ static bool zend_valid_closure_binding( bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0; if (newthis) { if (func->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(E_WARNING, "Cannot bind an instance to a static closure"); + zend_error(E_WARNING, "Cannot bind an instance to a static closure, this will be an error in PHP 9"); return 0; } if (is_fake_closure && func->common.scope && !instanceof_function(Z_OBJCE_P(newthis), func->common.scope)) { /* Binding incompatible $this to an internal method is not supported. */ - zend_error(E_WARNING, "Cannot bind method %s::%s() to object of class %s", + zend_error(E_WARNING, "Cannot bind method %s::%s() to object of class %s, this will be an error in PHP 9", ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name), ZSTR_VAL(Z_OBJCE_P(newthis)->name)); @@ -96,26 +96,26 @@ static bool zend_valid_closure_binding( } } else if (is_fake_closure && func->common.scope && !(func->common.fn_flags & ZEND_ACC_STATIC)) { - zend_error(E_WARNING, "Cannot unbind $this of method"); + zend_error(E_WARNING, "Cannot unbind $this of method, this will be an error in PHP 9"); return 0; } else if (!is_fake_closure && !Z_ISUNDEF(closure->this_ptr) && (func->common.fn_flags & ZEND_ACC_USES_THIS)) { - zend_error(E_WARNING, "Cannot unbind $this of closure using $this"); + zend_error(E_WARNING, "Cannot unbind $this of closure using $this, this will be an error in PHP 9"); return 0; } if (scope && scope != func->common.scope && scope->type == ZEND_INTERNAL_CLASS) { /* rebinding to internal class is not allowed */ - zend_error(E_WARNING, "Cannot bind closure to scope of internal class %s", + zend_error(E_WARNING, "Cannot bind closure to scope of internal class %s, this will be an error in PHP 9", ZSTR_VAL(scope->name)); return 0; } if (is_fake_closure && scope != func->common.scope) { if (func->common.scope == NULL) { - zend_error(E_WARNING, "Cannot rebind scope of closure created from function"); + zend_error(E_WARNING, "Cannot rebind scope of closure created from function, this will be an error in PHP 9"); } else { - zend_error(E_WARNING, "Cannot rebind scope of closure created from method"); + zend_error(E_WARNING, "Cannot rebind scope of closure created from method, this will be an error in PHP 9"); } return 0; } diff --git a/docs/source/miscellaneous/stubs.rst b/docs/source/miscellaneous/stubs.rst index 3899fe3084196..616d306895542 100644 --- a/docs/source/miscellaneous/stubs.rst +++ b/docs/source/miscellaneous/stubs.rst @@ -223,7 +223,8 @@ The generated ``class_Atmosphere_methods`` must be used when registering the ``A Additional meta information can be attached to functions, with the following PHPDoc tags: -- ``@deprecated``: Triggers the usual deprecation notice when the function/method is called. +- ``@deprecated``: Triggers the usual deprecation notice when the function/method is called. As of + PHP 8.4 the `#[Deprecated]` attribute should be used instead. - ``@alias``: If a function/method is an alias of another function/method, then the aliased function/method name has to be provided as value. E.g. the function ``sizeof()`` has the ``@alias @@ -244,7 +245,7 @@ Additional meta information can be attached to functions, with the following PHP - ``@genstubs-expose-comment-block``: By adding this annotation at the beginning of a PHPDoc block, the content of the PHPDoc block will be exposed for - `ReflectionFunctionAbstract::getDocComment()`. This feature was added in PHP 8.4.0. + `ReflectionFunctionAbstract::getDocComment()`. This feature was added in PHP 8.4. .. _tentative return type: https://wiki.php.net/rfc/internal_method_return_types @@ -337,7 +338,7 @@ Like functions and methods, classes also support meta information passed via PHP - ``@genstubs-expose-comment-block``: By adding this tag at the beginning of a PHPDoc block, the content of the PHPDoc block will be exposed for `ReflectionClass::getDocComment()`. This feature - is only available as of PHP 8.4.0. + is only available as of PHP 8.4. This is an example with all the flags: @@ -452,11 +453,12 @@ with ``@cvalue M_PI`` to the C-level constant ``M_PI`` (define by PHP's internal Constants can take the following extra meta information passed via PHPDoc tags: -- ``@deprecated``: Triggers a deprecation notice when the constant is used. +- ``@deprecated``: Triggers a deprecation notice when the constant is used. As of PHP 8.5 the + `#[Deprecated]` attribute should be used instead. - ``@genstubs-expose-comment-block``: By adding this tag at the beginning of a PHPDoc block, the content of the PHPDoc block will be exposed for `ReflectionClass::getDocComment()`. This feature - is only available as of PHP 8.4.0. + is only available as of PHP 8.4. ************************************ Maintaining Backward Compatibility