diff --git a/Universal/Docs/WhiteSpace/FnKeywordSpacingStandard.xml b/Universal/Docs/WhiteSpace/FnKeywordSpacingStandard.xml
new file mode 100644
index 0000000..6427176
--- /dev/null
+++ b/Universal/Docs/WhiteSpace/FnKeywordSpacingStandard.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+ ($x) => $x + 1;
+ ]]>
+
+
+ ($x) => $x + 1;
+ ]]>
+
+
+
diff --git a/Universal/Sniffs/WhiteSpace/FnKeywordSpacingSniff.php b/Universal/Sniffs/WhiteSpace/FnKeywordSpacingSniff.php
new file mode 100644
index 0000000..035bd65
--- /dev/null
+++ b/Universal/Sniffs/WhiteSpace/FnKeywordSpacingSniff.php
@@ -0,0 +1,73 @@
+
+ */
+ public function register()
+ {
+ return [\T_FN];
+ }
+
+ /**
+ * Processes this sniff, when one of its tokens is encountered.
+ *
+ * @since 1.6.0
+ *
+ * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
+ * @param int $stackPtr The position of the current token in the stack passed in $tokens.
+ *
+ * @return void
+ */
+ public function process(File $phpcsFile, $stackPtr)
+ {
+ $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
+
+ SpacesFixer::checkAndFix(
+ $phpcsFile,
+ $stackPtr,
+ $nextNonEmpty,
+ (int) $this->spacingAfterKeyword,
+ 'Expected %s after the "fn" keyword. Found: %s.',
+ 'Incorrect',
+ 'error',
+ 0,
+ 'Spacing after the arrow function "fn" keyword'
+ );
+ }
+}
diff --git a/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.1.inc b/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.1.inc
new file mode 100644
index 0000000..81e1964
--- /dev/null
+++ b/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.1.inc
@@ -0,0 +1,31 @@
+ $x + 1;
+$fn = fn&() => doSomething();
+$fn = static fn($x) => fn($y) => $x + $y;
+
+/*
+ * Invalid spacing.
+ */
+
+$fn = fn ($x) => $x + 1;
+$fn = fn &($x) => $x + 1;
+$fn = static fn
+ ($x) => $x + 1;
+$fn = fn () => doSomething();
+
+$fn = fn ($x) => fn ($y) => $x + $y;
+
+$fn = fn
+ /* comment */
+ ($x) => $x + 1;
+
+// phpcs:set Universal.WhiteSpace.FnKeywordSpacing spacingAfterKeyword 1
+$fn = fn($x) => $x + 1; // Error.
+$fn = fn ($x) => $x + 1; // OK.
+// Resetting to the default value.
+// phpcs:set Universal.WhiteSpace.FnKeywordSpacing spacingAfterKeyword 0
diff --git a/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.1.inc.fixed b/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.1.inc.fixed
new file mode 100644
index 0000000..cb6a55d
--- /dev/null
+++ b/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.1.inc.fixed
@@ -0,0 +1,30 @@
+ $x + 1;
+$fn = fn&() => doSomething();
+$fn = static fn($x) => fn($y) => $x + $y;
+
+/*
+ * Invalid spacing.
+ */
+
+$fn = fn($x) => $x + 1;
+$fn = fn&($x) => $x + 1;
+$fn = static fn($x) => $x + 1;
+$fn = fn() => doSomething();
+
+$fn = fn($x) => fn($y) => $x + $y;
+
+$fn = fn
+ /* comment */
+ ($x) => $x + 1;
+
+// phpcs:set Universal.WhiteSpace.FnKeywordSpacing spacingAfterKeyword 1
+$fn = fn ($x) => $x + 1; // Error.
+$fn = fn ($x) => $x + 1; // OK.
+// Resetting to the default value.
+// phpcs:set Universal.WhiteSpace.FnKeywordSpacing spacingAfterKeyword 0
diff --git a/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.php b/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.php
new file mode 100644
index 0000000..37cfee3
--- /dev/null
+++ b/Universal/Tests/WhiteSpace/FnKeywordSpacingUnitTest.php
@@ -0,0 +1,52 @@
+ Key is the line number, value is the number of expected errors.
+ */
+ public function getErrorList()
+ {
+ return [
+ 15 => 1,
+ 16 => 1,
+ 17 => 1,
+ 19 => 1,
+ 21 => 2,
+ 23 => 1,
+ 28 => 1,
+ ];
+ }
+
+ /**
+ * Returns the lines where warnings should occur.
+ *
+ * @return array Key is the line number, value is the number of expected warnings.
+ */
+ public function getWarningList()
+ {
+ return [];
+ }
+}