Skip to content

[FR] Enum cases: sniff to enforce PascalCase capitalization #444

Description

@rodrigoprimo

Setting the scene

PHP 8.1 introduced enumerations.

Since version 2.0, the PER Coding Standard defines a rule for enum case capitalization.

Neither PHPCS itself nor PHPCSExtra contains a sniff to verify the capitalization of enum case names.

Proposed new sniff: Universal.NamingConventions.EnumCaseName

To address this rule from PER:

Enum case declarations MUST use PascalCase capitalization.

So case Hearts; and case DiamondsRed; are fine, while case HEARTS;, case hearts; and case diamonds_red; are violations.

Notes for the implementation

The case keyword inside an enum is tokenized as a dedicated T_ENUM_CASE token, so registering [T_ENUM_CASE] is a good entry point. The case name is the following T_STRING.

For the PascalCase check, the sniff can use Common::isCamelCaps($name, true, true, true). The final true enables strict mode, which forbids two consecutive uppercase letters (so JsonValue is valid but JSONValue is not). I'm assuming this matches PER's definition, but I'm not certain. This relies on the PascalCase definition in section 2.1:

The term "StudlyCaps" in PSR-1 MUST be interpreted as PascalCase where the first letter of each word is capitalized including the very first letter.

The sniff would enforce PascalCase only, which is what PER requires. If support for other conventions is wanted later, a $case property defaulting to PascalCase could be added.

This sniff should not be auto-fixable. Renaming a case is a breaking change, and the sniff cannot know if the offending name is used elsewhere in the codebase.

Suggested error code:

  • Invalid

Describe the solution you'd like

A new sniff as outlined above.

The sniff should be able to flag the following:

enum Suit
{
    // OK.
    case Hearts;
    case DiamondsRed;
    case Type3D;

    // Error: consecutive uppercase letters.
    case JSONValue;

    // Error: all uppercase.
    case HEARTS;

    // Error: lowercase first character (and camelCase in general).
    case hearts;
    case diamondsRed;

    // Error: snake_case / contains underscores.
    case diamonds_red;
    case DIAMONDS_RED;

    // Error: leading underscore.
    case _Hidden;
}

// Backed enums are treated the same.
enum Rank: string
{
    // OK.
    case Hearts = 'H';

    // Error: snake_case name.
    case diamonds_red = 'D';
}

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.

  • I intend to create a pull request to implement this feature.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions