Skip to content
Draft
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
19 changes: 15 additions & 4 deletions CakePHP/Sniffs/NamingConventions/ValidFunctionNameSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ class ValidFunctionNameSniff extends AbstractScopeSniff
/**
* A list of all PHP magic methods.
*
* @var array
* @var array<string>
*/
protected array $_magicMethods = [
protected array $magicMethods = [
'construct',
'destruct',
'call',
Expand All @@ -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);
}

/**
Expand All @@ -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;
}

Expand All @@ -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);
}
}

/**
Expand Down
18 changes: 17 additions & 1 deletion CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class FunctionNames

protected function _someFunc()
{
// code here
// code here - error: underscore prefix not allowed
}

protected function noUnderscorePrefix()
Expand All @@ -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)
{
}
Expand Down
10 changes: 6 additions & 4 deletions CakePHP/Tests/NamingConventions/ValidFunctionNameUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@ class ValidFunctionNameUnitTest extends AbstractSniffTestCase
/**
* @inheritDoc
*/
public function getErrorList()
public function getErrorList(): array
{
return [
6 => 1,
87 => 1,
96 => 1,
30 => 1,
103 => 1,
112 => 1,
136 => 1,
];
}

/**
* @inheritDoc
*/
public function getWarningList()
public function getWarningList(): array
{
return [];
}
Expand Down
9 changes: 6 additions & 3 deletions CakePHP/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
<exclude name="PSR12.Files.FileHeader.SpacingAfterUseBlock"/>
<exclude name="PSR12.Files.FileHeader.SpacingAfterUseFunctionBlock"/>
<!--
Property and method names with underscore prefix are allowed in CakePHP.
Not using underscore prefix is a recommendation of PSR2, not a requirement.
We use our own CakePHP.NamingConventions.ValidFunctionName sniff which allows
Entity accessor/mutator pattern (_getField, _setField) while enforcing PSR naming elsewhere.
-->
<exclude name="PSR2.Classes.PropertyDeclaration.Underscore"/>
<exclude name="PSR2.Methods.MethodDeclaration.Underscore"/>
</rule>

Expand Down Expand Up @@ -256,6 +255,10 @@
<rule ref="SlevomatCodingStandard.Attributes.RequireAttributeAfterDocComment"/>
<rule ref="SlevomatCodingStandard.Classes.BackedEnumTypeSpacing"/>
<rule ref="SlevomatCodingStandard.ControlStructures.RequireShortTernaryOperator"/>
<rule ref="SlevomatCodingStandard.ControlStructures.RequireNullCoalesceEqualOperator"/>
<rule ref="SlevomatCodingStandard.ControlStructures.RequireNullSafeObjectOperator"/>
<rule ref="SlevomatCodingStandard.Classes.RequireSelfReference"/>
<rule ref="SlevomatCodingStandard.TypeHints.NullTypeHintOnLastPosition"/>

<!-- phpcs Zend sniffs -->
<rule ref="Zend.NamingConventions.ValidVariableName">
Expand Down