PHP PER: The Evolution Beyond PSR-12 Coding Standards

PHP Evolving Recommendations (PER) represent a fundamental shift in how the PHP community approaches standards. Unlike the static PSRs, PERs are designed to evolve with the language, ensuring standards stay relevant as PHP continues its rapid modernization.

What is PHP PER?

A PHP Evolving Recommendation is a "meta document accompanied by one or more artifacts that are set to evolve over time with multiple releases." This evolutionary approach addresses a critical limitation of the PSR system: once accepted, PSRs are essentially frozen in time.

Currently, there's only one active PER: the PER Coding Style 3.0, which extends, expands, and ultimately replaces PSR-12. But the implications go far beyond just coding style.

The Problem with Static Standards

When PSR-12 was accepted in 2019, PHP 7.3 was the latest version. Since then, we've seen:

PSR-12 couldn't provide guidance for these features because they didn't exist. Enter PER: a living standard that can adapt as PHP evolves.

PER vs PSR: The Key Differences

Aspect PSR (PHP Standard Recommendation) PER (PHP Evolving Recommendation)
Mutability Immutable once accepted Designed to evolve with multiple releases
Update Process Requires new PSR to supersede old one Can be updated through defined workflow
Scope Fixed at time of acceptance Expands to cover new language features
Leadership Working group disbanded after acceptance Maintains active Editor and Sponsor
Community Input Limited to initial draft period Ongoing through evolution process

What's New in PER Coding Style 3.0?

1. Modern Type Declarations

PER addresses the explosion of type system features in modern PHP:

// Union types (PHP 8.0+)
public function process(int|string $value): void {}

// Intersection types (PHP 8.1+)
public function handle(Countable&Traversable $items): void {}

// Complex compound types with proper formatting
function complex(
    array
    |(ArrayAccess&Traversable)
    |(Traversable&Countable) $input
): ArrayAccess&Traversable {
    // Implementation
}

2. Attributes (Annotations)

PHP 8 Attributes get comprehensive formatting rules:

// Single attribute
#[Route('/api/users')]
class UserController {}

// Multiple attributes
#[
    Route('/api/users'),
    Middleware('auth'),
    Cache(ttl: 3600)
]
class UserController {}

// Inline for simple cases
class User {
    #[Required] #[Email] 
    public string $email;
}

3. Enumerations

Clear guidelines for PHP 8.1 enums:

enum Status: string
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
    
    public function isActive(): bool
    {
        return $this === self::Published;
    }
}

4. Property Hooks (PHP 8.4+)

Forward-looking support for upcoming features:

class User
{
    public string $name {
        get => $this->firstName . ' ' . $this->lastName;
        set => [$this->firstName, $this->lastName] = explode(' ', $value, 2);
    }
}

5. Trailing Commas

Mandatory trailing commas in multi-line contexts:

// Required in multi-line arrays
$config = [
    'host' => 'localhost',
    'port' => 3306,
    'database' => 'app', // ← Required trailing comma
];

// Required in multi-line function calls
$result = processSomething(
    $firstArgument,
    $secondArgument,
    $thirdArgument, // ← Required trailing comma
);

Enforcing PER with QA Tools

PHP-CS-Fixer: The Gold Standard

PHP-CS-Fixer already includes PER support. The Symfony ruleset incorporates PER Coding Style by default:

// .php-cs-fixer.php
<?php

$finder = PhpCsFixerFinder::create()
    ->in(__DIR__)
    ->exclude('vendor');

return (new PhpCsFixerConfig())
    ->setRules([
        '@Symfony' => true,  // Includes @PER-CS2.0
        '@PER-CS' => true,   // Explicit PER compliance
        'declare_strict_types' => true,
        'void_return' => true,
    ])
    ->setFinder($finder)
    ->setRiskyAllowed(true);

Run with:

vendor/bin/php-cs-fixer fix --dry-run --diff  # Check changes
vendor/bin/php-cs-fixer fix                     # Apply fixes

PHPStan Integration

