Commit 0beb2a99d3b for php.net
commit 0beb2a99d3beb586a1ee5a2c768e43a9218be2a1
Author: Gina Peter Banyard <girgias@php.net>
Date: Wed Sep 9 16:08:18 2026 +0100
Zend: deprecate using "_" as a class and constant name (#23615)
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_using_as_a_constant_and_compile_time_alias
Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>
diff --git a/Zend/tests/deprecated_identifiers/underscore/class_alias_underscore.phpt b/Zend/tests/deprecated_identifiers/underscore/class_alias_underscore.phpt
new file mode 100644
index 00000000000..23afcbfeb92
--- /dev/null
+++ b/Zend/tests/deprecated_identifiers/underscore/class_alias_underscore.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Using "_" as a class name alias is deprecated
+--FILE--
+<?php
+
+class_alias('stdClass', '_');
+
+class_alias('stdClass', 'Foo\\_');
+
+?>
+--EXPECTF--
+Deprecated: Using "_" as a class alias is deprecated since 8.4 in %s on line %d
+
+Deprecated: Using "_" as a class alias is deprecated since 8.4 in %s on line %d
diff --git a/Zend/tests/class_underscore_as_name.phpt b/Zend/tests/deprecated_identifiers/underscore/class_underscore_as_name.phpt
similarity index 100%
rename from Zend/tests/class_underscore_as_name.phpt
rename to Zend/tests/deprecated_identifiers/underscore/class_underscore_as_name.phpt
diff --git a/Zend/tests/deprecated_identifiers/underscore/class_underscore_as_name_use.phpt b/Zend/tests/deprecated_identifiers/underscore/class_underscore_as_name_use.phpt
new file mode 100644
index 00000000000..685250b369a
--- /dev/null
+++ b/Zend/tests/deprecated_identifiers/underscore/class_underscore_as_name_use.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Using "_" as a class name in use statements is deprecated
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ use stdClass as _;
+}
+
+namespace {
+ use stdClass as _;
+}
+
+?>
+--EXPECTF--
+Deprecated: Using "_" as a class name is deprecated in %s on line %d
+
+Deprecated: Using "_" as a class name is deprecated in %s on line %d
diff --git a/Zend/tests/deprecated_identifiers/underscore/constant_underscore_as_name.phpt b/Zend/tests/deprecated_identifiers/underscore/constant_underscore_as_name.phpt
new file mode 100644
index 00000000000..4859e8ca5ae
--- /dev/null
+++ b/Zend/tests/deprecated_identifiers/underscore/constant_underscore_as_name.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Using "_" as a constant name is deprecated
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ const _ = 5;
+}
+
+namespace {
+ const _ = 5;
+
+ define('_', 'x');
+
+ define('foo\\_', 'x');
+}
+
+?>
+--EXPECTF--
+Deprecated: Calling a constant "_" is deprecated since 8.6 in %s on line %d
+
+Deprecated: Calling a constant "_" is deprecated since 8.6 in %s on line %d
+
+Deprecated: Calling a constant "_" is deprecated since 8.6 in %s on line %d
+
+Warning: Constant _ already defined, this will be an error in PHP 9 in %s on line %d
+
+Deprecated: Calling a constant "_" is deprecated since 8.6 in %s on line %d
diff --git a/Zend/tests/deprecated_identifiers/underscore/constant_underscore_as_name_use.phpt b/Zend/tests/deprecated_identifiers/underscore/constant_underscore_as_name_use.phpt
new file mode 100644
index 00000000000..e7421318aea
--- /dev/null
+++ b/Zend/tests/deprecated_identifiers/underscore/constant_underscore_as_name_use.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Using "_" as a constant in use statements is deprecated
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ use const PHP_INT_MAX as _;
+}
+
+namespace {
+ use const PHP_INT_MAX as _;
+}
+
+?>
+--EXPECTF--
+Deprecated: Using "_" as a constant name is deprecated since 8.6 in %s on line %d
+
+Deprecated: Using "_" as a constant name is deprecated since 8.6 in %s on line %d
diff --git a/Zend/tests/deprecated_identifiers/underscore/function_underscore_as_name.phpt b/Zend/tests/deprecated_identifiers/underscore/function_underscore_as_name.phpt
new file mode 100644
index 00000000000..0d127fab630
--- /dev/null
+++ b/Zend/tests/deprecated_identifiers/underscore/function_underscore_as_name.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Using "_" as a function name is NOT deprecated
+--SKIPIF--
+<?php
+if (extension_loaded('gettext')) {
+ die("skip gettext extension defines the _ function");
+}
+?>
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ function _() {}
+}
+
+namespace {
+ function _() {}
+ echo "OK";
+}
+
+?>
+--EXPECT--
+OK
diff --git a/Zend/tests/deprecated_identifiers/underscore/function_underscore_as_name_use.phpt b/Zend/tests/deprecated_identifiers/underscore/function_underscore_as_name_use.phpt
new file mode 100644
index 00000000000..688683a6039
--- /dev/null
+++ b/Zend/tests/deprecated_identifiers/underscore/function_underscore_as_name_use.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Using "_" as a function in use statements is NOT deprecated
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ use function strlen as _;
+}
+
+namespace {
+ use function strlen as _;
+
+ echo "OK";
+}
+
+?>
+--EXPECT--
+OK
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 317114265c5..5aa1b07f304 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -252,7 +252,7 @@ void zend_assert_valid_class_name(const zend_string *name, const char *type) /*
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use \"%s\" as %s as it is reserved", ZSTR_VAL(name), type);
}
- if (zend_string_equals_literal(name, "_")) {
+ if (zend_string_equals_literal(name, "_") || zend_string_ends_with_literal(name, "\\_")) {
zend_error(E_DEPRECATED, "Using \"_\" as %s is deprecated since 8.4", type);
}
}
@@ -10213,6 +10213,20 @@ static void zend_compile_use(zend_ast *ast) /* {{{ */
"is a special class name", ZSTR_VAL(old_name), ZSTR_VAL(new_name), ZSTR_VAL(new_name));
}
+ if (zend_string_equals(new_name, ZSTR_CHAR('_'))) {
+ switch (type) {
+ case ZEND_SYMBOL_CLASS:
+ zend_error(E_DEPRECATED, "Using \"_\" as a class name is deprecated");
+ break;
+ case ZEND_SYMBOL_CONST:
+ zend_error(E_DEPRECATED, "Using \"_\" as a constant name is deprecated since 8.6");
+ break;
+ case ZEND_SYMBOL_FUNCTION:
+ break;
+ default: ZEND_UNREACHABLE();
+ }
+ }
+
if (current_ns) {
zend_string *ns_name = zend_string_alloc(ZSTR_LEN(current_ns) + 1 + ZSTR_LEN(new_name), 0);
zend_str_tolower_copy(ZSTR_VAL(ns_name), ZSTR_VAL(current_ns), ZSTR_LEN(current_ns));
diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c
index 18292203bee..c8a2ae62d75 100644
--- a/Zend/zend_constants.c
+++ b/Zend/zend_constants.c
@@ -538,6 +538,12 @@ ZEND_API zend_constant *zend_register_constant(zend_constant *c)
c->attributes = NULL;
+ if (
+ zend_string_equals(name, ZSTR_CHAR('_'))
+ || (slash && zend_string_ends_with_literal(name, "\\_"))
+ ) {
+ zend_error(E_DEPRECATED, "Calling a constant \"_\" is deprecated since 8.6");
+ }
/* Check if the user is trying to define any special constant */
if (zend_string_equals_literal(name, "__COMPILER_HALT_OFFSET__")
|| (!persistent && zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name)))