diff --git a/Zend/tests/attributes/deprecated/functions/argument_binding.phpt b/Zend/tests/attributes/deprecated/functions/argument_binding.phpt new file mode 100644 index 000000000000..4d89d61388a2 --- /dev/null +++ b/Zend/tests/attributes/deprecated/functions/argument_binding.phpt @@ -0,0 +1,63 @@ +--TEST-- +#[\Deprecated]: positional and named arguments, null, and the errors of the constructor +--FILE-- +getMessage(), "\n"; + } +} + +?> +--EXPECTF-- + +Deprecated: Function positional_message() is deprecated, message only in %s on line %d + +Deprecated: Function named_since() is deprecated since 1.0 in %s on line %d + +Deprecated: Function both_positional() is deprecated since 1.0, m in %s on line %d + +Deprecated: Function named_reversed() is deprecated since 1.0, m in %s on line %d + +Deprecated: Function null_message() is deprecated since 1.0 in %s on line %d + +Deprecated: Function null_since() is deprecated, m in %s on line %d + +Deprecated: Function empty_strings() is deprecated in %s on line %d +Error: Named parameter $message overwrites previous argument +Error: Named parameter $message overwrites previous argument +Error: Unknown named parameter $unknown +Error: Unknown named parameter $Message +ArgumentCountError: Deprecated::__construct() expects at most 2 arguments, 3 given diff --git a/Zend/tests/attributes/deprecated/functions/internal_repeated_calls.phpt b/Zend/tests/attributes/deprecated/functions/internal_repeated_calls.phpt new file mode 100644 index 000000000000..b030b8929a22 --- /dev/null +++ b/Zend/tests/attributes/deprecated/functions/internal_repeated_calls.phpt @@ -0,0 +1,32 @@ +--TEST-- +#[\Deprecated]: the message of an internal function is the same on every call +--FILE-- +setAccessible(true); +$rp->setAccessible(true); +(Closure::fromCallable([$rp, 'setAccessible']))(true); +(new ReflectionMethod($rp, 'setAccessible'))->invoke($rp, true); + +set_error_handler(function (int $type, string $message) { + echo "handler: $message\n"; + return true; +}); +$rp->setAccessible(true); +restore_error_handler(); +$rp->setAccessible(true); + +?> +--EXPECTF-- +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d + +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d + +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d + +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d +handler: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 + +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/007.phpt b/Zend/tests/attributes/nodiscard/007.phpt index de4604e15e48..6d3df246f0aa 100644 --- a/Zend/tests/attributes/nodiscard/007.phpt +++ b/Zend/tests/attributes/nodiscard/007.phpt @@ -7,13 +7,23 @@ zend_test.observer.execute_internal=1 --FILE-- --EXPECTF-- - - + + Warning: The return value of function zend_test_nodiscard() should either be used or intentionally ignored by casting it as (void), custom message in %s on line %d + + + +Warning: The return value of function f() should either be used or intentionally ignored by casting it as (void), from a constant in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/argument_binding.phpt b/Zend/tests/attributes/nodiscard/argument_binding.phpt new file mode 100644 index 000000000000..fc6e9b69c3a3 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/argument_binding.phpt @@ -0,0 +1,41 @@ +--TEST-- +#[\NoDiscard]: positional and named message, null, and the errors of the constructor +--FILE-- +getMessage(), "\n"; + } +} + +?> +--EXPECTF-- + +Warning: The return value of function positional_message() should either be used or intentionally ignored by casting it as (void), positional in %s on line %d + +Warning: The return value of function named_message() should either be used or intentionally ignored by casting it as (void), named in %s on line %d + +Warning: The return value of function null_message() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function empty_message() should either be used or intentionally ignored by casting it as (void) in %s on line %d +Error: Unknown named parameter $since +ArgumentCountError: NoDiscard::__construct() expects at most 1 argument, 2 given +Error: Unknown named parameter $unknown diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index e7923d76996c..de943385c536 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1831,6 +1831,48 @@ ZEND_API zend_never_inline ZEND_COLD void zend_wrong_string_offset_error(void) zend_throw_error(NULL, "%s", msg); } +/* Reads the arguments of a #[\Deprecated] (message, since) or #[\NoDiscard] (message) + * attribute when they are strings or null, positional or named, each at most once; anything + * else is left to the constructor and its errors */ +static bool get_attribute_string_args(const zend_attribute *attr, zend_string **message, zend_string **since) +{ + zend_string *strs[2] = {NULL, NULL}; + uint32_t num_params = since ? 2 : 1; + + if (attr->argc > num_params) { + return false; + } + for (uint32_t i = 0; i < attr->argc; i++) { + const zend_attribute_arg *arg = &attr->args[i]; + uint32_t param; + + if (arg->name == NULL) { + param = i; + } else if (zend_string_equals(arg->name, ZSTR_KNOWN(ZEND_STR_MESSAGE))) { + param = 0; + } else if (num_params == 2 && zend_string_equals(arg->name, ZSTR_KNOWN(ZEND_STR_SINCE))) { + param = 1; + } else { + return false; + } + if (strs[param] != NULL) { + return false; + } + if (Z_TYPE(arg->value) == IS_STRING) { + strs[param] = Z_STR(arg->value); + } else if (Z_TYPE(arg->value) == IS_NULL) { + strs[param] = ZSTR_EMPTY_ALLOC(); + } else { + return false; + } + } + *message = strs[0] ? strs[0] : ZSTR_EMPTY_ALLOC(); + if (since) { + *since = strs[1] ? strs[1] : ZSTR_EMPTY_ALLOC(); + } + return true; +} + 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(); @@ -1858,6 +1900,11 @@ ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute ZVAL_UNDEF(&obj); zval *z; + /* With an exception pending the constructor is not run and nothing is emitted; keep that */ + if (!EG(exception) && get_attribute_string_args(deprecated, &message, &since)) { + goto build; + } + /* Construct the Deprecated object to correctly handle parameter processing. */ if (FAILURE == zend_get_attribute_object(&obj, zend_ce_deprecated, deprecated, scope, NULL)) { goto out; @@ -1877,6 +1924,7 @@ ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute since = Z_STR_P(z); } +build: /* Construct the suffix. */ *message_suffix = zend_strpprintf_unchecked( 0, @@ -1948,6 +1996,10 @@ ZEND_COLD static zend_result ZEND_FASTCALL get_nodiscard_suffix_from_attribute(H ZVAL_UNDEF(&obj); zval *z; + if (!EG(exception) && get_attribute_string_args(nodiscard, &message, NULL)) { + goto build; + } + /* Construct the NoDiscard object to correctly handle parameter processing. */ if (FAILURE == zend_get_attribute_object(&obj, zend_ce_nodiscard, nodiscard, scope, NULL)) { goto out; @@ -1960,6 +2012,7 @@ ZEND_COLD static zend_result ZEND_FASTCALL get_nodiscard_suffix_from_attribute(H message = Z_STR_P(z); } +build: /* Construct the suffix. */ *message_suffix = zend_strpprintf_unchecked( 0, diff --git a/ext/zend_test/tests/observer_sqlite_create_function.phpt b/ext/zend_test/tests/observer_sqlite_create_function.phpt index 5d809056193d..fa39d18cd162 100644 --- a/ext/zend_test/tests/observer_sqlite_create_function.phpt +++ b/ext/zend_test/tests/observer_sqlite_create_function.phpt @@ -30,9 +30,6 @@ echo 'Done' . PHP_EOL; - - - Deprecated: Method PDO::sqliteCreateFunction() is deprecated since 8.5, use Pdo\Sqlite::createFunction() instead in %s on line %d