RFC: Add #[\Deprecated] Attribute (#11293)

see https://wiki.php.net/rfc/deprecated_attribute

Co-authored-by: Tim Düsterhus <tim@tideways-gmbh.com>
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
This commit is contained in:
Benjamin Eberlei 2024-07-02 09:44:25 +02:00 committed by GitHub
parent 8291e81c00
commit 72c874691b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 1401 additions and 165 deletions

1
NEWS
View file

@ -32,6 +32,7 @@ PHP NEWS
(Julien Voisin) (Julien Voisin)
. Fixed bug GH-11928 (The --enable-re2c-cgoto doesn't add the -g flag). . Fixed bug GH-11928 (The --enable-re2c-cgoto doesn't add the -g flag).
(Peter Kokot) (Peter Kokot)
. Added the #[\Deprecated] attribute. (beberlei, timwolla)
- Curl: - Curl:
. Deprecated the CURLOPT_BINARYTRANSFER constant. (divinity76) . Deprecated the CURLOPT_BINARYTRANSFER constant. (divinity76)

View file

@ -213,6 +213,8 @@ PHP 8.4 UPGRADE NOTES
they allow chaining method calls, property accesses, etc. without enclosing they allow chaining method calls, property accesses, etc. without enclosing
the expression in parentheses. the expression in parentheses.
RFC: https://wiki.php.net/rfc/new_without_parentheses RFC: https://wiki.php.net/rfc/new_without_parentheses
. Added the #[\Deprecated] attribute.
RFC: https://wiki.php.net/rfc/deprecated_attribute
- Curl: - Curl:
. curl_version() returns an additional feature_list value, which is an . curl_version() returns an additional feature_list value, which is an

View file

@ -78,7 +78,7 @@ static void zend_delete_call_instructions(zend_op_array *op_array, zend_op *opli
static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_op *opline, zend_function *func) static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_op *opline, zend_function *func)
{ {
if (func->type == ZEND_USER_FUNCTION if (func->type == ZEND_USER_FUNCTION
&& !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS)) && !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_DEPRECATED))
/* TODO: function copied from trait may be inconsistent ??? */ /* TODO: function copied from trait may be inconsistent ??? */
&& !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE)) && !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE))
&& fcall->extended_value >= func->op_array.required_num_args && fcall->extended_value >= func->op_array.required_num_args

View file

@ -0,0 +1,43 @@
--TEST--
#[\Deprecated]: Class Constants.
--FILE--
<?php
class Clazz {
#[\Deprecated]
public const TEST = 1;
#[\Deprecated()]
public const TEST2 = 2;
#[\Deprecated("use Clazz::TEST instead")]
public const TEST3 = 3;
#[\Deprecated]
public const TEST4 = 4;
#[\Deprecated]
public const TEST5 = 5;
}
var_dump(Clazz::TEST);
var_dump(Clazz::TEST2);
var_dump(Clazz::TEST3);
var_dump(constant('Clazz::TEST4'));
var_dump(defined('Clazz::TEST5'));
?>
--EXPECTF--
Deprecated: Constant Clazz::TEST is deprecated in %s on line %d
int(1)
Deprecated: Constant Clazz::TEST2 is deprecated in %s on line %d
int(2)
Deprecated: Constant Clazz::TEST3 is deprecated, use Clazz::TEST instead in %s on line %d
int(3)
Deprecated: Constant Clazz::TEST4 is deprecated in %s on line %d
int(4)
bool(true)

View file

@ -0,0 +1,21 @@
--TEST--
#[\Deprecated]: Enum Cases.
--FILE--
<?php
enum E {
#[\Deprecated]
case Test;
#[\Deprecated("use E::Test instead")]
case Test2;
}
E::Test;
E::Test2;
?>
--EXPECTF--
Deprecated: Enum case E::Test is deprecated in %s on line %d
Deprecated: Enum case E::Test2 is deprecated, use E::Test instead in %s on line %d

View file

@ -0,0 +1,26 @@
--TEST--
#[\Deprecated]: Using the value of a deprecated class constant as the deprecation message.
--FILE--
<?php
class Clazz {
#[\Deprecated(self::TEST)]
public const TEST = "from itself";
#[\Deprecated]
public const TEST2 = "from another";
#[\Deprecated(self::TEST2)]
public const TEST3 = 1;
}
Clazz::TEST;
Clazz::TEST3;
?>
--EXPECTF--
Deprecated: Constant Clazz::TEST is deprecated, from itself in %s on line %d
Deprecated: Constant Clazz::TEST2 is deprecated in %s on line %d
Deprecated: Constant Clazz::TEST3 is deprecated, from another in %s on line %d

View file

@ -0,0 +1,36 @@
--TEST--
#[\Deprecated]: Using the value of a deprecated class constant as the deprecation message with a throwing error handler.
--FILE--
<?php
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});
class Clazz {
#[\Deprecated(self::TEST)]
public const TEST = "from itself";
#[\Deprecated]
public const TEST2 = "from another";
#[\Deprecated(self::TEST2)]
public const TEST3 = 1;
}
try {
Clazz::TEST;
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
try {
Clazz::TEST3;
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
Caught: Constant Clazz::TEST is deprecated, from itself
Caught: Constant Clazz::TEST2 is deprecated

View file

@ -0,0 +1,23 @@
--TEST--
#[\Deprecated]: Using the value of a deprecated class constant in a constant expression.
--FILE--
<?php
class Clazz {
#[\Deprecated("prefix")]
public const PREFIX = "prefix";
#[\Deprecated("suffix")]
public const SUFFIX = "suffix";
public const CONSTANT = self::PREFIX . self::SUFFIX;
}
var_dump(Clazz::CONSTANT);
?>
--EXPECTF--
Deprecated: Constant Clazz::PREFIX is deprecated, prefix in %s on line %d
Deprecated: Constant Clazz::SUFFIX is deprecated, suffix in %s on line %d
string(12) "prefixsuffix"

View file

@ -0,0 +1,21 @@
--TEST--
#[\Deprecated]: Code is E_USER_DEPRECATED for class constants.
--FILE--
<?php
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
var_dump($errno, E_USER_DEPRECATED, $errno === E_USER_DEPRECATED);
});
class Clazz {
#[\Deprecated]
public const TEST = 1;
}
Clazz::TEST;
?>
--EXPECT--
int(16384)
int(16384)
bool(true)

View file

@ -0,0 +1,21 @@
--TEST--
#[\Deprecated]: Class constant with value unknown at compile time.
--FILE--
<?php
define('SUFFIX', random_int(1, 2) == 1 ? 'a' : 'b');
class Clazz {
#[\Deprecated]
public const CONSTANT = self::class . '-' . SUFFIX;
}
$value = Clazz::CONSTANT;
var_dump($value);
var_dump($value === 'Clazz-' . SUFFIX);
?>
--EXPECTF--
Deprecated: Constant Clazz::CONSTANT is deprecated in %s on line %d
string(7) "Clazz-%c"
bool(true)

View file

