Skip to content

Commit 04243a9

Browse files
committed
Ruleset: hard deprecate support for sniffs not implementing the Sniff interface
While sniffs which don't implement the `Sniff` interface, but do implement the `register()` and `process()` methods, will _work_, it should be considered strongly discouraged. This commit adds a new, non-blocking deprecation notice which will inform users if they are using a sniff which doesn't implement the `Sniff` interface. The intention is to remove support for sniffs which don't implement the `Sniff` interface in PHPCS 4.0. Includes tests. This commit executes step 3 to address issue 694..
1 parent ee7e4f0 commit 04243a9

10 files changed

+165
-1
lines changed

Diff for: src/Ruleset.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,12 @@ public function registerSniffs($files, $restrictions, $exclusions)
14091409
continue;
14101410
}
14111411

1412-
if ($reflection->implementsInterface('PHP_CodeSniffer\Sniffs\Sniff') === false) {
1412+
if ($reflection->implementsInterface('PHP_CodeSniffer\\Sniffs\\Sniff') === false) {
1413+
$message = 'All sniffs must implement the PHP_CodeSniffer\\Sniffs\\Sniff interface.'.PHP_EOL;
1414+
$message .= "Interface not implemented for sniff $className.".PHP_EOL;
1415+
$message .= 'Contact the sniff author to fix the sniff.';
1416+
$this->msgCache->add($message, MessageCollector::DEPRECATED);
1417+
14131418
// Skip classes which don't implement the register() or process() methods.
14141419
if (method_exists($className, 'register') === false
14151420
|| method_exists($className, 'process') === false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\RegisterSniffsMissingInterfaceTest
6+
*/
7+
8+
namespace Fixtures\TestStandard\Sniffs\MissingInterface;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
12+
final class InvalidImplementsWithoutImplementSniff
13+
{
14+
15+
public function register()
16+
{
17+
return [T_OPEN_TAG];
18+
}
19+
20+
public function process(File $phpcsFile, $stackPtr)
21+
{
22+
// Do something.
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\RegisterSniffsMissingInterfaceTest
6+
*/
7+
8+
namespace Fixtures\TestStandard\Sniffs\MissingInterface;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
use PHP_CodeSniffer\Sniffs\Sniff;
12+
13+
final class ValidImplementsSniff implements Sniff
14+
{
15+
16+
public function register()
17+
{
18+
return [T_OPEN_TAG];
19+
}
20+
21+
public function process(File $phpcsFile, $stackPtr)
22+
{
23+
// Do something.
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\RegisterSniffsMissingInterfaceTest
6+
*/
7+
8+
namespace Fixtures\TestStandard\Sniffs\MissingInterface;
9+
10+
use PHP_CodeSniffer\Sniffs\AbstractArraySniff;
11+
12+
final class ValidImplementsViaAbstractSniff extends AbstractArraySniff
13+
{
14+
15+
protected function processSingleLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices)
16+
{
17+
// Do something.
18+
}
19+
20+
protected function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices)
21+
{
22+
// Do something.
23+
}
24+
}

Diff for: tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<rule ref="TestStandard">
77
<exclude name="TestStandard.InvalidSniffs"/>
88
<exclude name="TestStandard.InvalidSniffError"/>
9+
<exclude name="TestStandard.MissingInterface.InvalidImplementsWithoutImplement"/>
910
</rule>
1011

1112
</ruleset>

Diff for: tests/Core/Ruleset/ProcessRulesetTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ public function testAutoExpandSniffsDirectory()
6767
"$std.DeprecatedInvalid.InvalidDeprecationMessage" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationMessageSniff",
6868
"$std.DeprecatedInvalid.InvalidDeprecationVersion" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationVersionSniff",
6969
"$std.DeprecatedInvalid.InvalidRemovalVersion" => "$sniffDir\DeprecatedInvalid\InvalidRemovalVersionSniff",
70+
"$std.MissingInterface.ValidImplements" => "$sniffDir\MissingInterface\ValidImplementsSniff",
71+
"$std.MissingInterface.ValidImplementsViaAbstract" => "$sniffDir\MissingInterface\ValidImplementsViaAbstractSniff",
7072
"$std.SetProperty.AllowedAsDeclared" => "$sniffDir\SetProperty\AllowedAsDeclaredSniff",
7173
"$std.SetProperty.AllowedViaMagicMethod" => "$sniffDir\SetProperty\AllowedViaMagicMethodSniff",
7274
"$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="RegisterSniffsMissingInterfaceTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
5+
6+
<rule ref="TestStandard.MissingInterface"/>
7+
8+
</ruleset>
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
/**
3+
* Tests deprecation of support for sniffs not implementing the PHPCS `Sniff` interface.
4+
*
5+
* @author Juliette Reinders Folmer <[email protected]>
6+
* @copyright 2025 PHPCSStandards and contributors
7+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
11+
12+
use PHP_CodeSniffer\Ruleset;
13+
use PHP_CodeSniffer\Tests\ConfigDouble;
14+
use PHPUnit\Framework\TestCase;
15+
16+
/**
17+
* Tests deprecation of support for sniffs not implementing the PHPCS `Sniff` interface.
18+
*
19+
* @covers \PHP_CodeSniffer\Ruleset::registerSniffs
20+
*/
21+
final class RegisterSniffsMissingInterfaceTest extends TestCase
22+
{
23+
24+
25+
/**
26+
* Test that no deprecation is shown when sniffs implement the `PHP_CodeSniffer\Sniffs\Sniff` interface.
27+
*
28+
* @return void
29+
*/
30+
public function testNoNoticesForSniffsImplementingInterface()
31+
{
32+
// Set up the ruleset.
33+
$standard = __DIR__.'/RegisterSniffsMissingInterfaceValidTest.xml';
34+
$config = new ConfigDouble(["--standard=$standard"]);
35+
36+
$this->expectOutputString('');
37+
38+
new Ruleset($config);
39+
40+
}//end testNoNoticesForSniffsImplementingInterface()
41+
42+
43+
/**
44+
* Test that a deprecation notice is shown if a sniff doesn't implement the Sniff interface.
45+
*
46+
* @return void
47+
*/
48+
public function testDeprecationNoticeWhenSniffDoesntImplementInterface()
49+
{
50+
// Set up the ruleset.
51+
$standard = __DIR__.'/RegisterSniffsMissingInterfaceInvalidTest.xml';
52+
$config = new ConfigDouble(["--standard=$standard"]);
53+
54+
$expected = 'DEPRECATED: All sniffs must implement the PHP_CodeSniffer\\Sniffs\\Sniff interface.'.PHP_EOL;
55+
$expected .= 'Interface not implemented for sniff Fixtures\\TestStandard\\Sniffs\\MissingInterface\\InvalidImplementsWithoutImplementSniff.'.PHP_EOL;
56+
$expected .= 'Contact the sniff author to fix the sniff.'.PHP_EOL.PHP_EOL;
57+
58+
$this->expectOutputString($expected);
59+
60+
new Ruleset($config);
61+
62+
}//end testDeprecationNoticeWhenSniffDoesntImplementInterface()
63+
64+
65+
}//end class
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="RegisterSniffsMissingInterfaceTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
5+
6+
<rule ref="TestStandard.MissingInterface.ValidImplements"/>
7+
<rule ref="TestStandard.MissingInterface.ValidImplementsViaAbstract"/>
8+
9+
</ruleset>

Diff for: tests/Core/Ruleset/ShowSniffDeprecationsTest.xml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<exclude name="TestStandard.DeprecatedInvalid"/>
88
<exclude name="TestStandard.InvalidSniffs"/>
99
<exclude name="TestStandard.InvalidSniffError"/>
10+
<exclude name="TestStandard.MissingInterface"/>
1011
</rule>
1112

1213
</ruleset>

0 commit comments

Comments
 (0)