[PHP-CVS] [php-src] master: Merge branch 'PHP-8.4' into PHP-8.5

[email protected] (Daniel Scherzer) Mon, 3 Aug 2026 17:47:21 +0000
Newsgroups php.cvs
Message-ID <[email protected]>
Author: Daniel Scherzer (DanielEScherzer)
Date: 2026-08-03T10:22:50-07:00

Commit: https://github.com/php/php-src/commit/74a1f21ebdfb7458943527813db8a72e878d9dea
Raw diff: https://github.com/php/php-src/commit/74a1f21ebdfb7458943527813db8a72e878d9dea.diff

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  NEWS for PHP 8.4
  GH-22905: avoid truncation on null bytes in reflection exceptions
  Reflection: Add regression tests for error messages with null bytes

Changed paths:
  A  ext/reflection/tests/gh22905/ReflectionClassConstant_construct_class.phpt
  A  ext/reflection/tests/gh22905/ReflectionClassConstant_construct_constant.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_construct.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_getMethod.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_getProperty.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_base.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_nobase.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_getStaticPropertyValue.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_implementsInterface.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_isSubclassOf.phpt
  A  ext/reflection/tests/gh22905/ReflectionClass_setStaticPropertyValue.phpt
  A  ext/reflection/tests/gh22905/ReflectionConstant_construct.phpt
  A  ext/reflection/tests/gh22905/ReflectionEnum_getCase.phpt
  A  ext/reflection/tests/gh22905/ReflectionExtension_construct.phpt
  A  ext/reflection/tests/gh22905/ReflectionFunction_construct.phpt
  A  ext/reflection/tests/gh22905/ReflectionMethod_construct_class.phpt
  A  ext/reflection/tests/gh22905/ReflectionMethod_construct_method.phpt
  A  ext/reflection/tests/gh22905/ReflectionMethod_create_method.phpt
  A  ext/reflection/tests/gh22905/ReflectionParameter_construct_class.phpt
  A  ext/reflection/tests/gh22905/ReflectionParameter_construct_method.phpt
  A  ext/reflection/tests/gh22905/ReflectionParameter_construct_string.phpt
  A  ext/reflection/tests/gh22905/ReflectionProperty_construct_class.phpt
  A  ext/reflection/tests/gh22905/ReflectionProperty_construct_property.phpt
  A  ext/reflection/tests/gh22905/ReflectionProperty_setRawValueWithoutLazyInitialization.phpt
  A  ext/reflection/tests/gh22905/ReflectionProperty_skipLazyInitialization.phpt
  A  ext/reflection/tests/gh22905/ReflectionZendExtension_construct.phpt
  A  ext/reflection/tests/gh22905/Reflection_getAttributes.phpt
  M  Zend/zend.c
  M  ext/reflection/php_reflection.c


Diff:

diff --git a/Zend/zend.c b/Zend/zend.c
index 59a1a1a3ba88..e58566541dd2 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -1816,7 +1816,6 @@ ZEND_API void zend_free_recorded_errors(void)
 ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) /* {{{ */
 {
 	va_list va;
-	char *message = NULL;
 
 	if (!exception_ce) {
 		exception_ce = zend_ce_error;
@@ -1828,16 +1827,20 @@ ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const c
 	}
 
 	va_start(va, format);
-	zend_vspprintf(&message, 0, format, va);
+	zend_string *message = zend_vstrpprintf(0, format, va);
 
 	//TODO: we can't convert compile-time errors to exceptions yet???
 	if (EG(current_execute_data) && !CG(in_compilation)) {
-		zend_throw_exception(exception_ce, message, 0);
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		// Use "%S" so that the message can contain null bytes.
+		const char *format = "%S";
+		zend_throw_exception_ex(exception_ce, 0, format, message);
 	} else {
-		zend_error_noreturn(E_ERROR, "%s", message);
+		zend_error_noreturn(E_ERROR, "%s", ZSTR_VAL(message));
 	}
 
-	efree(message);
+	zend_string_release(message);
 	va_end(va);
 }
 /* }}} */
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 9780a0368cf5..9aa6a908627f 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -1382,7 +1382,10 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut
 	if (name && (flags & REFLECTION_ATTRIBUTE_IS_INSTANCEOF)) {
 		if (NULL == (base = zend_lookup_class(name))) {
 			if (!EG(exception)) {
-				zend_throw_error(NULL, "Class \"%s\" not found", ZSTR_VAL(name));
+				// %S is used for zend_string pointers by smart str printing, but normally
+				// is for wide character strings and so compilers complain if this is inline
+				const char *format = "Class \"%S\" not found";
+				zend_throw_error(NULL, format, name);
 			}
 
 			RETURN_THROWS();
@@ -1802,8 +1805,11 @@ ZEND_METHOD(ReflectionFunction, __construct)
 		}
 
 		if (fptr == NULL) {
+			// %S is used for zend_string pointers by smart str printing, but normally
+			// is for wide character strings and so compilers complain if this is inline
+			const char *format = "Function %S() does not exist";
 			zend_throw_exception_ex(reflection_exception_ptr, 0,
-				"Function %s() does not exist", ZSTR_VAL(fname));
+				format, fname);
 			RETURN_THROWS();
 		}
 	}