@ -0,0 +1,76 @@
--TEST--
#[\Deprecated]: Functions and Methods.
--FILE--
<?php
#[\Deprecated]
function test() {
}
#[\Deprecated("use test() instead")]
function test2() {
}
class Clazz {
#[\Deprecated]
function test() {
}
#[\Deprecated("use test() instead")]
function test2() {
}
}
$closure = #[\Deprecated] function() {
};
$closure2 = #[\Deprecated] function() {
};
class Constructor {
#[\Deprecated]
public function __construct() {
}
#[\Deprecated]
public function __destruct() {
}
}
test();
test2();
call_user_func("test");
$cls = new Clazz();
$cls->test();
$cls->test2();
call_user_func([$cls, "test"]);
$closure();
$closure2();
new Constructor();
?>
--EXPECTF--
Deprecated: Function test() is deprecated in %s
Deprecated: Function test2() is deprecated, use test() instead in %s on line %d
Deprecated: Function test() is deprecated in %s on line %d
Deprecated: Method Clazz::test() is deprecated in %s
Deprecated: Method Clazz::test2() is deprecated, use test() instead in %s
Deprecated: Method Clazz::test() is deprecated in %s
Deprecated: Function {closure:%s:%d}() is deprecated in %s on line %d
Deprecated: Function {closure:%s:%d}() is deprecated in %s on line %d
Deprecated: Method Constructor::__construct() is deprecated in %s on line %d
Deprecated: Method Constructor::__destruct() is deprecated in %s on line %d

View file

@ -0,0 +1,18 @@
--TEST--
#[\Deprecated]: Exception Handler is deprecated.
--FILE--
<?php
#[\Deprecated]
function my_exception_handler($e) {
echo "Handled: ", $e->getMessage(), PHP_EOL;
};
set_exception_handler('my_exception_handler');
throw new \Exception('test');
?>
--EXPECT--
Deprecated: Function my_exception_handler() is deprecated in Unknown on line 0
Handled: test

View file

@ -0,0 +1,31 @@
--TEST--
#[\Deprecated]: Exception Handler is deprecated for throwing error handler.
--FILE--
<?php
function my_error_handler(int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler('my_error_handler');
#[\Deprecated]
function my_exception_handler($e) {
echo "Handled: ", $e->getMessage(), PHP_EOL;
};
set_exception_handler('my_exception_handler');
#[\Deprecated]
function test() {
}
test();
?>
--EXPECTF--
Fatal error: Uncaught ErrorException: Function my_exception_handler() is deprecated in Unknown:0
Stack trace:
#0 [internal function]: my_error_handler(%d, '%s', '%s', %d)
#1 {main}
thrown in Unknown on line 0

View file

@ -0,0 +1,22 @@
--TEST--
#[\Deprecated]: Error Handler is deprecated.
--FILE--
<?php
#[\Deprecated]
function my_error_handler(int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
echo $errstr, PHP_EOL;
};
set_error_handler('my_error_handler');
#[\Deprecated]
function test() {
}
test();
?>
--EXPECTF--
Deprecated: Function my_error_handler() is deprecated in %s on line %d
Function test() is deprecated

View file

@ -0,0 +1,20 @@
--TEST--
#[\Deprecated]: Code is E_USER_DEPRECATED for functions.
--FILE--
<?php
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
var_dump($errno, E_USER_DEPRECATED, $errno === E_USER_DEPRECATED);
});
#[\Deprecated]
function test() {
}
test();
?>
--EXPECT--
int(16384)
int(16384)
bool(true)

View file

@ -0,0 +1,16 @@
--TEST--
#[\Deprecated]: Message from constant.
--FILE--
<?php
#[\Deprecated(DEPRECATION_MESSAGE)]
function test() {
}
define('DEPRECATION_MESSAGE', 'from constant');
test();
?>
--EXPECTF--
Deprecated: Function test() is deprecated, from constant in %s on line %d

View file

@ -0,0 +1,22 @@
--TEST--
#[\Deprecated]: Message from protected class constant.
--FILE--
<?php
class P {
protected const DEPRECATION_MESSAGE = 'from class constant';
}
class Clazz extends P {
#[\Deprecated(parent::DEPRECATION_MESSAGE)]
public function test() {
}
}
$c = new Clazz();
$c->test();
?>
--EXPECTF--
Deprecated: Method Clazz::test() is deprecated, from class constant in %s on line %d

View file

