Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Add #[\Deprecated] Attribute #11293

Merged
merged 9 commits into from
Jul 2, 2024
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Zend/Optimizer/optimize_func_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 43 additions & 0 deletions Zend/tests/attributes/deprecated/class_constants/001.phpt
Original file line number Diff line number Diff line change
@@ -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)
21 changes: 21 additions & 0 deletions Zend/tests/attributes/deprecated/class_constants/101.phpt
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
iluuu1994 marked this conversation as resolved.
Show resolved Hide resolved

Deprecated: Constant Clazz::TEST2 is deprecated in %s on line %d

Deprecated: Constant Clazz::TEST3 is deprecated, from another in %s on line %d
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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"
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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)
76 changes: 76 additions & 0 deletions Zend/tests/attributes/deprecated/functions/001.phpt
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am guessing this is emitted when the call is actually performed by the engine.

One potential idea in the future (which might not be sensible), is to make the callable type check also check if the provided function is deprecated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One potential idea in the future (which might not be sensible), is to make the callable type check also check if the provided function is deprecated.

What would it then do, if the function is deprecated?

Handled: test
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions Zend/tests/attributes/deprecated/functions/error_code_001.phpt
Original file line number Diff line number Diff line change
@@ -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)
Loading
Loading