While PHPStan focuses on static analysis, you can enforce some PER conventions:

# phpstan.neon
parameters:
    level: 9
    strictRules:
        strictCalls: true
        strictProperties: true
    
    # Enforce modern PHP features
    phpVersion: 80300  # Minimum PHP 8.3
    
includes:
    - vendor/phpstan/phpstan-strict-rules/rules.neon

Composer Scripts

Integrate into your workflow:

{
    "scripts": {
        "check-style": "php-cs-fixer fix --dry-run --diff",
        "fix-style": "php-cs-fixer fix",
        "analyse": "phpstan analyse",
        "qa": [
            "@check-style",
            "@analyse"
        ]
    }
}

CI/CD Integration

GitHub Actions example:

name: Code Quality

on: [push, pull_request]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
          tools: php-cs-fixer, phpstan
      
      - name: Check PER Compliance
        run: php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.php
      
      - name: Static Analysis
        run: phpstan analyse

A Brief History of PHP Standards

The PSR Era (2009-Present)

  • 2009: PHP-FIG formed
  • 2010: PSR-0 (Autoloading) - The first PSR
  • 2012: PSR-1 & PSR-2 (Basic & Coding Style)
  • 2013: PSR-4 (Improved Autoloading)
  • 2019: PSR-12 (Extended Coding Style)

The Problem Emerges

As PHP accelerated its release cycle with annual major versions, the static nature of PSRs became problematic. PSR-12 couldn't be updated for new syntax, leading to:

  • Fragmented community standards
  • Tool-specific interpretations
  • Inconsistent codebases

Enter PER (2022-2023)

PHP-FIG introduced the PER Workflow Bylaw, creating a new category of living standards. PER Coding Style 2.0 was released in April 2023, followed by 3.0 in July 2023. Key innovations:

  • Active Maintainership: Each PER has an Editor and Sponsor
  • Version Control: PERs use semantic versioning
  • Community Evolution: Regular updates based on language changes

The Future of PHP Standards

Expected PER Evolution

As PHP continues to evolve, PER Coding Style will likely address:

Potential New PERs

The community is discussing PERs for:

  • Documentation Standards: Evolving PHPDoc alternatives
  • Testing Conventions: Modern PHPUnit/Pest practices
  • API Design: RESTful and GraphQL standards
  • Security Practices: Evolving security recommendations

Tool Ecosystem Alignment

Major tools are aligning with PER:

Practical Migration Guide

From PSR-12 to PER

Migrating is straightforward with proper tooling:

# 1. Install/update PHP-CS-Fixer
composer require --dev friendsofphp/php-cs-fixer

# 2. Create configuration
cat > .php-cs-fixer.php << 'EOF'
<?php
return (new PhpCsFixer\Config())
    ->setRules([
        '@PER-CS' => true,
        // Your additional rules
    ])
    ->setFinder(
        PhpCsFixer\Finder::create()
            ->in(__DIR__)
            ->exclude('vendor')
    );
EOF

# 3. Check what will change
vendor/bin/php-cs-fixer fix --dry-run --diff

# 4. Apply changes
vendor/bin/php-cs-fixer fix

# 5. Commit
git add .
git commit -m "Migrate from PSR-12 to PER Coding Style"

Common Migration Issues

  • Trailing commas: Now required in multi-line contexts
  • Type declarations: May need reformatting
  • Attributes: New formatting rules apply

Conclusion

PHP Evolving Recommendations represent a maturation of the PHP community's approach to standards. By acknowledging that languages evolve and standards must evolve with them, PER provides a sustainable path forward.

For teams already using PHP-CS-Fixer with Symfony rules, you're likely already PER-compliant. For others, the migration is painless with modern tooling.

The key insight: PER isn't just about coding style—it's about creating living standards that grow with PHP. As PHP continues its renaissance with performance improvements, type safety, and modern features, PER ensures our standards keep pace. With PHP 8.5 on the horizon and new features constantly being added, PER's evolutionary approach is more important than ever.

Resources