@ -0,0 +1,91 @@
--TEST--
#[\Deprecated]: Throwing error handler.
--FILE--
<?php
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});
#[\Deprecated("convert to exception")]
function test() {
echo "Not executed", PHP_EOL;
}
try {
test();
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
eval(<<<'CODE'
#[\Deprecated("convert to exception")]
function test2() {
echo "Not executed", PHP_EOL;
}
CODE);
try {
test2();
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
class Clazz {
#[\Deprecated("convert to exception")]
function test() {
echo "Not executed", PHP_EOL;
}
}
try {
$cls = new Clazz();
$cls->test();
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
$closure = #[\Deprecated("convert to exception")] function () {
echo "Not executed", PHP_EOL;
};
try {
$closure();
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
class Constructor {
#[\Deprecated("convert to exception")]
public function __construct() {
echo "Not executed", PHP_EOL;
}
}
try {
new Constructor();
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
class Destructor {
#[\Deprecated("convert to exception")]
public function __destruct() {
echo "Not executed", PHP_EOL;
}
}
try {
new Destructor();
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
?>
--EXPECTF--
Caught: Function test() is deprecated, convert to exception
Caught: Function test2() is deprecated, convert to exception
Caught: Method Clazz::test() is deprecated, convert to exception
Caught: Function {closure:%s:%d}() is deprecated, convert to exception
Caught: Method Constructor::__construct() is deprecated, convert to exception
Caught: Method Destructor::__destruct() is deprecated, convert to exception

View file

@ -0,0 +1,21 @@
--TEST--
#[\Deprecated]: Throwing error handler when using the return value.
--FILE--
<?php
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});
#[Deprecated]
function test() {}
try {
$x = test();
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
Caught: Function test() is deprecated

View file

@ -0,0 +1,21 @@
--TEST--
#[\Deprecated]: Throwing error handler does not leak parameters.
--FILE--
<?php
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});
#[Deprecated]
function test($dummy) {}
try {
$x = test(new stdClass());
} catch (ErrorException $e) {
echo "Caught: ", $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
Caught: Function test() is deprecated

View file

@ -0,0 +1,49 @@
--TEST--
#[\Deprecated]: Message Formats.
--FILE--
<?php
#[\Deprecated]
function test1() {
}
#[\Deprecated()]
function test2() {
}
#[\Deprecated("use test() instead")]
function test3() {
}
#[\Deprecated(message: "use test() instead", since: "1.0")]
function test4() {
}
#[\Deprecated(since: "1.0", message: "use test() instead")]
function test5() {
}
#[\Deprecated(since: "1.0")]
function test6() {
}
test1();
test2();
test3();
test4();
test5();
test6();
?>
--EXPECTF--
Deprecated: Function test1() is deprecated in %s on line %d
Deprecated: Function test2() is deprecated in %s on line %d
Deprecated: Function test3() is deprecated, use test() instead in %s on line %d
Deprecated: Function test4() is deprecated since 1.0, use test() instead in %s on line %d
Deprecated: Function test5() is deprecated since 1.0, use test() instead in %s on line %d
Deprecated: Function test6() is deprecated since 1.0 in %s on line %d

View file

@ -0,0 +1,14 @@
--TEST--
#[\Deprecated]: Message is empty.
--FILE--
<?php
#[\Deprecated("")]
function test() {
}
test();
?>
--EXPECTF--
Deprecated: Function test() is deprecated in %s on line %d

View file

@ -0,0 +1,14 @@
--TEST--
#[\Deprecated]: Message contains NUL bytes.
--FILE--
<?php
#[\Deprecated("Here is a NUL \x00 Byte")]
function test() {
}
test();
?>
--EXPECTF--
Deprecated: Function test() is deprecated, Here is a NUL %0 Byte in %s on line %d

View file

@ -0,0 +1,16 @@
--TEST--
#[\Deprecated]: Message with value unknown at compile time.
--FILE--
<?php
define('MESSAGE', 'value-' . (random_int(1, 2) == 1 ? 'a' : 'b'));
#[\Deprecated(MESSAGE)]
function test() {
}
test();
?>
--EXPECTF--
Deprecated: Function test() is deprecated, value-%c in %s on line %d

View file

@ -0,0 +1,14 @@
--TEST--
#[\Deprecated]: Deprecated::$message is readonly.
--FILE--
<?php
$d = new \Deprecated("foo");
$d->message = 'bar';
?>
--EXPECTF--
Fatal error: Uncaught Error: Cannot modify readonly property Deprecated::$message in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View file

@ -0,0 +1,14 @@
--TEST--
#[\Deprecated]: Deprecated::$since is readonly.
--FILE--
<?php
$d = new \Deprecated("foo", "1.0");
$d->since = "2.0";
?>
--EXPECTF--
Fatal error: Uncaught Error: Cannot modify readonly property Deprecated::$since in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View file

@ -0,0 +1,15 @@
--TEST--
#[\Deprecated]: __construct() respects that properties are readonly.
--FILE--
<?php
$d = new \Deprecated("foo");
$d->__construct("bar");
?>
--EXPECTF--
Fatal error: Uncaught Error: Cannot modify readonly property Deprecated::$message in %s:%d
Stack trace:
#0 %s(%d): Deprecated->__construct('bar')
#1 {main}
thrown in %s on line %d

View file

@ -0,0 +1,14 @@
--TEST--
#[\Deprecated]: Type validation of $message parameter with int.
--FILE--
<?php
#[\Deprecated(1234)]
function test() {
}
test();
?>
--EXPECTF--
Deprecated: Function test() is deprecated, 1234 in %s on line %d

View file

@ -0,0 +1,19 @@
--TEST--
#[\Deprecated]: Type validation of $message parameter with int and strict types.
--FILE--
<?php
declare(strict_types = 1);
#[\Deprecated(1234)]
function test() {
}
test();
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Deprecated::__construct(): Argument #1 ($message) must be of type ?string, int given in %s:%d
Stack trace:
#0 %s(%d): Deprecated->__construct(1234)
#1 {main}
thrown in %s on line %d

View file

@ -0,0 +1,17 @@
--TEST--
#[\Deprecated]: Type validation of $message parameter with array.
--FILE--
<?php
#[\Deprecated([])]
function test() {
}
test();
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Deprecated::__construct(): Argument #1 ($message) must be of type ?string, array given in %s:%d
Stack trace:
#0 %s(%d): Deprecated->__construct(Array)
#1 {main}
thrown in %s on line %d

View file

@ -0,0 +1,17 @@
--TEST--
#[\Deprecated]: Type validation of $message parameter with native enum case.
--FILE--
<?php
#[\Deprecated(\Random\IntervalBoundary::ClosedOpen)]
function test() {
}
test();
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Deprecated::__construct(): Argument #1 ($message) must be of type ?string, Random\IntervalBoundary given in %s:%d
Stack trace:
#0 %s(%d): Deprecated->__construct(Random\IntervalBoundary::ClosedOpen)
#1 {main}
thrown in %s on line %d

View file

@ -30,6 +30,7 @@ ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
ZEND_API zend_class_entry *zend_ce_sensitive_parameter; ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
ZEND_API zend_class_entry *zend_ce_override; ZEND_API zend_class_entry *zend_ce_override;
ZEND_API zend_class_entry *zend_ce_deprecated;
static zend_object_handlers attributes_object_handlers_sensitive_parameter_value; static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;
@ -146,6 +147,43 @@ ZEND_METHOD(Override, __construct)
ZEND_PARSE_PARAMETERS_NONE(); ZEND_PARSE_PARAMETERS_NONE();
} }
ZEND_METHOD(Deprecated, __construct)
{
zend_string *message = NULL;
zend_string *since = NULL;
zval value;
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(message)
Z_PARAM_STR_OR_NULL(since)
ZEND_PARSE_PARAMETERS_END();
if (message) {
ZVAL_STR(&value, message);
} else {
ZVAL_NULL(&value);
}
zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value);
/* The assignment might fail due to 'readonly'. */
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
if (since) {
ZVAL_STR(&value, since);
} else {
ZVAL_NULL(&value);
}
zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_SINCE), &value);
/* The assignment might fail due to 'readonly'. */
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
}
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
{ {
if (attributes) { if (attributes) {
@ -470,6 +508,9 @@ void zend_register_attribute_ce(void)
zend_ce_override = register_class_Override(); zend_ce_override = register_class_Override();
zend_mark_internal_attribute(zend_ce_override); zend_mark_internal_attribute(zend_ce_override);
zend_ce_deprecated = register_class_Deprecated();
attr = zend_mark_internal_attribute(zend_ce_deprecated);
} }
void zend_attributes_shutdown(void) void zend_attributes_shutdown(void)

View file

@ -46,6 +46,7 @@ extern ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter; extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
extern ZEND_API zend_class_entry *zend_ce_override; extern ZEND_API zend_class_entry *zend_ce_override;
extern ZEND_API zend_class_entry *zend_ce_deprecated;
typedef struct { typedef struct {
zend_string *name; zend_string *name;

View file

@ -71,3 +71,16 @@ final class Override
{ {
public function __construct() {} public function __construct() {}
} }
/**
* @strict-properties
*/
#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION|Attribute::TARGET_CLASS_CONSTANT)]
final class Deprecated
{
public readonly ?string $message;
public readonly ?string $since;
public function __construct(?string $message = null, ?string $since = null) {}
}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 32f0458c20f04099e353a8300ffb19e40bc38f69 */ * Stub hash: 2358a0d820edd06a1702c84104bfd545af08311c */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL")
@ -24,6 +24,11 @@ ZEND_END_ARG_INFO()
#define arginfo_class_Override___construct arginfo_class_ReturnTypeWillChange___construct #define arginfo_class_Override___construct arginfo_class_ReturnTypeWillChange___construct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Deprecated___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, since, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_METHOD(Attribute, __construct); ZEND_METHOD(Attribute, __construct);
ZEND_METHOD(ReturnTypeWillChange, __construct); ZEND_METHOD(ReturnTypeWillChange, __construct);
ZEND_METHOD(AllowDynamicProperties, __construct); ZEND_METHOD(AllowDynamicProperties, __construct);
@ -32,6 +37,7 @@ ZEND_METHOD(SensitiveParameterValue, __construct);
ZEND_METHOD(SensitiveParameterValue, getValue); ZEND_METHOD(SensitiveParameterValue, getValue);
ZEND_METHOD(SensitiveParameterValue, __debugInfo); ZEND_METHOD(SensitiveParameterValue, __debugInfo);
ZEND_METHOD(Override, __construct); ZEND_METHOD(Override, __construct);
ZEND_METHOD(Deprecated, __construct);
static const zend_function_entry class_Attribute_methods[] = { static const zend_function_entry class_Attribute_methods[] = {
ZEND_ME(Attribute, __construct, arginfo_class_Attribute___construct, ZEND_ACC_PUBLIC) ZEND_ME(Attribute, __construct, arginfo_class_Attribute___construct, ZEND_ACC_PUBLIC)
@ -65,6 +71,11 @@ static const zend_function_entry class_Override_methods[] = {
ZEND_FE_END ZEND_FE_END
}; };
static const zend_function_entry class_Deprecated_methods[] = {
ZEND_ME(Deprecated, __construct, arginfo_class_Deprecated___construct, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static zend_class_entry *register_class_Attribute(void) static zend_class_entry *register_class_Attribute(void)
{ {
zend_class_entry ce, *class_entry; zend_class_entry ce, *class_entry;
@ -225,3 +236,33 @@ static zend_class_entry *register_class_Override(void)
return class_entry; return class_entry;
} }
static zend_class_entry *register_class_Deprecated(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "Deprecated", class_Deprecated_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES;
zval property_message_default_value;
ZVAL_UNDEF(&property_message_default_value);
zend_string *property_message_name = zend_string_init("message", sizeof("message") - 1, 1);
zend_declare_typed_property(class_entry, property_message_name, &property_message_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL));
zend_string_release(property_message_name);
zval property_since_default_value;
ZVAL_UNDEF(&property_since_default_value);
zend_string *property_since_name = zend_string_init("since", sizeof("since") - 1, 1);
zend_declare_typed_property(class_entry, property_since_name, &property_since_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL));
zend_string_release(property_since_name);
zend_string *attribute_name_Attribute_class_Deprecated_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1);
zend_attribute *attribute_Attribute_class_Deprecated_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_Deprecated_0, 1);
zend_string_release(attribute_name_Attribute_class_Deprecated_0);
zval attribute_Attribute_class_Deprecated_0_arg0;
ZVAL_LONG(&attribute_Attribute_class_Deprecated_0_arg0, ZEND_ATTRIBUTE_TARGET_METHOD | ZEND_ATTRIBUTE_TARGET_FUNCTION | ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
ZVAL_COPY_VALUE(&attribute_Attribute_class_Deprecated_0->args[0].value, &attribute_Attribute_class_Deprecated_0_arg0);
return class_entry;
}

View file

@ -3883,7 +3883,11 @@ ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc) /*
} }
} else if (!(CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)){ } else if (!(CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)){
if (zend_execute_ex == execute_ex) { if (zend_execute_ex == execute_ex) {
if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) {
return ZEND_DO_UCALL; return ZEND_DO_UCALL;
} else {
return ZEND_DO_FCALL_BY_NAME;
}
} }
} }
} else if (zend_execute_ex == execute_ex && } else if (zend_execute_ex == execute_ex &&
@ -8047,6 +8051,16 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
if (override_attribute) { if (override_attribute) {
op_array->fn_flags |= ZEND_ACC_OVERRIDE; op_array->fn_flags |= ZEND_ACC_OVERRIDE;
} }
zend_attribute *deprecated_attribute = zend_get_attribute_str(
op_array->attributes,
"deprecated",
sizeof("deprecated")-1
);
if (deprecated_attribute) {
op_array->fn_flags |= ZEND_ACC_DEPRECATED;
}
} }
/* Do not leak the class scope into free standing functions, even if they are dynamically /* Do not leak the class scope into free standing functions, even if they are dynamically
@ -8304,6 +8318,12 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as
if (attr_ast) { if (attr_ast) {
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0); zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
if (deprecated) {
ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
}
} }
} }
} }
@ -8733,6 +8753,12 @@ static void zend_compile_enum_case(zend_ast *ast)
zend_ast *attr_ast = ast->child[3]; zend_ast *attr_ast = ast->child[3];
if (attr_ast) { if (attr_ast) {
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0); zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
if (deprecated) {
ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
}
} }
} }

View file

@ -354,7 +354,7 @@ ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string *
if (UNEXPECTED(ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) { if (UNEXPECTED(ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) {
if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) { if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(class_name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
goto failure; goto failure;
} }

View file

@ -43,6 +43,7 @@
#include "zend_observer.h" #include "zend_observer.h"
#include "zend_system_id.h" #include "zend_system_id.h"
#include "zend_call_stack.h" #include "zend_call_stack.h"
#include "zend_attributes.h"
#include "Optimizer/zend_func_info.h" #include "Optimizer/zend_func_info.h"
/* Virtual current working directory support */ /* Virtual current working directory support */
@ -1766,16 +1767,118 @@ ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void)
zend_throw_error(NULL, "%s", msg); zend_throw_error(NULL, "%s", msg);
} }
ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute(HashTable *attributes, zend_class_entry* scope, zend_string **message_suffix)
{
*message_suffix = ZSTR_EMPTY_ALLOC();
if (!attributes) {
return SUCCESS;
}
zend_attribute *deprecated = zend_get_attribute_str(attributes, "deprecated", sizeof("deprecated")-1);
if (!deprecated) {
return SUCCESS;
}
if (deprecated->argc == 0) {
return SUCCESS;
}
zend_result result = FAILURE;
zend_string *message = ZSTR_EMPTY_ALLOC();
zend_string *since = ZSTR_EMPTY_ALLOC();
zval obj;
ZVAL_UNDEF(&obj);
zval *z;
/* Construct the Deprecated object to correctly handle parameter processing. */
if (FAILURE == zend_get_attribute_object(&obj, zend_ce_deprecated, deprecated, scope, NULL)) {
goto out;
}
/* Extract the $message property. */
z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL);
ZEND_ASSERT(z != &EG(uninitialized_zval));
if (Z_TYPE_P(z) == IS_STRING) {
message = zend_string_copy(Z_STR_P(z));
}
/* Extract the $since property. */
z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_SINCE), false, NULL);
ZEND_ASSERT(z != &EG(uninitialized_zval));
if (Z_TYPE_P(z) == IS_STRING) {
since = zend_string_copy(Z_STR_P(z));
}
/* Construct the suffix. */
*message_suffix = zend_strpprintf_unchecked(
0,
"%s%S%s%S",
ZSTR_LEN(since) > 0 ? " since " : "",
since,
ZSTR_LEN(message) > 0 ? ", " : "",
message
);
result = SUCCESS;
out:
zend_string_release(since);
zend_string_release(message);
zval_ptr_dtor(&obj);
return result;
}
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc) ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
{ {
zend_string *message_suffix = ZSTR_EMPTY_ALLOC();
if (get_deprecation_suffix_from_attribute(fbc->common.attributes, fbc->common.scope, &message_suffix) == FAILURE) {
return;
}
int code = fbc->type == ZEND_INTERNAL_FUNCTION ? E_DEPRECATED : E_USER_DEPRECATED;
if (fbc->common.scope) { if (fbc->common.scope) {
zend_error(E_DEPRECATED, "Method %s::%s() is deprecated", zend_error_unchecked(code, "Method %s::%s() is deprecated%S",
ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.scope->name),
ZSTR_VAL(fbc->common.function_name) ZSTR_VAL(fbc->common.function_name),
message_suffix
); );
} else { } else {
zend_error(E_DEPRECATED, "Function %s() is deprecated", ZSTR_VAL(fbc->common.function_name)); zend_error_unchecked(code, "Function %s() is deprecated%S",
ZSTR_VAL(fbc->common.function_name),
message_suffix
);
} }
zend_string_release(message_suffix);
}
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name)
{
zend_string *message_suffix = ZSTR_EMPTY_ALLOC();
if (get_deprecation_suffix_from_attribute(c->attributes, c->ce, &message_suffix) == FAILURE) {
return;
}
int code = c->ce->type == ZEND_INTERNAL_CLASS ? E_DEPRECATED : E_USER_DEPRECATED;
char *type = (ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE) ? "Enum case" : "Constant";
zend_error_unchecked(code, "%s %s::%s is deprecated%S",
type,
ZSTR_VAL(c->ce->name),
ZSTR_VAL(constant_name),
message_suffix
);
zend_string_release(message_suffix);
} }
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void) ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void)

