diff --git a/build/code_sniffer/phpbb/Sniffs/CodeLayout/UnionTypesCheckSniff.php b/build/code_sniffer/phpbb/Sniffs/CodeLayout/UnionTypesCheckSniff.php
new file mode 100644
index 0000000000..64b30a859e
--- /dev/null
+++ b/build/code_sniffer/phpbb/Sniffs/CodeLayout/UnionTypesCheckSniff.php
@@ -0,0 +1,116 @@
+
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\Sniffs\CodeLayout;
+
+use PHP_CodeSniffer\Files\File;
+use PHP_CodeSniffer\Sniffs\Sniff;
+
+/**
+ * Checks that union type declarations follows the coding guidelines.
+ */
+class UnionTypesCheckSniff implements Sniff
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function register()
+ {
+ return [
+ T_FUNCTION,
+ T_CLASS,
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(File $phpcsFile, $stackPtr)
+ {
+ $tokens = $phpcsFile->getTokens();
+ if ($tokens[$stackPtr]['type'] === 'T_FUNCTION')
+ {
+ $method_params = $phpcsFile->getMethodParameters($stackPtr);
+ $method_params_array = array_column($method_params, 'type_hint', 'token');
+ foreach ($method_params_array as $stack_pointer => $type_hint)
+ {
+ $this->check_union_type($phpcsFile, $stack_pointer, $type_hint);
+ }
+
+ $method_properties = $phpcsFile->getMethodProperties($stackPtr);
+ $this->check_union_type($phpcsFile, $stackPtr, $method_properties['return_type']);
+ }
+ else if ($tokens[$stackPtr]['type'] === 'T_CLASS')
+ {
+ $class_token = $tokens[$stackPtr];
+ $class_closer_pointer = $class_token['scope_closer'];
+ $first_method_pointer = $phpcsFile->findNext(T_FUNCTION, $stackPtr);
+ $class_members_declarations_end_pointer = $first_method_pointer ?: $class_closer_pointer;
+
+ $stack_pointer = $stackPtr;
+ while(($class_member_pointer = $phpcsFile->findNext(T_VARIABLE, $stack_pointer)) !== false && ($class_member_pointer < $class_members_declarations_end_pointer))
+ {
+ $properties = $phpcsFile->getMemberProperties($class_member_pointer);
+ $this->check_union_type($phpcsFile, $class_member_pointer, $properties['type']);
+ $stack_pointer = $class_member_pointer + 1;
+ }
+ }
+ }
+
+ public function check_union_type(File $phpcsFile, $stack_pointer, $type_hint)
+ {
+ if (empty($type_hint))
+ {
+ return;
+ }
+
+ if (!strpos($type_hint, '|') && $type_hint[0] == '?') // Check nullable shortcut syntax
+ {
+ $type = substr($type_hint, 1);
+ $error = 'Nullable shortcut syntax must not be used. Use union type instead: %1$s|null; found %2$s';
+ $data = [$type, $type_hint];
+ $phpcsFile->addError($error, $stack_pointer, 'ShortNullableSyntax', $data);
+ }
+ else if ((count($types_array = explode('|', $type_hint))) > 1) // Check union type layout
+ {
+ $types_array_null_less = $types_array;
+
+ // Check 'null' to be the last element
+ $null_position = array_search('null', $types_array);
+ if ($null_position !== false && $null_position != array_key_last($types_array))
+ {
+ $error = 'The "null" type hint must be the last of the union type elements; found %s';
+ $data = [implode('|', $types_array)];
+ $phpcsFile->addError($error, $stack_pointer, 'NullAlwaysLast', $data);
+ }
+
+ // Check types excepting 'null' to follow alphabetical order
+ if ($null_position !== false)
+ {
+ array_splice($types_array_null_less, $null_position, 1);
+ }
+
+ if (count($types_array_null_less) > 1)
+ {
+ $types_array_null_less_sorted = $types_array_null_less;
+ sort($types_array_null_less_sorted);
+ if (!empty(array_diff_assoc($types_array_null_less, $types_array_null_less_sorted)))
+ {
+ $error = 'Union type elements must be sorted alphabetically excepting the "null" type hint must be the last if any; found %s';
+ $data = [implode('|', $types_array)];
+ $phpcsFile->addError($error, $stack_pointer, 'AlphabeticalSort', $data);
+ }
+ }
+ }
+ }
+}
diff --git a/build/code_sniffer/ruleset-php-strict.xml b/build/code_sniffer/ruleset-php-strict.xml
index 9e2f0664d8..58fe270021 100644
--- a/build/code_sniffer/ruleset-php-strict.xml
+++ b/build/code_sniffer/ruleset-php-strict.xml
@@ -45,4 +45,8 @@
+
+
+
diff --git a/phpBB/phpbb/routing/loader_resolver.php b/phpBB/phpbb/routing/loader_resolver.php
index de3adcaa34..2e21d8bb3d 100644
--- a/phpBB/phpbb/routing/loader_resolver.php
+++ b/phpBB/phpbb/routing/loader_resolver.php
@@ -33,7 +33,7 @@ class loader_resolver implements LoaderResolverInterface
/**
* {@inheritdoc}
*/
- public function resolve($resource, $type = null): false|\Symfony\Component\Config\Loader\LoaderInterface
+ public function resolve($resource, $type = null): \Symfony\Component\Config\Loader\LoaderInterface|false
{
/** @var \Symfony\Component\Config\Loader\LoaderInterface $loader */
foreach ($this->loaders as $loader)