@@ -2566,8 +2572,11 @@ ZEND_METHOD(ReflectionParameter, __construct)
 					zend_string_release(lcname);
 				}
 				if (!fptr) {
+					// %S is used for zend_string pointers by smart str printing, but normally
+					// is for wide character strings and so compilers complain if this is inline
+					const char *format = "Function %S() does not exist";
 					zend_throw_exception_ex(reflection_exception_ptr, 0,
-						"Function %s() does not exist", Z_STRVAL_P(reference));
+						format, Z_STR_P(reference));
 					RETURN_THROWS();
 				}
 				ce = fptr->common.scope;
@@ -2594,8 +2603,11 @@ ZEND_METHOD(ReflectionParameter, __construct)
 						return;
 					}
 					if ((ce = zend_lookup_class(name)) == NULL) {
+						// %S is used for zend_string pointers by smart str printing, but normally
+						// is for wide character strings and so compilers complain if this is inline
+						const char *format = "Class \"%S\" does not exist";
 						zend_throw_exception_ex(reflection_exception_ptr, 0,
-								"Class \"%s\" does not exist", ZSTR_VAL(name));
+								format, name);
 						zend_string_release(name);
 						RETURN_THROWS();
 					}
@@ -2614,8 +2626,11 @@ ZEND_METHOD(ReflectionParameter, __construct)
 					/* nothing to do. don't set is_closure since is the invoke handler,
 					   not the closure itself */
 				} else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
+					// %S is used for zend_string pointers by smart str printing, but normally
+					// is for wide character strings and so compilers complain if this is inline
+					const char *format = "Method %S::%S() does not exist";
 					zend_throw_exception_ex(reflection_exception_ptr, 0,
-						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+						format, ce->name, name);
 					zend_string_release(name);
 					zend_string_release(lcname);
 					RETURN_THROWS();
@@ -3380,7 +3395,10 @@ static void instantiate_reflection_method(INTERNAL_FUNCTION_PARAMETERS, bool is_
 	if (class_name) {
 		if ((ce = zend_lookup_class(class_name)) == NULL) {
 			if (!EG(exception)) {
-				zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_name));
+				// %S is used for zend_string pointers by smart str printing, but normally
+				// is for wide character strings and so compilers complain if this is inline
+				const char *format = "Class \"%S\" does not exist";
+				zend_throw_exception_ex(reflection_exception_ptr, 0, format, class_name);
 			}
 			zend_string_release(class_name);
 			RETURN_THROWS();
@@ -3409,8 +3427,16 @@ static void instantiate_reflection_method(INTERNAL_FUNCTION_PARAMETERS, bool is_
 		/* do nothing, mptr already set */
 	} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
 		efree(lcname);
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Method %S::%S() does not exist";
+		ALLOCA_FLAG(use_heap);
+		zend_string *method_name_zstr;
+		ZSTR_ALLOCA_INIT(method_name_zstr, method_name, method_name_len, use_heap);
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
-			"Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
+			format, ce->name, method_name_zstr);
+		ZSTR_ALLOCA_FREE(method_name_zstr, use_heap);
+
 		RETURN_THROWS();
 	}
 	efree(lcname);