View file

@ -62,6 +62,7 @@ extern ZEND_API const zend_internal_function zend_pass_function;
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void);
ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num); ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim);

View file

@ -633,6 +633,8 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_COUNT, "count") \ _(ZEND_STR_COUNT, "count") \
_(ZEND_STR_SENSITIVEPARAMETER, "SensitiveParameter") \ _(ZEND_STR_SENSITIVEPARAMETER, "SensitiveParameter") \
_(ZEND_STR_CONST_EXPR_PLACEHOLDER, "[constant expression]") \ _(ZEND_STR_CONST_EXPR_PLACEHOLDER, "[constant expression]") \
_(ZEND_STR_DEPRECATED, "Deprecated") \
_(ZEND_STR_SINCE, "since") \
typedef enum _zend_known_string_id { typedef enum _zend_known_string_id {

View file

@ -4072,10 +4072,23 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
ZEND_VM_C_GOTO(fcall_by_name_end);
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
@ -4091,24 +4104,11 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
ZEND_VM_ENTER_EX(); ZEND_VM_ENTER_EX();
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (ZEND_OBSERVER_ENABLED) { if (ZEND_OBSERVER_ENABLED) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
ZEND_VM_C_GOTO(fcall_by_name_end);
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -4138,7 +4138,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
ZEND_VM_C_GOTO(fcall_by_name_end);
}
if (0) {
ZEND_VM_C_LABEL(fcall_by_name_end): ZEND_VM_C_LABEL(fcall_by_name_end):
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
uint32_t call_info = ZEND_CALL_INFO(call); uint32_t call_info = ZEND_CALL_INFO(call);
@ -4170,10 +4175,26 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
}
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
ZEND_VM_C_GOTO(fcall_end);
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
@ -4198,24 +4219,11 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
zend_execute_ex(call); zend_execute_ex(call);
} }
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (ZEND_OBSERVER_ENABLED) { if (ZEND_OBSERVER_ENABLED) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
ZEND_VM_C_GOTO(fcall_end);
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -4250,7 +4258,12 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
ZEND_VM_C_GOTO(fcall_end);
}
if (0) {
ZEND_VM_C_LABEL(fcall_end): ZEND_VM_C_LABEL(fcall_end):
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {
zend_free_extra_named_params(call->extra_named_params); zend_free_extra_named_params(call->extra_named_params);
@ -6011,7 +6024,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
if (UNEXPECTED(is_constant_deprecated)) { if (UNEXPECTED(is_constant_deprecated)) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var)); ZVAL_UNDEF(EX_VAR(opline->result.var));

207
Zend/zend_vm_execute.h generated
View file

@ -1530,10 +1530,23 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!0) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_by_name_end;
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (0) { if (0) {
@ -1548,24 +1561,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
ZEND_VM_ENTER_EX(); ZEND_VM_ENTER_EX();
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) { if (0) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!0) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_by_name_end;
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -1593,7 +1593,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
goto fcall_by_name_end;
}
if (0) {
fcall_by_name_end: fcall_by_name_end:
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
uint32_t call_info = ZEND_CALL_INFO(call); uint32_t call_info = ZEND_CALL_INFO(call);
@ -1625,10 +1630,23 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!1) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_by_name_end;
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (1) { if (1) {
@ -1643,24 +1661,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
ZEND_VM_ENTER_EX(); ZEND_VM_ENTER_EX();
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) { if (0) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!1) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_by_name_end;
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -1688,7 +1693,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
goto fcall_by_name_end;
}
if (0) {
fcall_by_name_end: fcall_by_name_end:
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
uint32_t call_info = ZEND_CALL_INFO(call); uint32_t call_info = ZEND_CALL_INFO(call);
@ -1720,10 +1730,23 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_by_name_end;
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
@ -1739,24 +1762,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
ZEND_VM_ENTER_EX(); ZEND_VM_ENTER_EX();
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (1) { if (1) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_by_name_end;
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -1786,7 +1796,12 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
goto fcall_by_name_end;
}
if (0) {
fcall_by_name_end: fcall_by_name_end:
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
uint32_t call_info = ZEND_CALL_INFO(call); uint32_t call_info = ZEND_CALL_INFO(call);
@ -1818,10 +1833,26 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
}
UNDEF_RESULT();
if (!0) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_end;
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (0) { if (0) {
@ -1846,24 +1877,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
zend_execute_ex(call); zend_execute_ex(call);
} }
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) { if (0) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!0) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_end;
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -1896,7 +1914,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
goto fcall_end;
}
if (0) {
fcall_end: fcall_end:
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {
zend_free_extra_named_params(call->extra_named_params); zend_free_extra_named_params(call->extra_named_params);
@ -1927,10 +1950,26 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
}
UNDEF_RESULT();
if (!1) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_end;
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (1) { if (1) {
@ -1955,24 +1994,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
zend_execute_ex(call); zend_execute_ex(call);
} }
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) { if (0) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!1) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_end;
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -2005,7 +2031,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
goto fcall_end;
}
if (0) {
fcall_end: fcall_end:
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {
zend_free_extra_named_params(call->extra_named_params); zend_free_extra_named_params(call->extra_named_params);
@ -2036,10 +2067,26 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
zend_function *fbc = call->func; zend_function *fbc = call->func;
zval *ret; zval *ret;
zval retval;
SAVE_OPLINE(); SAVE_OPLINE();
EX(call) = call->prev_execute_data; EX(call) = call->prev_execute_data;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
}
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_end;
}
}
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
ret = NULL; ret = NULL;
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
@ -2064,24 +2111,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
zend_execute_ex(call); zend_execute_ex(call);
} }
} else { } else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (1) { if (1) {
ret = NULL; ret = NULL;
} }
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_deprecated_function(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
UNDEF_RESULT();
if (!RETURN_VALUE_USED(opline)) {
ret = &retval;
ZVAL_UNDEF(ret);
}
goto fcall_end;
}
}
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
EG(current_execute_data) = call; EG(current_execute_data) = call;
@ -2116,7 +2150,12 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
goto fcall_end;
}
if (0) {
fcall_end: fcall_end:
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {
zend_free_extra_named_params(call->extra_named_params); zend_free_extra_named_params(call->extra_named_params);
@ -7526,7 +7565,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
if (UNEXPECTED(is_constant_deprecated)) { if (UNEXPECTED(is_constant_deprecated)) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var)); ZVAL_UNDEF(EX_VAR(opline->result.var));
@ -8691,7 +8730,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
if (UNEXPECTED(is_constant_deprecated)) { if (UNEXPECTED(is_constant_deprecated)) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var)); ZVAL_UNDEF(EX_VAR(opline->result.var));
@ -25407,7 +25446,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
if (UNEXPECTED(is_constant_deprecated)) { if (UNEXPECTED(is_constant_deprecated)) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var)); ZVAL_UNDEF(EX_VAR(opline->result.var));
@ -25980,7 +26019,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
if (UNEXPECTED(is_constant_deprecated)) { if (UNEXPECTED(is_constant_deprecated)) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var)); ZVAL_UNDEF(EX_VAR(opline->result.var));
@ -34575,7 +34614,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
if (UNEXPECTED(is_constant_deprecated)) { if (UNEXPECTED(is_constant_deprecated)) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var)); ZVAL_UNDEF(EX_VAR(opline->result.var));
@ -34938,7 +34977,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
if (UNEXPECTED(is_constant_deprecated)) { if (UNEXPECTED(is_constant_deprecated)) {
zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); zend_deprecated_class_constant(c, constant_name);
if (EG(exception)) { if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var)); ZVAL_UNDEF(EX_VAR(opline->result.var));

