From be92b75d66333276ea3d57b7f4cb4d5332f73ca4 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 6 Feb 2026 15:17:54 +0100 Subject: [PATCH 1/3] Add stricter naming convention sniffs for CakePHP 6.x - Update ValidFunctionNameSniff to flag underscore-prefixed protected/private methods (except Entity accessor/mutator pattern _get*, _set*) - Add ValidPropertyNameSniff to flag underscore-prefixed properties - Remove PSR2.Classes.PropertyDeclaration.Underscore exclusion from ruleset - Add new Slevomat sniffs: - RequireNullCoalesceEqualOperator - RequireNullSafeObjectOperator - RequireSelfReference - NullTypeHintOnLastPosition - Fix $_magicMethods property naming in sniff itself - Add T_ENUM support to ValidFunctionNameSniff --- .../ValidFunctionNameSniff.php | 19 +++-- .../ValidPropertyNameSniff.php | 69 +++++++++++++++++++ .../ValidFunctionNameUnitTest.inc | 18 ++++- .../ValidFunctionNameUnitTest.php | 12 ++-- .../ValidPropertyNameUnitTest.inc | 39 +++++++++++ .../ValidPropertyNameUnitTest.php | 33 +++++++++ CakePHP/ruleset.xml | 9 ++- 7 files changed, 186 insertions(+), 13 deletions(-) create mode 100644 CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php create mode 100644 CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc create mode 100644 CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.php diff --git a/CakePHP/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/CakePHP/Sniffs/NamingConventions/ValidFunctionNameSniff.php index 65037bf7..a3ed2f68 100644 --- a/CakePHP/Sniffs/NamingConventions/ValidFunctionNameSniff.php +++ b/CakePHP/Sniffs/NamingConventions/ValidFunctionNameSniff.php @@ -27,9 +27,9 @@ class ValidFunctionNameSniff extends AbstractScopeSniff /** * A list of all PHP magic methods. * - * @var array + * @var array */ - protected array $_magicMethods = [ + protected array $magicMethods = [ 'construct', 'destruct', 'call', @@ -54,7 +54,7 @@ class ValidFunctionNameSniff extends AbstractScopeSniff */ public function __construct() { - parent::__construct([T_CLASS, T_INTERFACE, T_TRAIT], [T_FUNCTION], true); + parent::__construct([T_CLASS, T_INTERFACE, T_TRAIT, T_ENUM], [T_FUNCTION], true); } /** @@ -71,7 +71,7 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop $errorData = [$className . '::' . $methodName]; // Ignore magic methods - if (preg_match('/^__(' . implode('|', $this->_magicMethods) . ')$/', $methodName)) { + if (preg_match('/^__(' . implode('|', $this->magicMethods) . ')$/', $methodName)) { return; } @@ -89,6 +89,17 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop return; } + + // Check non-public methods for underscore prefix + if ($isPublic === false && $methodName[0] === '_') { + // Allow CakePHP Entity accessor/mutator pattern: _getField(), _setField() + if (preg_match('/^_(get|set)[A-Z]/', $methodName)) { + return; + } + + $error = 'Non-public method name "%s" should not be prefixed with underscore'; + $phpcsFile->addError($error, $stackPtr, 'ProtectedWithUnderscore', $errorData); + } } /** diff --git a/CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php b/CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php new file mode 100644 index 00000000..38207176 --- /dev/null +++ b/CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php @@ -0,0 +1,69 @@ +getTokens(); + $propName = ltrim($tokens[$stackPtr]['content'], '$'); + + // Only check properties starting with underscore + if ($propName[0] !== '_') { + return; + } + + $props = $phpcsFile->getMemberProperties($stackPtr); + + // Public properties with underscore are also bad, but less common + // Focus on protected/private which was the old convention + if ($props['scope'] !== 'public') { + $error = 'Non-public property "$%s" should not be prefixed with underscore'; + $phpcsFile->addError($error, $stackPtr, 'PropertyWithUnderscore', [$propName]); + } else { + $error = 'Public property "$%s" must not be prefixed with underscore'; + $phpcsFile->addError($error, $stackPtr, 'PublicPropertyWithUnderscore', [$propName]); + } + } + + /** + * @inheritDoc + */ + protected function processVariable(File $phpcsFile, $stackPtr) + { + // We only care about member variables (properties) + } + + /** + * @inheritDoc + */ + protected function processVariableInString(File $phpcsFile, $stackPtr) + { + // We only care about member variables (properties) + } +} diff --git a/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.inc b/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.inc index e4bc5652..837502cd 100644 --- a/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.inc +++ b/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.inc @@ -29,7 +29,7 @@ class FunctionNames protected function _someFunc() { - // code here + // code here - error: underscore prefix not allowed } protected function noUnderscorePrefix() @@ -40,6 +40,22 @@ class FunctionNames }; } + // Entity accessor/mutator patterns - should be allowed + protected function _getName() + { + return $this->name; + } + + protected function _setName($name) + { + $this->name = $name; + } + + protected function _getFullName() + { + return $this->first_name . ' ' . $this->last_name; + } + public function __call($name, $arguments) { } diff --git a/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php b/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php index 2816783a..ee750aee 100644 --- a/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php +++ b/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php @@ -9,19 +9,21 @@ class ValidFunctionNameUnitTest extends AbstractSniffTestCase /** * @inheritDoc */ - public function getErrorList() + public function getErrorList(): array { return [ - 6 => 1, - 87 => 1, - 96 => 1, + 6 => 1, // public function _forbidden + 30 => 1, // protected function _someFunc + 103 => 1, // public function _forbidden (interface) + 112 => 1, // public function _forbidden (trait) + 136 => 1, // protected function _someFunc (trait) ]; } /** * @inheritDoc */ - public function getWarningList() + public function getWarningList(): array { return []; } diff --git a/CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc b/CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc new file mode 100644 index 00000000..d612db27 --- /dev/null +++ b/CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc @@ -0,0 +1,39 @@ + 1, // public $_publicUnderscore + 13 => 1, // protected $_protectedUnderscore + 17 => 1, // private $_privateUnderscore + 21 => 1, // protected static $_protectedStatic + 23 => 1, // private static $_privateStatic + 30 => 1, // public $_publicUnderscore (trait) + 34 => 1, // protected $_protectedUnderscore (trait) + 38 => 1, // private $_privateUnderscore (trait) + ]; + } + + /** + * @inheritDoc + */ + public function getWarningList(): array + { + return []; + } +} diff --git a/CakePHP/ruleset.xml b/CakePHP/ruleset.xml index f41ec35f..13225b57 100644 --- a/CakePHP/ruleset.xml +++ b/CakePHP/ruleset.xml @@ -18,10 +18,9 @@ - @@ -256,6 +255,10 @@ + + + + From 5a998250eeff8e5fa857837eb1d1712a102ff499 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 6 Feb 2026 18:42:35 +0100 Subject: [PATCH 2/3] Remove custom ValidPropertyNameSniff, use PSR2 built-in instead --- .../ValidPropertyNameSniff.php | 69 ------------------- .../ValidPropertyNameUnitTest.inc | 39 ----------- .../ValidPropertyNameUnitTest.php | 33 --------- 3 files changed, 141 deletions(-) delete mode 100644 CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php delete mode 100644 CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc delete mode 100644 CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.php diff --git a/CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php b/CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php deleted file mode 100644 index 38207176..00000000 --- a/CakePHP/Sniffs/NamingConventions/ValidPropertyNameSniff.php +++ /dev/null @@ -1,69 +0,0 @@ -getTokens(); - $propName = ltrim($tokens[$stackPtr]['content'], '$'); - - // Only check properties starting with underscore - if ($propName[0] !== '_') { - return; - } - - $props = $phpcsFile->getMemberProperties($stackPtr); - - // Public properties with underscore are also bad, but less common - // Focus on protected/private which was the old convention - if ($props['scope'] !== 'public') { - $error = 'Non-public property "$%s" should not be prefixed with underscore'; - $phpcsFile->addError($error, $stackPtr, 'PropertyWithUnderscore', [$propName]); - } else { - $error = 'Public property "$%s" must not be prefixed with underscore'; - $phpcsFile->addError($error, $stackPtr, 'PublicPropertyWithUnderscore', [$propName]); - } - } - - /** - * @inheritDoc - */ - protected function processVariable(File $phpcsFile, $stackPtr) - { - // We only care about member variables (properties) - } - - /** - * @inheritDoc - */ - protected function processVariableInString(File $phpcsFile, $stackPtr) - { - // We only care about member variables (properties) - } -} diff --git a/CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc b/CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc deleted file mode 100644 index d612db27..00000000 --- a/CakePHP/Tests/NamingConventions/ValidPropertyNameUnitTest.inc +++ /dev/null @@ -1,39 +0,0 @@ - 1, // public $_publicUnderscore - 13 => 1, // protected $_protectedUnderscore - 17 => 1, // private $_privateUnderscore - 21 => 1, // protected static $_protectedStatic - 23 => 1, // private static $_privateStatic - 30 => 1, // public $_publicUnderscore (trait) - 34 => 1, // protected $_protectedUnderscore (trait) - 38 => 1, // private $_privateUnderscore (trait) - ]; - } - - /** - * @inheritDoc - */ - public function getWarningList(): array - { - return []; - } -} From 6446baa5d74760423186af67f375aaf089b07b29 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 6 Feb 2026 19:17:36 +0100 Subject: [PATCH 3/3] Fix coding standard - remove double spaces --- .../NamingConventions/ValidFunctionNameUnitTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php b/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php index ee750aee..9ac89c5c 100644 --- a/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php +++ b/CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php @@ -12,11 +12,11 @@ class ValidFunctionNameUnitTest extends AbstractSniffTestCase public function getErrorList(): array { return [ - 6 => 1, // public function _forbidden - 30 => 1, // protected function _someFunc - 103 => 1, // public function _forbidden (interface) - 112 => 1, // public function _forbidden (trait) - 136 => 1, // protected function _someFunc (trait) + 6 => 1, + 30 => 1, + 103 => 1, + 112 => 1, + 136 => 1, ]; }