PHP-QA-CI: A Comprehensive Quality Assurance Pipeline in a Single Dependency

In the PHP ecosystem, setting up a comprehensive quality assurance pipeline typically involves installing and configuring a dozen different tools, each with their own configuration files, command-line interfaces, and quirks. What if you could get a battle-tested, production-ready QA pipeline with a single Composer dependency?

The Problem with Traditional QA Setup

Setting up quality assurance tools for a PHP project traditionally involves a time-consuming process:

  • Installing multiple dev dependencies individually
  • Creating configuration files for each tool
  • Writing scripts to run tools in the correct order
  • Ensuring consistency across different projects
  • Maintaining and updating configurations as tools evolve
  • Training team members on different tool interfaces

This fragmented approach leads to inconsistency across projects, maintenance overhead, and often results in teams skipping important QA steps due to complexity.

Enter PHP-QA-CI

PHP-QA-CI is our first-party quality assurance and continuous integration pipeline that solves these problems elegantly. Built by Long Term Support LTD, it provides a complete QA pipeline through a single Composer dependency.

The key innovation is simple yet powerful: instead of manually orchestrating multiple tools, PHP-QA-CI provides:

  • Pre-configured, sensible defaults for all integrated tools
  • Logical execution order that fails fast on errors
  • Consistent interface across all projects
  • Easy customization when needed
  • Version-specific branches for different PHP versions

The Complete Tool Suite

Installing PHP-QA-CI gives you immediate access to a comprehensive suite of quality assurance tools, organized into four logical categories:

The tools are executed in a logical order, from fastest to slowest, to provide quick feedback:

1. Validation and Checks

  • PSR-4 Validation - Checks code namespaces for PSR-4 standard compliance (built-in script)
  • Composer Check for Issues - Runs composer diagnose and dumps autoloader
  • Strict Types Enforcing - Checks and can fix files without strict types defined

2. Linting

  • PHP Parallel Lint - Very fast PHP syntax error checking

3. Static Analysis

  • PHPStan - Performs static code analysis

4. Testing

  • PHPUnit - Runs unit tests
  • Infection - Mutation testing tool that deliberately mutates your code to test test quality