View file

@ -1583,6 +1583,13 @@ class FuncInfo {
$flags[] = "ZEND_ACC_DEPRECATED"; $flags[] = "ZEND_ACC_DEPRECATED";
} }
foreach ($this->attributes as $attr) {
if ($attr->class === "Deprecated") {
$flags[] = "ZEND_ACC_DEPRECATED";
break;
}
}
$php82AndAboveFlags = $flags; $php82AndAboveFlags = $flags;
if ($this->isMethod() === false && $this->supportsCompileTimeEval) { if ($this->isMethod() === false && $this->supportsCompileTimeEval) {
$php82AndAboveFlags[] = "ZEND_ACC_COMPILE_TIME_EVAL"; $php82AndAboveFlags[] = "ZEND_ACC_COMPILE_TIME_EVAL";
@ -2865,6 +2872,13 @@ class ConstInfo extends VariableLike
$flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_DEPRECATED", PHP_80_VERSION_ID); $flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_DEPRECATED", PHP_80_VERSION_ID);
} }
foreach ($this->attributes as $attr) {
if ($attr->class === "Deprecated") {
$flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_DEPRECATED", PHP_80_VERSION_ID);
break;
}
}
if ($this->flags & Modifiers::FINAL) { if ($this->flags & Modifiers::FINAL) {
$flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_FINAL", PHP_81_VERSION_ID); $flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_FINAL", PHP_81_VERSION_ID);
} }
@ -3103,11 +3117,18 @@ class AttributeInfo {
/** @param array<string, ConstInfo> $allConstInfos */ /** @param array<string, ConstInfo> $allConstInfos */
public function generateCode(string $invocation, string $nameSuffix, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility): string { public function generateCode(string $invocation, string $nameSuffix, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility): string {
$php82MinimumCompatibility = $phpVersionIdMinimumCompatibility === null || $phpVersionIdMinimumCompatibility >= PHP_82_VERSION_ID; $php82MinimumCompatibility = $phpVersionIdMinimumCompatibility === null || $phpVersionIdMinimumCompatibility >= PHP_82_VERSION_ID;
$php84MinimumCompatibility = $phpVersionIdMinimumCompatibility === null || $phpVersionIdMinimumCompatibility >= PHP_84_VERSION_ID;
/* see ZEND_KNOWN_STRINGS in Zend/strings.h */ /* see ZEND_KNOWN_STRINGS in Zend/strings.h */
$knowns = []; $knowns = [
"message" => "ZEND_STR_MESSAGE",
];
if ($php82MinimumCompatibility) { if ($php82MinimumCompatibility) {
$knowns["SensitiveParameter"] = "ZEND_STR_SENSITIVEPARAMETER"; $knowns["SensitiveParameter"] = "ZEND_STR_SENSITIVEPARAMETER";
} }
if ($php84MinimumCompatibility) {
$knowns["Deprecated"] = "ZEND_STR_DEPRECATED";
$knowns["since"] = "ZEND_STR_SINCE";
}
$code = "\n"; $code = "\n";
$escapedAttributeName = strtr($this->class, '\\', '_'); $escapedAttributeName = strtr($this->class, '\\', '_');
@ -3124,9 +3145,13 @@ class AttributeInfo {
$code .= $value->initializeZval($zvalName); $code .= $value->initializeZval($zvalName);
$code .= "\tZVAL_COPY_VALUE(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, &$zvalName);\n"; $code .= "\tZVAL_COPY_VALUE(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, &$zvalName);\n";
if ($arg->name) { if ($arg->name) {
if (isset($knowns[$arg->name->name])) {
$code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = ZSTR_KNOWN({$knowns[$arg->name->name]});\n";
} else {
$code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init_interned(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n"; $code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init_interned(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n";
} }
} }
}
return $code; return $code;
} }
} }