@@ -3893,7 +3919,10 @@ ZEND_METHOD(ReflectionClassConstant, __construct)
 		ce = classname_obj->ce;
 	} else {
 		if ((ce = zend_lookup_class(classname_str)) == NULL) {
-			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
+			// %S is used for zend_string pointers by smart str printing, but normally
+			// is for wide character strings and so compilers complain if this is inline
+			const char *format = "Class \"%S\" does not exist";
+			zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
 			RETURN_THROWS();
 		}
 	}
@@ -3902,7 +3931,10 @@ ZEND_METHOD(ReflectionClassConstant, __construct)
 	intern = Z_REFLECTION_P(object);
 
 	if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constname)) == NULL) {
-		zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Constant %S::%S does not exist";
+		zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, constname);
 		RETURN_THROWS();
 	}
 
@@ -4168,7 +4200,10 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob
 	} else {
 		if ((ce = zend_lookup_class(arg_class)) == NULL) {
 			if (!EG(exception)) {
-				zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(arg_class));
+				// %S is used for zend_string pointers by smart str printing, but normally
+				// is for wide character strings and so compilers complain if this is inline
+				const char *format = "Class \"%S\" does not exist";
+				zend_throw_exception_ex(reflection_exception_ptr, -1, format, arg_class);
 			}
 			RETURN_THROWS();
 		}
@@ -4310,8 +4345,11 @@ ZEND_METHOD(ReflectionClass, getStaticPropertyValue)
 		zend_throw_error(NULL,
 			"Typed property %s::$%s must not be accessed before initialization", ZSTR_VAL(ce->name), ZSTR_VAL(name));
 	} else {
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Property %S::$%S does not exist";
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
-			"Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+			format, ce->name, name);
 	}
 }
 /* }}} */
@@ -4340,8 +4378,11 @@ ZEND_METHOD(ReflectionClass, setStaticPropertyValue)
 	EG(fake_scope) = old_scope;
 	if (!variable_ptr) {
 		zend_clear_exception();
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Class %S does not have a property named %S";
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
-				"Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+				format, ce->name, name);
 		RETURN_THROWS();
 	}
 
@@ -4583,8 +4624,11 @@ ZEND_METHOD(ReflectionClass, getMethod)
 	} else if ((mptr = zend_hash_find_ptr(&ce->function_table, lc_name)) != NULL) {
 		reflection_method_factory(ce, mptr, NULL, return_value);
 	} else {
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Method %S::%S() does not exist";
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
-				"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+				format, ce->name, name);
 	}
 	zend_string_release(lc_name);
 }
@@ -4710,7 +4754,9 @@ ZEND_METHOD(ReflectionClass, getProperty)
 		}
 	}
 	str_name = ZSTR_VAL(name);
+	bool fully_qualified = false;
 	if ((tmp = zend_memnstr(ZSTR_VAL(name), "::", 2, ZSTR_VAL(name) + ZSTR_LEN(name))) != NULL) {
+		fully_qualified = true;
 		classname_len = tmp - ZSTR_VAL(name);
 		classname = zend_string_init(ZSTR_VAL(name), classname_len, 0);
 		str_name_len = ZSTR_LEN(name) - (classname_len + 2);
@@ -4727,7 +4773,15 @@ ZEND_METHOD(ReflectionClass, getProperty)
 		zend_string_release_ex(classname, 0);
 
 		if (!instanceof_function(ce, ce2)) {
-			zend_throw_exception_ex(reflection_exception_ptr, -1, "Fully qualified property name %s::$%s does not specify a base class of %s", ZSTR_VAL(ce2->name), str_name, ZSTR_VAL(ce->name));
+			// %S is used for zend_string pointers by smart str printing, but normally
+			// is for wide character strings and so compilers complain if this is inline
+			const char *format = "Fully qualified property name %S::$%S does not specify a base class of %S";
+			ALLOCA_FLAG(use_heap);
+			zend_string *prop_name_zstr;
+			ZSTR_ALLOCA_INIT(prop_name_zstr, str_name, str_name_len, use_heap);
+			zend_throw_exception_ex(reflection_exception_ptr, -1, format, ce2->name, prop_name_zstr, ce->name);
+			ZSTR_ALLOCA_FREE(prop_name_zstr, use_heap);
+
 			RETURN_THROWS();
 		}
 		ce = ce2;
@@ -4740,7 +4794,19 @@ ZEND_METHOD(ReflectionClass, getProperty)
 			return;
 		}
 	}
