Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NamingConventions/ValidFunctionName: implement PHPCSUtils and support modern PHP #2191

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions WordPress/Sniffs/NamingConventions/ValidFunctionNameSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use PHPCSUtils\BackCompat\BCTokens;
use PHPCSUtils\Utils\FunctionDeclarations;
use PHPCSUtils\Utils\NamingConventions;
use PHPCSUtils\Utils\ObjectDeclarations;
use PHPCSUtils\Utils\Scopes;
use WordPressCS\WordPress\Helpers\DeprecationHelper;
Expand Down Expand Up @@ -127,7 +128,7 @@ protected function process_function_declaration( $stackPtr, $functionName ) {
*
* @since 0.1.0
* @since 3.0.0 Renamed from `processTokenWithinScope()` to `process_method_declaration()`.
* Method signature has been changed as well as this method no longer overloads
* Method signature has been changed as well, as this method no longer overloads
* a method from the PEAR sniff which was previously the sniff parent.
*
* @param int $stackPtr The position where this token was found.
Expand All @@ -142,19 +143,16 @@ protected function process_method_declaration( $stackPtr, $methodName, $currScop
$className = '[Anonymous Class]';
} else {
$className = ObjectDeclarations::getName( $this->phpcsFile, $currScope );
}

$methodNameLc = strtolower( $methodName );
$classNameLc = strtolower( $className );
// PHP4 constructors are allowed to break our rules.
if ( NamingConventions::isEqual( $methodName, $className ) === true ) {
return;
}

// PHP4 constructors are allowed to break our rules.
if ( $methodNameLc === $classNameLc ) {
return;
}

// PHP4 destructors are allowed to break our rules.
if ( '_' . $classNameLc === $methodNameLc ) {
return;
// PHP4 destructors are allowed to break our rules.
if ( NamingConventions::isEqual( $methodName, '_' . $className ) === true ) {
return;
}
Comment on lines +152 to +155
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought destructors didn't exist until PHP 5?

I've not seen them suggested with a leading underscore in PHP 4 as:

class Foo {
	function Foo() {} // Constructor.
	function _Foo() {} // Destructor.
}

Was that the de facto approach back then? How did they get triggered?

Copy link
Member Author

@jrfnl jrfnl Jan 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good questions. To be honest, it's so far back, that this should be redundant and I hope to never come across that type of code again.

For the purposes of this PR, I've just kept the existing functionality, which already handled things in this way (whether correct or not).
Also note that the PHPCS native PEAR.NamingConventions.ValidFunctionName sniff, which this sniff was originally based on, treats _ClassName() methods the same, i.e. as PHP 4-destructors.

I realize this is not an answer to your question, but there's only so much time (research) I'm willing to spend on work arounds for code which shouldn't exist anymore in the first place.

}

// PHP magic methods are exempt from our rules.
Expand All @@ -178,7 +176,7 @@ protected function process_method_declaration( $stackPtr, $methodName, $currScop
}

// Check for all lowercase.
if ( $methodNameLc !== $methodName ) {
if ( strtolower( $methodName ) !== $methodName ) {
$error = 'Method name "%s" in class %s is not in snake case format, try "%s"';
$errorData = array(
$methodName,
Expand All @@ -188,5 +186,4 @@ protected function process_method_declaration( $stackPtr, $methodName, $currScop
$this->phpcsFile->addError( $error, $stackPtr, 'MethodNameInvalid', $errorData );
}
}

}
37 changes: 37 additions & 0 deletions WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,40 @@ class UnderScoreHandling {
public function Multiple_______Underscores() {} // Bad, replacement suggestion should be: multiple_______underscores.
public function Trailing_Underscores___() {}// Bad, replacement suggestion should be: trailing_underscores___.
}

// Safeguard that functions with a name only consisting of underscores are always ignored.
function __() {}

class OnlyUnderscores {
public function _____() {}
}

// Class vs function name PHP case-sensitivity quirks.
class FooBÃÈ {
function FooBÃÈ() {} // OK, same case.
function fOOBÃÈ() {} // OK, same case for the non-ascii chars.
function FooBãè() {} // Bad - not PHP 4-type constructor, non ascii chars not in same case - POC: https://3v4l.org/YOc2R.
}

// Safeguard that methods in enums are correctly handled by the sniff.
enum Suit {
case Hearts;
case Diamonds;

public function color(): string {} // OK.
public function __changeColor(): string {} // Bad

public function &getShape(): string // Bad.
{
return "Rectangle";
}

// These are the only three magic methods allowed in enums.
public function __call( $a, $b ) {} // Ok.
public static function __callStatic( $a, $b ) {} // Ok.
public function __invoke() {} // Ok.
}

// Live coding/parse error.
// This has to be the last test in the file.
function
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public function getErrorList() {
183 => 1,
184 => 1,
185 => 1,
199 => 1,
208 => 2,
210 => 1,
);
}

Expand All @@ -61,5 +64,4 @@ public function getErrorList() {
public function getWarningList() {
return array();
}

}