View file

@ -9750,7 +9750,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
jit_SET_EX_OPLINE(jit, opline); jit_SET_EX_OPLINE(jit, opline);
if (opline->opcode == ZEND_DO_FCALL) { if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
if (!func) { if (!func) {
if (trace) { if (trace) {
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
@ -9787,7 +9787,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
} }
} }
if (opline->opcode == ZEND_DO_FCALL) { if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
if (!func) { if (!func) {
if (!trace) { if (!trace) {
ir_ref if_deprecated, ret; ir_ref if_deprecated, ret;
@ -10140,48 +10140,6 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
if (!func && (opline->opcode != ZEND_DO_ICALL)) { if (!func && (opline->opcode != ZEND_DO_ICALL)) {
ir_IF_FALSE(if_user); ir_IF_FALSE(if_user);
} }
if (opline->opcode == ZEND_DO_FCALL_BY_NAME) {
if (!func) {
if (trace) {
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
if (!exit_addr) {
return 0;
}
ZEND_ASSERT(func_ref);
ir_GUARD_NOT(
ir_AND_U32(
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
ir_CONST_U32(ZEND_ACC_DEPRECATED)),
ir_CONST_ADDR(exit_addr));
} else {
ir_ref if_deprecated, ret;
if_deprecated = ir_IF(ir_AND_U32(
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
ir_CONST_U32(ZEND_ACC_DEPRECATED)));
ir_IF_TRUE_cold(if_deprecated);
if (GCC_GLOBAL_REGS) {
ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
} else {
ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
}
ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
}
} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
ir_ref ret;
if (GCC_GLOBAL_REGS) {
ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
} else {
ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
}
ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
}
}
// JIT: EG(current_execute_data) = execute_data; // JIT: EG(current_execute_data) = execute_data;
ir_STORE(jit_EG(current_execute_data), rx); ir_STORE(jit_EG(current_execute_data), rx);

View file

@ -0,0 +1,59 @@
--TEST--
ReflectionAttribute::newInstance(): #[\Deprecated]
--FILE--
<?php
#[\Deprecated]
function test1() {
}
#[\Deprecated()]
function test2() {
}
#[\Deprecated("use test() instead")]
function test3() {
}
#[\Deprecated(since: "2.0")]
function test4() {
}
$reflection = new ReflectionFunction('test1');
var_dump($reflection->getAttributes()[0]->newInstance());
$reflection = new ReflectionFunction('test2');
var_dump($reflection->getAttributes()[0]->newInstance());
$reflection = new ReflectionFunction('test3');
var_dump($reflection->getAttributes()[0]->newInstance());
$reflection = new ReflectionFunction('test4');
var_dump($reflection->getAttributes()[0]->newInstance());
?>
--EXPECTF--
object(Deprecated)#%d (2) {
["message"]=>
NULL
["since"]=>
NULL
}
object(Deprecated)#%d (2) {
["message"]=>
NULL
["since"]=>
NULL
}
object(Deprecated)#%d (2) {
["message"]=>
string(18) "use test() instead"
["since"]=>
NULL
}
object(Deprecated)#%d (2) {
["message"]=>
NULL
["since"]=>
string(3) "2.0"
}

View file

@ -0,0 +1,17 @@
--TEST--
ReflectionClassConstant::isDeprecated() with userland constants.
--FILE--
<?php
class Clazz {
#[\Deprecated]
public const TEST = 'test';
}
$r = new ReflectionClassConstant('Clazz', 'TEST');
var_dump($r->isDeprecated());
?>
--EXPECTF--
bool(true)

View file

@ -0,0 +1,16 @@
--TEST--
ReflectionClassConstant::isDeprecated() with userland functions.
--FILE--
<?php
#[\Deprecated]
function test() {
}
$r = new ReflectionFunction('test');
var_dump($r->isDeprecated());
?>
--EXPECTF--
bool(true)

View file

@ -0,0 +1,29 @@
--TEST--
ReflectionMethod::isDeprecated(): Implementing a deprecated interface method.
--FILE--
<?php
interface I {
#[\Deprecated]
function test();
}
class Clazz implements I {
function test() {
}
}
$c = new Clazz();
$c->test();
$r = new ReflectionMethod('I', 'test');
var_dump($r->isDeprecated());
$r = new ReflectionMethod('Clazz', 'test');
var_dump($r->isDeprecated());
?>
--EXPECTF--
bool(true)
bool(false)

View file

@ -0,0 +1,29 @@
--TEST--
ReflectionMethod::isDeprecated(): Implementing a deprecated abstract method.
--FILE--
<?php
abstract class P {
#[\Deprecated]
abstract function test();
}
class Clazz extends P {
function test() {
}
}
$c = new Clazz();
$c->test();
$r = new ReflectionMethod('P', 'test');
var_dump($r->isDeprecated());
$r = new ReflectionMethod('Clazz', 'test');
var_dump($r->isDeprecated());
?>
--EXPECTF--
bool(true)
bool(false)

View file

@ -124,6 +124,11 @@ static ZEND_FUNCTION(zend_test_deprecated)
zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg1); zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg1);
} }
static ZEND_FUNCTION(zend_test_deprecated_attr)
{
ZEND_PARSE_PARAMETERS_NONE();
}
/* Create a string without terminating null byte. Must be terminated with /* Create a string without terminating null byte. Must be terminated with
* zend_terminate_string() before destruction, otherwise a warning is issued * zend_terminate_string() before destruction, otherwise a warning is issued
* in debug builds. */ * in debug builds. */