-	zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), str_name);
+	// %S is used for zend_string pointers by smart str printing, but normally
+	// is for wide character strings and so compilers complain if this is inline
+	const char *format = "Property %S::$%S does not exist";
+	// Can only use the existing `name` string if it wasn't fully qualified
+	if (fully_qualified) {
+		ALLOCA_FLAG(use_heap);
+		zend_string *prop_name_zstr;
+		ZSTR_ALLOCA_INIT(prop_name_zstr, str_name, str_name_len, use_heap);
+		zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, prop_name_zstr);
+		ZSTR_ALLOCA_FREE(prop_name_zstr, use_heap);
+	} else {
+		zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, name);
+	}
 }
 /* }}} */
 
@@ -5584,7 +5650,10 @@ ZEND_METHOD(ReflectionClass, isSubclassOf)
 		class_ce = argument->ptr;
 	} else {
 		if ((class_ce = zend_lookup_class(class_str)) == NULL) {
-			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_str));
+			// %S is used for zend_string pointers by smart str printing, but normally
+			// is for wide character strings and so compilers complain if this is inline
+			const char *format = "Class \"%S\" does not exist";
+			zend_throw_exception_ex(reflection_exception_ptr, 0, format, class_str);
 			RETURN_THROWS();
 		}
 	}
@@ -5617,7 +5686,10 @@ ZEND_METHOD(ReflectionClass, implementsInterface)
 		interface_ce = argument->ptr;
 	} else {
 		if ((interface_ce = zend_lookup_class(interface_str)) == NULL) {
-			zend_throw_exception_ex(reflection_exception_ptr, 0, "Interface \"%s\" does not exist", ZSTR_VAL(interface_str));
+			// %S is used for zend_string pointers by smart str printing, but normally
+			// is for wide character strings and so compilers complain if this is inline
+			const char *format = "Interface \"%S\" does not exist";
+			zend_throw_exception_ex(reflection_exception_ptr, 0, format, interface_str);
 			RETURN_THROWS();
 		}
 	}
@@ -5773,7 +5845,10 @@ ZEND_METHOD(ReflectionProperty, __construct)
 		ce = classname_obj->ce;
 	} else {
 		if ((ce = zend_lookup_class(classname_str)) == NULL) {
-			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
+			// %S is used for zend_string pointers by smart str printing, but normally
+			// is for wide character strings and so compilers complain if this is inline
+			const char *format = "Class \"%S\" does not exist";
+			zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
 			RETURN_THROWS();
 		}
 	}
@@ -5789,7 +5864,10 @@ ZEND_METHOD(ReflectionProperty, __construct)
 			}
 		}
 		if (dynam_prop == 0) {
-			zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+			// %S is used for zend_string pointers by smart str printing, but normally
+			// is for wide character strings and so compilers complain if this is inline
+			const char *format = "Property %S::$%S does not exist";
+			zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, name);
 			RETURN_THROWS();
 		}
 	}
@@ -6199,13 +6277,17 @@ static zend_result reflection_property_check_lazy_compatible(
 		zend_property_info *prop, zend_string *unmangled_name,
 		reflection_object *intern, zend_object *object, const char *method)
 {
-	if (!prop) {
+	if (!prop) {		
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Can not use %s on dynamic property %S::$%S";
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
-				"Can not use %s on dynamic property %s::$%s",
-				method, ZSTR_VAL(intern->ce->name),
-				ZSTR_VAL(unmangled_name));
+				format,
+				method, intern->ce->name,
+				unmangled_name);
 		return FAILURE;
 	}
