Setting the scene
PHP 8.1 introduced enumerations (enums). Enums do not support inheritance: an enum cannot extend another enum or be extended, which means a protected member is functionally equivalent to private.
PER-CS 2.0 added a dedicated section on enumerations and codifies this: in an enum, a non-public method must be declared private, never protected.
Neither PHP_CodeSniffer itself nor PHPCSExtra contains a sniff to handle this.
Proposed new sniff: Universal.Enums.EnumProtectedMember
To address this rule from PER:
Non-public methods MUST use private instead of protected, as enums do not support inheritance.
Notes for the implementation
Registering [T_FUNCTION, T_CONST] is a good entry point. From each token, PHPCSUtils\Utils\Scopes::validDirectScope($phpcsFile, $stackPtr, \T_ENUM) confirms the member's direct wrapping scope is an enum. From there the sniff locates the T_PROTECTED token and flags it.
PER states this rule for methods only, but enum constants can also be declared protected, and the same reasoning applies: enums are implicitly final, so a protected constant is functionally identical to a private one.
The fix replaces the protected keyword with private.
Suggested error codes:
MethodFound
ConstantFound
Note: I opened an issue suggesting that the PER-CS rule be updated to cover constants as well: php-fig/per-coding-style#150. Using a separate error code means the error for constants can be excluded when implementing the PER-CS 2.0 standard.
Describe the solution you'd like
A new sniff as outlined above.
The sniff should be able to flag and auto-fix the following:
enum Suit: string
{
case Hearts = 'H';
// OK.
public function color(): string
{
return 'Red';
}
// OK.
private function helper(): string
{
return 'ok';
}
// Error: non-public method MUST use `private`, not `protected`. Auto-fixed to `private`.
protected function bad(): string
{
return 'nope';
}
// Error: `protected` constant in an enum. Auto-fixed to `private`.
protected const SECRET = 'x';
// Not flagged: method in an anonymous class nested inside an enum method is out of scope.
public function makeHelper(): object
{
return new class {
protected function stillFine(): string
{
return 'ok';
}
};
}
}
Also see the examples outlined in the PER documents (rules + migration guide).
Additional context (optional)
This ticket is the result of a detailed analysis of the rules as outlined in PER-CS 2.0, as well as a critical look at what's still missing rule-wise.
Setting the scene
PHP 8.1 introduced enumerations (enums). Enums do not support inheritance: an enum cannot extend another enum or be extended, which means a
protectedmember is functionally equivalent toprivate.PER-CS 2.0 added a dedicated section on enumerations and codifies this: in an enum, a non-public method must be declared
private, neverprotected.Neither PHP_CodeSniffer itself nor PHPCSExtra contains a sniff to handle this.
Proposed new sniff:
Universal.Enums.EnumProtectedMemberTo address this rule from PER:
Notes for the implementation
Registering
[T_FUNCTION, T_CONST]is a good entry point. From each token,PHPCSUtils\Utils\Scopes::validDirectScope($phpcsFile, $stackPtr, \T_ENUM)confirms the member's direct wrapping scope is an enum. From there the sniff locates theT_PROTECTEDtoken and flags it.PER states this rule for methods only, but enum constants can also be declared
protected, and the same reasoning applies: enums are implicitlyfinal, so aprotectedconstant is functionally identical to aprivateone.The fix replaces the
protectedkeyword withprivate.Suggested error codes:
MethodFoundConstantFoundNote: I opened an issue suggesting that the PER-CS rule be updated to cover constants as well: php-fig/per-coding-style#150. Using a separate error code means the error for constants can be excluded when implementing the PER-CS 2.0 standard.
Describe the solution you'd like
A new sniff as outlined above.
The sniff should be able to flag and auto-fix the following:
Also see the examples outlined in the PER documents (rules + migration guide).
Additional context (optional)
This ticket is the result of a detailed analysis of the rules as outlined in PER-CS 2.0, as well as a critical look at what's still missing rule-wise.