View file

@ -43,6 +43,9 @@ namespace {
*/ */
public const int ZEND_TEST_DEPRECATED = 42; public const int ZEND_TEST_DEPRECATED = 42;
#[\Deprecated(message: "custom message")]
public const int ZEND_TEST_DEPRECATED_ATTR = 42;
/** @var mixed */ /** @var mixed */
public static $_StaticProp; public static $_StaticProp;
public static int $staticIntProp = 123; public static int $staticIntProp = 123;
@ -206,6 +209,9 @@ namespace {
/** @deprecated */ /** @deprecated */
function zend_test_deprecated(mixed $arg = null): void {} function zend_test_deprecated(mixed $arg = null): void {}
#[\Deprecated(message: "custom message")]
function zend_test_deprecated_attr(): void {}
/** @alias zend_test_void_return */ /** @alias zend_test_void_return */
function zend_test_aliased(): void {} function zend_test_aliased(): void {}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 6b49c60e3b86415a0e0d95cd915419fac39de531 */ * Stub hash: 470b6d507911cf05279de3557df03831858dd8c1 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
@ -20,6 +20,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_deprecated, 0, 0, IS_V
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg, IS_MIXED, 0, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg, IS_MIXED, 0, "null")
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#define arginfo_zend_test_deprecated_attr arginfo_zend_test_void_return
#define arginfo_zend_test_aliased arginfo_zend_test_void_return #define arginfo_zend_test_aliased arginfo_zend_test_void_return
#define arginfo_zend_test_deprecated_aliased arginfo_zend_test_void_return #define arginfo_zend_test_deprecated_aliased arginfo_zend_test_void_return
@ -253,6 +255,7 @@ static ZEND_FUNCTION(zend_test_nullable_array_return);
static ZEND_FUNCTION(zend_test_void_return); static ZEND_FUNCTION(zend_test_void_return);
static ZEND_FUNCTION(zend_test_compile_string); static ZEND_FUNCTION(zend_test_compile_string);
static ZEND_FUNCTION(zend_test_deprecated); static ZEND_FUNCTION(zend_test_deprecated);
static ZEND_FUNCTION(zend_test_deprecated_attr);
static ZEND_FUNCTION(zend_create_unterminated_string); static ZEND_FUNCTION(zend_create_unterminated_string);
static ZEND_FUNCTION(zend_terminate_string); static ZEND_FUNCTION(zend_terminate_string);
static ZEND_FUNCTION(zend_leak_variable); static ZEND_FUNCTION(zend_leak_variable);
@ -343,6 +346,11 @@ static const zend_function_entry ext_functions[] = {
#else #else
ZEND_RAW_FENTRY("zend_test_deprecated", zif_zend_test_deprecated, arginfo_zend_test_deprecated, ZEND_ACC_DEPRECATED) ZEND_RAW_FENTRY("zend_test_deprecated", zif_zend_test_deprecated, arginfo_zend_test_deprecated, ZEND_ACC_DEPRECATED)
#endif #endif
#if (PHP_VERSION_ID >= 80400)
ZEND_RAW_FENTRY("zend_test_deprecated_attr", zif_zend_test_deprecated_attr, arginfo_zend_test_deprecated_attr, ZEND_ACC_DEPRECATED, NULL, NULL)
#else
ZEND_RAW_FENTRY("zend_test_deprecated_attr", zif_zend_test_deprecated_attr, arginfo_zend_test_deprecated_attr, ZEND_ACC_DEPRECATED)
#endif
#if (PHP_VERSION_ID >= 80400) #if (PHP_VERSION_ID >= 80400)
ZEND_RAW_FENTRY("zend_test_aliased", zif_zend_test_void_return, arginfo_zend_test_aliased, 0, NULL, NULL) ZEND_RAW_FENTRY("zend_test_aliased", zif_zend_test_void_return, arginfo_zend_test_aliased, 0, NULL, NULL)
#else #else
@ -563,6 +571,15 @@ static void register_test_symbols(int module_number)
REGISTER_STRING_CONSTANT("ZendTestNS2\\ZendSubNS\\ZEND_CONSTANT_A", "namespaced", CONST_PERSISTENT); REGISTER_STRING_CONSTANT("ZendTestNS2\\ZendSubNS\\ZEND_CONSTANT_A", "namespaced", CONST_PERSISTENT);
zend_string *attribute_name_Deprecated_func_zend_test_deprecated_attr_0 = zend_string_init_interned("Deprecated", sizeof("Deprecated") - 1, 1);
zend_attribute *attribute_Deprecated_func_zend_test_deprecated_attr_0 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_deprecated_attr", sizeof("zend_test_deprecated_attr") - 1), attribute_name_Deprecated_func_zend_test_deprecated_attr_0, 1);
zend_string_release(attribute_name_Deprecated_func_zend_test_deprecated_attr_0);
zval attribute_Deprecated_func_zend_test_deprecated_attr_0_arg0;
zend_string *attribute_Deprecated_func_zend_test_deprecated_attr_0_arg0_str = zend_string_init("custom message", strlen("custom message"), 1);
ZVAL_STR(&attribute_Deprecated_func_zend_test_deprecated_attr_0_arg0, attribute_Deprecated_func_zend_test_deprecated_attr_0_arg0_str);
ZVAL_COPY_VALUE(&attribute_Deprecated_func_zend_test_deprecated_attr_0->args[0].value, &attribute_Deprecated_func_zend_test_deprecated_attr_0_arg0);
attribute_Deprecated_func_zend_test_deprecated_attr_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
zend_string *attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1); zend_string *attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1);
zend_attribute *attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1), 0, attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0, 1); zend_attribute *attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1), 0, attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0, 1);
zend_string_release(attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0); zend_string_release(attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0);
@ -647,6 +664,16 @@ static zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_e
#endif #endif
zend_string_release(const_ZEND_TEST_DEPRECATED_name); zend_string_release(const_ZEND_TEST_DEPRECATED_name);
zval const_ZEND_TEST_DEPRECATED_ATTR_value;
ZVAL_LONG(&const_ZEND_TEST_DEPRECATED_ATTR_value, 42);
zend_string *const_ZEND_TEST_DEPRECATED_ATTR_name = zend_string_init_interned("ZEND_TEST_DEPRECATED_ATTR", sizeof("ZEND_TEST_DEPRECATED_ATTR") - 1, 1);
#if (PHP_VERSION_ID >= 80300)
zend_class_constant *const_ZEND_TEST_DEPRECATED_ATTR = zend_declare_typed_class_constant(class_entry, const_ZEND_TEST_DEPRECATED_ATTR_name, &const_ZEND_TEST_DEPRECATED_ATTR_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
#else
zend_class_constant *const_ZEND_TEST_DEPRECATED_ATTR = zend_declare_class_constant_ex(class_entry, const_ZEND_TEST_DEPRECATED_ATTR_name, &const_ZEND_TEST_DEPRECATED_ATTR_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL);
#endif
zend_string_release(const_ZEND_TEST_DEPRECATED_ATTR_name);
zval property__StaticProp_default_value; zval property__StaticProp_default_value;
ZVAL_NULL(&property__StaticProp_default_value); ZVAL_NULL(&property__StaticProp_default_value);
zend_string *property__StaticProp_name = zend_string_init("_StaticProp", sizeof("_StaticProp") - 1, 1); zend_string *property__StaticProp_name = zend_string_init("_StaticProp", sizeof("_StaticProp") - 1, 1);
@ -708,6 +735,16 @@ static zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_e
#endif #endif
zend_string_release(property_readonlyProp_name); zend_string_release(property_readonlyProp_name);
zend_string *attribute_name_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0 = zend_string_init_interned("Deprecated", sizeof("Deprecated") - 1, 1);
zend_attribute *attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0 = zend_add_class_constant_attribute(class_entry, const_ZEND_TEST_DEPRECATED_ATTR, attribute_name_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0, 1);
zend_string_release(attribute_name_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0);
zval attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0_arg0;
zend_string *attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0_arg0_str = zend_string_init("custom message", strlen("custom message"), 1);
ZVAL_STR(&attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0_arg0, attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0_arg0_str);
ZVAL_COPY_VALUE(&attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0->args[0].value, &attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0_arg0);
attribute_Deprecated_const_ZEND_TEST_DEPRECATED_ATTR_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
return class_entry; return class_entry;
} }