+	// Non-dynamic properties cannot have null bytes so %s is fine
 
 	if (prop->flags & ZEND_ACC_STATIC) {
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
@@ -6729,22 +6811,24 @@ ZEND_METHOD(ReflectionExtension, __construct)
 	char *lcname;
 	reflection_object *intern;
 	zend_module_entry *module;
-	char *name_str;
-	size_t name_len;
+	zend_string *name_zstr;
 	ALLOCA_FLAG(use_heap)
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name_zstr) == FAILURE) {
 		RETURN_THROWS();
 	}
 
 	object = ZEND_THIS;
 	intern = Z_REFLECTION_P(object);
-	lcname = do_alloca(name_len + 1, use_heap);
-	zend_str_tolower_copy(lcname, name_str, name_len);
-	if ((module = zend_hash_str_find_ptr(&module_registry, lcname, name_len)) == NULL) {
+	lcname = do_alloca(ZSTR_LEN(name_zstr) + 1, use_heap);
+	zend_str_tolower_copy(lcname, ZSTR_VAL(name_zstr), ZSTR_LEN(name_zstr));
+	if ((module = zend_hash_str_find_ptr(&module_registry, lcname, ZSTR_LEN(name_zstr))) == NULL) {
 		free_alloca(lcname, use_heap);
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Extension \"%S\" does not exist";
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
-			"Extension \"%s\" does not exist", name_str);
+			format, name_zstr);
 		RETURN_THROWS();
 	}
 	free_alloca(lcname, use_heap);
@@ -7045,20 +7129,22 @@ ZEND_METHOD(ReflectionZendExtension, __construct)
 	zval *object;
 	reflection_object *intern;
 	zend_extension *extension;
-	char *name_str;
-	size_t name_len;
+	zend_string *name_zstr;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name_zstr) == FAILURE) {
 		RETURN_THROWS();
 	}
 
 	object = ZEND_THIS;
 	intern = Z_REFLECTION_P(object);
 
-	extension = zend_get_extension(name_str);
+	extension = zend_get_extension(ZSTR_VAL(name_zstr));
 	if (!extension) {
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Zend Extension \"%S\" does not exist";
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
-				"Zend Extension \"%s\" does not exist", name_str);
+				format, name_zstr);
 		RETURN_THROWS();
 	}
 	ZVAL_STRING(reflection_prop_name(object), extension->name);
@@ -7519,7 +7605,10 @@ ZEND_METHOD(ReflectionEnum, getCase)
 
 	zend_class_constant *constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name);
 	if (constant == NULL) {
-		zend_throw_exception_ex(reflection_exception_ptr, 0, "Case %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Case %S::%S does not exist";
+		zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, name);
 		RETURN_THROWS();
 	}
 	if (!(ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE)) {
@@ -7819,7 +7908,10 @@ ZEND_METHOD(ReflectionConstant, __construct)
 	zend_constant *const_ = zend_get_constant_ptr(lc_name);
 	zend_string_release_ex(lc_name, /* persistent */ false);
 	if (!const_) {
-		zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant \"%s\" does not exist", ZSTR_VAL(name));
+		// %S is used for zend_string pointers by smart str printing, but normally
+		// is for wide character strings and so compilers complain if this is inline
+		const char *format = "Constant \"%S\" does not exist";
+		zend_throw_exception_ex(reflection_exception_ptr, 0, format, name);
 		RETURN_THROWS();
 	}
 
