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)
. Fixed bug GH-11928 (The --enable-re2c-cgoto doesn't add the -g flag).
(Peter Kokot)
. Added the #[\Deprecated] attribute. (beberlei, timwolla)
- Curl:
. 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
the expression in parentheses.
RFC: https://wiki.php.net/rfc/new_without_parentheses
. Added the #[\Deprecated] attribute.
RFC: https://wiki.php.net/rfc/deprecated_attribute
- Curl:
. 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)
{
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 ??? */
&& !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE))
&& 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_value;
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;
@ -146,6 +147,43 @@ ZEND_METHOD(Override, __construct)
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)
{
if (attributes) {
@ -470,6 +508,9 @@ void zend_register_attribute_ce(void)
zend_ce_override = register_class_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)

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_value;
extern ZEND_API zend_class_entry *zend_ce_override;
extern ZEND_API zend_class_entry *zend_ce_deprecated;
typedef struct {
zend_string *name;

View File

@ -71,3 +71,16 @@ final class Override
{
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.
* Stub hash: 32f0458c20f04099e353a8300ffb19e40bc38f69 */
* Stub hash: 2358a0d820edd06a1702c84104bfd545af08311c */
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")
@ -24,6 +24,11 @@ ZEND_END_ARG_INFO()
#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(ReturnTypeWillChange, __construct);
ZEND_METHOD(AllowDynamicProperties, __construct);
@ -32,6 +37,7 @@ ZEND_METHOD(SensitiveParameterValue, __construct);
ZEND_METHOD(SensitiveParameterValue, getValue);
ZEND_METHOD(SensitiveParameterValue, __debugInfo);
ZEND_METHOD(Override, __construct);
ZEND_METHOD(Deprecated, __construct);
static const zend_function_entry class_Attribute_methods[] = {
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
};
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)
{
zend_class_entry ce, *class_entry;
@ -225,3 +236,33 @@ static zend_class_entry *register_class_Override(void)
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)){
if (zend_execute_ex == execute_ex) {
return ZEND_DO_UCALL;
if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) {
return ZEND_DO_UCALL;
} else {
return ZEND_DO_FCALL_BY_NAME;
}
}
}
} 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) {
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
@ -8304,6 +8318,12 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as
if (attr_ast) {
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];
if (attr_ast) {
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 ((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)) {
goto failure;
}

View File

@ -43,6 +43,7 @@
#include "zend_observer.h"
#include "zend_system_id.h"
#include "zend_call_stack.h"
#include "zend_attributes.h"
#include "Optimizer/zend_func_info.h"
/* 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_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_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) {
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.function_name)
ZSTR_VAL(fbc->common.function_name),
message_suffix
);
} 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)

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_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_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);

View File

@ -633,6 +633,8 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_COUNT, "count") \
_(ZEND_STR_SENSITIVEPARAMETER, "SensitiveParameter") \
_(ZEND_STR_CONST_EXPR_PLACEHOLDER, "[constant expression]") \
_(ZEND_STR_DEPRECATED, "Deprecated") \
_(ZEND_STR_SINCE, "since") \
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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (ZEND_OBSERVER_ENABLED) {
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;
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;
ZEND_VM_C_GOTO(fcall_by_name_end);
}
if (0) {
ZEND_VM_C_LABEL(fcall_by_name_end):
zend_vm_stack_free_args(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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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);
}
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (ZEND_OBSERVER_ENABLED) {
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;
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;
ZEND_VM_C_GOTO(fcall_end);
}
if (0) {
ZEND_VM_C_LABEL(fcall_end):
zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_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;
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)) {
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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) {
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;
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;
goto fcall_by_name_end;
}
if (0) {
fcall_by_name_end:
zend_vm_stack_free_args(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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) {
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;
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;
goto fcall_by_name_end;
}
if (0) {
fcall_by_name_end:
zend_vm_stack_free_args(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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (1) {
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;
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;
goto fcall_by_name_end;
}
if (0) {
fcall_by_name_end:
zend_vm_stack_free_args(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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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);
}
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) {
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;
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;
goto fcall_end;
}
if (0) {
fcall_end:
zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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);
}
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (0) {
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;
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;
goto fcall_end;
}
if (0) {
fcall_end:
zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_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_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
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)) {
ret = NULL;
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);
}
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (1) {
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;
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;
goto fcall_end;
}
if (0) {
fcall_end:
zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_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;
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)) {
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;
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)) {
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;
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)) {
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;
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)) {
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;
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)) {
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;
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)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));

View File

@ -1583,6 +1583,13 @@ class FuncInfo {
$flags[] = "ZEND_ACC_DEPRECATED";
}
foreach ($this->attributes as $attr) {
if ($attr->class === "Deprecated") {
$flags[] = "ZEND_ACC_DEPRECATED";
break;
}
}
$php82AndAboveFlags = $flags;
if ($this->isMethod() === false && $this->supportsCompileTimeEval) {
$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);
}
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) {
$flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_FINAL", PHP_81_VERSION_ID);
}
@ -3103,11 +3117,18 @@ class AttributeInfo {
/** @param array<string, ConstInfo> $allConstInfos */
public function generateCode(string $invocation, string $nameSuffix, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility): string {
$php82MinimumCompatibility = $phpVersionIdMinimumCompatibility === null || $phpVersionIdMinimumCompatibility >= PHP_82_VERSION_ID;
$php84MinimumCompatibility = $phpVersionIdMinimumCompatibility === null || $phpVersionIdMinimumCompatibility >= PHP_84_VERSION_ID;
/* see ZEND_KNOWN_STRINGS in Zend/strings.h */
$knowns = [];
$knowns = [
"message" => "ZEND_STR_MESSAGE",
];
if ($php82MinimumCompatibility) {
$knowns["SensitiveParameter"] = "ZEND_STR_SENSITIVEPARAMETER";
}
if ($php84MinimumCompatibility) {
$knowns["Deprecated"] = "ZEND_STR_DEPRECATED";
$knowns["since"] = "ZEND_STR_SINCE";
}
$code = "\n";
$escapedAttributeName = strtr($this->class, '\\', '_');
@ -3124,7 +3145,11 @@ class AttributeInfo {
$code .= $value->initializeZval($zvalName);
$code .= "\tZVAL_COPY_VALUE(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, &$zvalName);\n";
if ($arg->name) {
$code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init_interned(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n";
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";
}
}
}
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);
if (opline->opcode == ZEND_DO_FCALL) {
if (opline->opcode == ZEND_DO_FCALL || 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);
@ -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 (!trace) {
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)) {
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;
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);
}
static ZEND_FUNCTION(zend_test_deprecated_attr)
{
ZEND_PARSE_PARAMETERS_NONE();
}
/* Create a string without terminating null byte. Must be terminated with
* zend_terminate_string() before destruction, otherwise a warning is issued
* in debug builds. */

View File

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

View File

@ -1,5 +1,5 @@
/* 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_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_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_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_compile_string);
static ZEND_FUNCTION(zend_test_deprecated);
static ZEND_FUNCTION(zend_test_deprecated_attr);
static ZEND_FUNCTION(zend_create_unterminated_string);
static ZEND_FUNCTION(zend_terminate_string);
static ZEND_FUNCTION(zend_leak_variable);
@ -343,6 +346,11 @@ static const zend_function_entry ext_functions[] = {
#else
ZEND_RAW_FENTRY("zend_test_deprecated", zif_zend_test_deprecated, arginfo_zend_test_deprecated, ZEND_ACC_DEPRECATED)
#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)
ZEND_RAW_FENTRY("zend_test_aliased", zif_zend_test_void_return, arginfo_zend_test_aliased, 0, NULL, NULL)
#else
@ -563,6 +571,15 @@ static void register_test_symbols(int module_number)
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_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);
@ -647,6 +664,16 @@ static zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_e
#endif
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_NULL(&property__StaticProp_default_value);
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
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;
}

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)