View file

@ -0,0 +1,40 @@
--TEST--
#[\Deprecated]: Works in stubs.
--EXTENSIONS--
zend_test
--FILE--
<?php
zend_test_deprecated();
zend_test_deprecated_attr();
$reflection = new ReflectionFunction('zend_test_deprecated_attr');
var_dump($reflection->getAttributes()[0]->newInstance());
var_dump($reflection->isDeprecated());
_ZendTestClass::ZEND_TEST_DEPRECATED_ATTR;
$reflection = new ReflectionClassConstant('_ZendTestClass', 'ZEND_TEST_DEPRECATED_ATTR');
var_dump($reflection->getAttributes()[0]->newInstance());
var_dump($reflection->isDeprecated());
?>
--EXPECTF--
Deprecated: Function zend_test_deprecated() is deprecated in %s on line %d
Deprecated: Function zend_test_deprecated_attr() is deprecated, custom message in %s on line %d
object(Deprecated)#%d (2) {
["message"]=>
string(14) "custom message"
["since"]=>
NULL
}
bool(true)
Deprecated: Constant _ZendTestClass::ZEND_TEST_DEPRECATED_ATTR is deprecated, custom message in %s on line %d
object(Deprecated)#%d (2) {
["message"]=>
string(14) "custom message"
["since"]=>
NULL
}
bool(true)