5. Documentation

  • Markdown Links Checker - Validates links in README.md and docs/*.md files (built-in script)

6. Final Checks

  • Uncommitted Changes Check - Verifies no pending code changes before further processing

7. Code Formatting

  • Beautifier and Fixer - Automatically reformats PHP code and applies coding standards
  • PHP Code Sniffer - Checks remaining coding standards issues

Installation and Basic Usage

Getting started with PHP-QA-CI requires just a single Composer command:

{
    "require-dev": {
        "lts/php-qa-ci": "dev-master@dev"
    },
    "config": {
        "bin-dir": "bin"
    }
}

Install the package (using the PHP 8.4 branch):

composer require --dev lts/php-qa-ci:dev-php8.4

That's it! You now have access to the complete QA pipeline:

#!/bin/bash
# Run the complete QA pipeline
./bin/qa

# Run with a specific PHP version
export PHP_QA_CI_PHP_EXECUTABLE=/usr/bin/php8.3
./bin/qa

# Run on a specific directory
./bin/qa /path/to/scan

# Run a single tool (example with PHPStan)
./bin/qa -t phpstan

The pipeline runs tools in a logical order designed to "fail as quickly as possible," saving time by catching basic issues before running more time-consuming analyses.

PHP Version Support

PHP-QA-CI maintains separate branches for different PHP versions, ensuring compatibility and leveraging version-specific features:

  • master - Stable release branch
  • php8.3 - PHP 8.3 specific configurations
  • php8.4 - PHP 8.4 support (current recommended branch as of 2025)

This branching strategy allows the tool to provide optimal configurations for each PHP version while maintaining backward compatibility where needed.

Configuration and Customization

While PHP-QA-CI works out of the box with sensible defaults, it's designed for easy customization. The tool looks for custom configurations in your project's qaConfig directory, falling back to defaults when custom configs aren't found.

Creating Custom Configurations

#!/bin/bash
# Create custom configuration directory
mkdir -p qaConfig

# Copy and customize PHPStan configuration
cp vendor/lts/php-qa-ci/configDefaults/generic/phpstan.neon qaConfig/
# Edit qaConfig/phpstan.neon as needed

# Copy and customize PHP CS Fixer configuration
cp vendor/lts/php-qa-ci/configDefaults/generic/php_cs.php qaConfig/
# Edit qaConfig/php_cs.php as needed

# The QA pipeline will automatically use your custom configs

PHPStan Custom Configuration Example

Here's how to extend the default PHPStan configuration for your project:

includes:
    - vendor/lts/php-qa-ci/configDefaults/generic/phpstan.neon

parameters:
    level: 9
    paths:
        - src
        - tests
    excludePaths:
        - tests/fixtures
    ignoreErrors:
        - '#Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\NodeDefinition::children\(\)#'
    reportUnmatchedIgnoredErrors: false
    checkMissingIterableValueType: false

PHP CS Fixer Custom Configuration

Customize coding standards while maintaining the base configuration:

<?php

declare(strict_types=1);

// Include the default configuration
$config = require __DIR__ . '/../vendor/lts/php-qa-ci/configDefaults/generic/php_cs.php';

// Get the default finder
$finder = require __DIR__ . '/../vendor/lts/php-qa-ci/configDefaults/generic/php_cs_finder.php';

// Customize the finder if needed
$finder
    ->exclude('legacy')
    ->notPath('src/Migrations/Version*.php');

// Add or override rules
$rules = $config->getRules();
$rules['php_unit_test_class_requires_covers'] = false;
$rules['php_unit_internal_class'] = false;

return $config
    ->setFinder($finder)
    ->setRules($rules);

Symfony Project Integration

PHP-QA-CI includes special considerations for Symfony projects. When installing in a Symfony project, you have two options:

#!/bin/bash
# For Symfony projects: choose between Symfony defaults or php-qa-ci defaults

# Option 1: Use php-qa-ci defaults (more extensive)
rm phpunit.xml.dist
ln -s vendor/lts/php-qa-ci/configDefaults/generic/phpunit.xml

# Option 2: Keep Symfony defaults
# Simply accept the recipe prompts during installation

# Create project-specific overrides
mkdir -p qaConfig
echo "parameters:
    level: 8
    paths:
        - src
    excludePaths:
        - var
        - vendor" > qaConfig/phpstan.neon

The PHP-QA-CI defaults are generally more extensive than Symfony's defaults, including additional static analysis rules and stricter coding standards.

Advanced Features

Hooks System

PHP-QA-CI supports pre and post execution hooks, allowing you to integrate custom logic into the pipeline:

#!/bin/bash
# Create custom hooks for the QA pipeline
mkdir -p qaConfig

# Pre-hook: Run before QA pipeline starts
cat > qaConfig/preBashHook.bash << 'EOF'
#!/bin/bash
echo "Starting QA pipeline for project: $(basename $(pwd))"
echo "PHP Version: $($PHP_QA_CI_PHP_EXECUTABLE --version | head -n1)"

# Clear any caches that might affect results
if [ -d "var/cache" ]; then
    rm -rf var/cache/*
fi
EOF

# Post-hook: Run after QA pipeline completes
cat > qaConfig/postBashHook.bash << 'EOF'
#!/bin/bash
echo "QA Pipeline completed!"

# Generate a summary report
if [ -f "infection.log" ]; then
    echo "Mutation Score: $(grep -oP 'Mutation Score Indicator \(MSI\): \K[0-9.]+' infection.log)%"
fi

# Send notification (example)
# curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
#   -H 'Content-type: application/json' \
#   --data '{"text":"QA Pipeline completed successfully!"}'
EOF

chmod +x qaConfig/*.bash

Mutation Testing with Infection

One of the most powerful features is the integrated mutation testing via Infection. This helps assess the quality of your test suite by introducing small changes (mutations) to your code and checking if tests catch them:

{
    "source": {
        "directories": [
            "src"
        ]
    },
    "logs": {
        "text": "infection.log",
        "summary": "summary.log",
        "debug": "debug.log",
        "perMutator": "per-mutator.md"
    },
    "mutators": {
        "@default": true,
        "global-ignoreSourceCodeByRegex": [
            "Assert::.*"
        ]
    },
    "testFramework": "phpunit",
    "testFrameworkOptions": "--configuration=phpunit.xml"
}

Performance Optimization

The pipeline is optimized for performance through several strategies:

  • Fail-fast approach: Basic checks run first
  • Parallel execution where possible
  • Intelligent caching of results
  • Option to run quick tests only during development

CI/CD Integration

PHP-QA-CI is designed to work seamlessly in continuous integration environments. Here's an example GitHub Actions workflow:

name: Quality Assurance

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  qa:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php-version: ['8.1', '8.2', '8.3']
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: ${{ matrix.php-version }}
        coverage: xdebug
    
    - name: Install dependencies
      run: composer install --prefer-dist --no-progress
    
    - name: Run QA Pipeline
      run: ./bin/qa
      env:
        PHP_QA_CI_PHP_EXECUTABLE: /usr/bin/php${{ matrix.php-version }}

The pipeline works equally well with other CI systems like GitLab CI, Jenkins, or Bitbucket Pipelines. The consistent interface means your local development experience matches your CI environment exactly.

Real-World Benefits

Consistency Across Projects

With PHP-QA-CI, all your projects use the same QA pipeline, making it easy for developers to move between projects without learning new tools or configurations.

Time Savings

Setting up a comprehensive QA pipeline manually can take hours or days. With PHP-QA-CI, you're up and running in minutes with a battle-tested configuration.

Maintenance Reduction

Instead of maintaining configurations for a dozen tools across multiple projects, you maintain a single dependency. Updates to tool configurations are handled centrally.

Best Practices by Default

The default configurations encode years of PHP development best practices, ensuring your code meets high quality standards without extensive research.

Comparison with Manual Setup

Consider what manual setup of these tools would require:

Aspect Manual Setup PHP-QA-CI
Initial Setup Time 2-4 hours 5 minutes
Configuration Files 10-15 files 0 (uses defaults)
Composer Dependencies 12+ packages 1 package
Execution Scripts Custom required Single qa command
Cross-project Consistency Manual synchronization Automatic
Tool Updates Individual updates Single update

Troubleshooting Common Issues

Permission Issues

If you encounter permission issues with the qa script:

chmod +x vendor/lts/php-qa-ci/bin/qa
# Or use composer's bin directory
chmod +x bin/qa

Memory Limits

Some tools like PHPStan may require increased memory limits:

export PHP_QA_CI_PHP_EXECUTABLE="php -d memory_limit=512M"
./bin/qa

Tool-Specific Issues

Individual tools can be run in isolation for debugging:

# Run only PHPStan
./bin/qa phpstan

# Run with verbose output
./bin/qa --verbose

Future Development

PHP-QA-CI continues to evolve with the PHP ecosystem. Current development focuses on:

  • Support for newer PHP versions as they're released
  • Integration of emerging QA tools
  • Performance optimizations for large codebases
  • Enhanced reporting and metrics
  • Better IDE integration support

Conclusion

PHP-QA-CI represents a paradigm shift in PHP quality assurance setup. By providing a complete, pre-configured pipeline through a single dependency, it removes the barriers to implementing comprehensive quality checks in PHP projects.

Whether you're starting a new project or looking to improve quality assurance in an existing codebase, PHP-QA-CI offers immediate value with minimal setup effort. The combination of sensible defaults, easy customization, and comprehensive tool coverage makes it an essential addition to any serious PHP development workflow.

The tool embodies the philosophy of the PHP language itself: pragmatic, powerful, and focused on developer productivity. By abstracting away the complexity of QA pipeline configuration, PHP-QA-CI lets developers focus on what matters most - writing quality code.

Get Started Today

Ready to streamline your PHP quality assurance workflow? Visit the PHP-QA-CI GitHub repository or install it directly via Composer:

composer require --dev lts/php-qa-ci:dev-master@dev