diff --git a/ext/reflection/tests/gh22905/ReflectionClassConstant_construct_class.phpt b/ext/reflection/tests/gh22905/ReflectionClassConstant_construct_class.phpt
new file mode 100644
index 000000000000..cb8ce925e851
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClassConstant_construct_class.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionClassConstant::__construct() error messages (class name)
+--FILE--
+<?php
+
+new ReflectionClassConstant("foo\0bar", "");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Class "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClassConstant->__construct('foo\x00bar', '')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClassConstant_construct_constant.phpt b/ext/reflection/tests/gh22905/ReflectionClassConstant_construct_constant.phpt
new file mode 100644
index 000000000000..537204a781b4
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClassConstant_construct_constant.phpt
@@ -0,0 +1,15 @@
+--TEST--
+GH-22905: null bytes in ReflectionClassConstant::__construct() error messages (constant name)
+--FILE--
+<?php
+
+class Demo {}
+new ReflectionClassConstant(Demo::class, "foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Constant Demo::foo%0bar does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClassConstant->__construct('Demo', 'foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_construct.phpt b/ext/reflection/tests/gh22905/ReflectionClass_construct.phpt
new file mode 100644
index 000000000000..f4575993c631
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_construct.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::__construct() error messages
+--FILE--
+<?php
+
+new ReflectionClass("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Class "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->__construct('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_getMethod.phpt b/ext/reflection/tests/gh22905/ReflectionClass_getMethod.phpt
new file mode 100644
index 000000000000..27bfbd9072a8
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_getMethod.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::getMethod() error messages
+--FILE--
+<?php
+
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->getMethod("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Method Demo::foo%0bar() does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->getMethod('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_getProperty.phpt b/ext/reflection/tests/gh22905/ReflectionClass_getProperty.phpt
new file mode 100644
index 000000000000..d989daebdebb
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_getProperty.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::getProperty() error messages
+--FILE--
+<?php
+
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->getProperty("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Property Demo::$foo%0bar does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->getProperty('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_base.phpt b/ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_base.phpt
new file mode 100644
index 000000000000..650e9ad189e2
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_base.phpt
@@ -0,0 +1,17 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::getProperty() (fully qualified, base class) error messages
+--FILE--
+<?php
+
+class Base {}
+class Demo extends Base {}
+$r = new ReflectionClass(Demo::class);
+$r->getProperty("Base::foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Property Base::$foo%0bar does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->getProperty('Base::foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_nobase.phpt b/ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_nobase.phpt
new file mode 100644
index 000000000000..561a2afc585d
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_getProperty_qualified_nobase.phpt
@@ -0,0 +1,17 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::getProperty() (fully qualified, non-base class) error messages
+--FILE--
+<?php
+
+class Base {}
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->getProperty("Base::foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Fully qualified property name Base::$foo%0bar does not specify a base class of Demo in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->getProperty('Base::foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_getStaticPropertyValue.phpt b/ext/reflection/tests/gh22905/ReflectionClass_getStaticPropertyValue.phpt
new file mode 100644
index 000000000000..7ded20bedd46
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_getStaticPropertyValue.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::getStaticPropertyValue() error messages
+--FILE--
+<?php
+
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->getStaticPropertyValue("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Property Demo::$foo%0bar does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->getStaticPropertyValue('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_implementsInterface.phpt b/ext/reflection/tests/gh22905/ReflectionClass_implementsInterface.phpt
new file mode 100644
index 000000000000..b516907dc51e
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_implementsInterface.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::implementsInterface() error messages
+--FILE--
+<?php
+
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->implementsInterface("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Interface "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->implementsInterface('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_isSubclassOf.phpt b/ext/reflection/tests/gh22905/ReflectionClass_isSubclassOf.phpt
new file mode 100644
index 000000000000..915426824f3f
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_isSubclassOf.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::isSubclassOf() error messages
+--FILE--
+<?php
+
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->isSubclassOf("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Class "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->isSubclassOf('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionClass_setStaticPropertyValue.phpt b/ext/reflection/tests/gh22905/ReflectionClass_setStaticPropertyValue.phpt
new file mode 100644
index 000000000000..c450f41cb6ed
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionClass_setStaticPropertyValue.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionClass::setStaticPropertyValue() error messages
+--FILE--
+<?php
+
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->setStaticPropertyValue("foo\0bar", 123);
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Class Demo does not have a property named foo%0bar in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->setStaticPropertyValue('foo\x00bar', 123)
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionConstant_construct.phpt b/ext/reflection/tests/gh22905/ReflectionConstant_construct.phpt
new file mode 100644
index 000000000000..62b6024d83d7
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionConstant_construct.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionConstant::__construct() error messages
+--FILE--
+<?php
+
+new ReflectionConstant("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Constant "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionConstant->__construct('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionEnum_getCase.phpt b/ext/reflection/tests/gh22905/ReflectionEnum_getCase.phpt
new file mode 100644
index 000000000000..3c50da112ef0
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionEnum_getCase.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionEnum::getCase() error messages
+--FILE--
+<?php
+
+enum Demo {}
+$r = new ReflectionEnum(Demo::class);
+$r->getCase("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Case Demo::foo%0bar does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionEnum->getCase('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionExtension_construct.phpt b/ext/reflection/tests/gh22905/ReflectionExtension_construct.phpt
new file mode 100644
index 000000000000..c1980087edbb
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionExtension_construct.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionExtension::__construct() error messages
+--FILE--
+<?php
+
+new ReflectionExtension("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Extension "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionExtension->__construct('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionFunction_construct.phpt b/ext/reflection/tests/gh22905/ReflectionFunction_construct.phpt
new file mode 100644
index 000000000000..a145473c3485
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionFunction_construct.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionFunction::__construct() error messages
+--FILE--
+<?php
+
+new ReflectionFunction("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Function foo%0bar() does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionFunction->__construct('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionMethod_construct_class.phpt b/ext/reflection/tests/gh22905/ReflectionMethod_construct_class.phpt
new file mode 100644
index 000000000000..fcc39c1209bd
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionMethod_construct_class.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionMethod::__construct() error messages (class name)
+--FILE--
+<?php
+
+new ReflectionMethod("foo\0bar", "");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Class "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionMethod->__construct('foo\x00bar', '')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionMethod_construct_method.phpt b/ext/reflection/tests/gh22905/ReflectionMethod_construct_method.phpt
new file mode 100644
index 000000000000..1a4ba03cf2d2
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionMethod_construct_method.phpt
@@ -0,0 +1,15 @@
+--TEST--
+GH-22905: null bytes in ReflectionMethod::__construct() error messages (method name)
+--FILE--
+<?php
+
+class Demo {}
+new ReflectionMethod(Demo::class, "foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Method Demo::foo%0bar() does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionMethod->__construct('Demo', 'foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionMethod_create_method.phpt b/ext/reflection/tests/gh22905/ReflectionMethod_create_method.phpt
new file mode 100644
index 000000000000..137106559dcd
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionMethod_create_method.phpt
@@ -0,0 +1,15 @@
+--TEST--
+GH-22905: null bytes in ReflectionMethod::createFromMethodName() error messages (method name)
+--FILE--
+<?php
+
+class Demo {}
+ReflectionMethod::createFromMethodName("Demo::foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Method Demo::foo%0bar() does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionMethod::createFromMethodName('Demo::foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionParameter_construct_class.phpt b/ext/reflection/tests/gh22905/ReflectionParameter_construct_class.phpt
new file mode 100644
index 000000000000..6b2b599a1109
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionParameter_construct_class.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionParameter::__construct() error messages (array class name)
+--FILE--
+<?php
+
+new ReflectionParameter(["foo\0bar", ""], 0);
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Class "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionParameter->__construct(Array, 0)
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionParameter_construct_method.phpt b/ext/reflection/tests/gh22905/ReflectionParameter_construct_method.phpt
new file mode 100644
index 000000000000..2158724dd451
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionParameter_construct_method.phpt
@@ -0,0 +1,15 @@
+--TEST--
+GH-22905: null bytes in ReflectionParameter::__construct() error messages (array method name)
+--FILE--
+<?php
+
+class Demo {}
+new ReflectionParameter([Demo::class, "foo\0bar"], 0);
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Method Demo::foo%0bar() does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionParameter->__construct(Array, 0)
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionParameter_construct_string.phpt b/ext/reflection/tests/gh22905/ReflectionParameter_construct_string.phpt
new file mode 100644
index 000000000000..2ac9b8b763d2
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionParameter_construct_string.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionParameter::__construct() error messages (string function)
+--FILE--
+<?php
+
+new ReflectionParameter("foo\0bar", 0);
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Function foo%0bar() does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionParameter->__construct('foo\x00bar', 0)
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionProperty_construct_class.phpt b/ext/reflection/tests/gh22905/ReflectionProperty_construct_class.phpt
new file mode 100644
index 000000000000..a5a785e908ea
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionProperty_construct_class.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionProperty::__construct() error messages (class name)
+--FILE--
+<?php
+
+new ReflectionProperty("foo\0bar", "");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Class "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionProperty->__construct('foo\x00bar', '')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionProperty_construct_property.phpt b/ext/reflection/tests/gh22905/ReflectionProperty_construct_property.phpt
new file mode 100644
index 000000000000..d18f926ecbff
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionProperty_construct_property.phpt
@@ -0,0 +1,15 @@
+--TEST--
+GH-22905: null bytes in ReflectionProperty::__construct() error messages (property name)
+--FILE--
+<?php
+
+class Demo {}
+new ReflectionProperty(Demo::class, "foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Property Demo::$foo%0bar does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionProperty->__construct('Demo', 'foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionProperty_setRawValueWithoutLazyInitialization.phpt b/ext/reflection/tests/gh22905/ReflectionProperty_setRawValueWithoutLazyInitialization.phpt
new file mode 100644
index 000000000000..d2d609bcf287
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionProperty_setRawValueWithoutLazyInitialization.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionProperty::setRawValueWithoutLazyInitialization() error messages
+--FILE--
+<?php
+
+$o = (object)["foo\0bar" => "baz"];
+$r = new ReflectionProperty($o, "foo\0bar");
+$r->setRawValueWithoutLazyInitialization($o, 123);
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Can not use setRawValueWithoutLazyInitialization on dynamic property stdClass::$foo%0bar in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionProperty->setRawValueWithoutLazyInitialization(Object(stdClass), 123)
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionProperty_skipLazyInitialization.phpt b/ext/reflection/tests/gh22905/ReflectionProperty_skipLazyInitialization.phpt
new file mode 100644
index 000000000000..49bad02ab4d7
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionProperty_skipLazyInitialization.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in ReflectionProperty::skipLazyInitialization() error messages
+--FILE--
+<?php
+
+$o = (object)["foo\0bar" => "baz"];
+$r = new ReflectionProperty($o, "foo\0bar");
+$r->skipLazyInitialization($o);
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Can not use skipLazyInitialization on dynamic property stdClass::$foo%0bar in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionProperty->skipLazyInitialization(Object(stdClass))
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/ReflectionZendExtension_construct.phpt b/ext/reflection/tests/gh22905/ReflectionZendExtension_construct.phpt
new file mode 100644
index 000000000000..5722b6b08d8f
--- /dev/null
+++ b/ext/reflection/tests/gh22905/ReflectionZendExtension_construct.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-22905: null bytes in ReflectionZendExtension::__construct() error messages
+--FILE--
+<?php
+
+new ReflectionZendExtension("foo\0bar");
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ReflectionException: Zend Extension "foo%0bar" does not exist in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionZendExtension->__construct('foo\x00bar')
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/reflection/tests/gh22905/Reflection_getAttributes.phpt b/ext/reflection/tests/gh22905/Reflection_getAttributes.phpt
new file mode 100644
index 000000000000..ea3ec411629f
--- /dev/null
+++ b/ext/reflection/tests/gh22905/Reflection_getAttributes.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-22905: null bytes in Reflection*::getAttributes() error messages
+--FILE--
+<?php
+
+class Demo {}
+$r = new ReflectionClass(Demo::class);
+$r->getAttributes("foo\0bar", ReflectionAttribute::IS_INSTANCEOF);
+
+?>
+--EXPECTF--
+Fatal error: Uncaught Error: Class "foo%0bar" not found in %s:%d
+Stack trace:
+#0 %s(%d): ReflectionClass->getAttributes('foo\x00bar', 2)
+#1 {main}
+  thrown in %s on line %d