Skip to main content
The setup-php action has been tested with a wide range of PHP frameworks and packages. This page collects the official example workflows so you can copy a starting point that matches your stack. All examples follow the same pattern:
  • Check out your code with actions/checkout
  • Set up PHP with shivammathur/setup-php@v2
  • Cache Composer dependencies with actions/cache
  • Install dependencies and run your test suite
For the full set of workflow files, see the examples/ directory on GitHub.

Available examples

Framework / PackageRuns onWorkflow file
BlackfiremacOS, Ubuntu, Windowsblackfire.yml
Blackfire PlayermacOS, Ubuntublackfire-player.yml
CakePHP with MySQL and RedisUbuntucakephp-mysql.yml
CakePHP with PostgreSQL and RedisUbuntucakephp-postgres.yml
CakePHP without servicesmacOS, Ubuntu, Windowscakephp.yml
CodeIgnitermacOS, Ubuntu, Windowscodeigniter.yml
Drupal 11 (Composer-managed)Ubuntudrupal.yml
Laminas MVCmacOS, Ubuntu, Windowslaminas-mvc.yml
Laravel with MySQL and RedisUbuntularavel-mysql.yml
Laravel with PostgreSQL and RedisUbuntularavel-postgres.yml
Laravel without servicesmacOS, Ubuntu, Windowslaravel.yml
Lumen with MySQL and RedisUbuntulumen-mysql.yml
Lumen with PostgreSQL and RedisUbuntulumen-postgres.yml
Lumen without servicesmacOS, Ubuntu, Windowslumen.yml
Phalcon with MySQLUbuntuphalcon-mysql.yml
Phalcon with PostgreSQLUbuntuphalcon-postgres.yml
Slim FrameworkmacOS, Ubuntu, Windowsslim-framework.yml
Symfony with MySQLUbuntusymfony-mysql.yml
Symfony with PostgreSQLUbuntusymfony-postgres.yml
Symfony without servicesmacOS, Ubuntu, Windowssymfony.yml
WordPress pluginUbuntuwordpress.yml
WordPress with Roots/BedrockUbuntubedrock.yml
WordPress with Roots/SageUbuntusage.yml
Yii3 with MySQLUbuntuyii3-mysql.yml
Yii3 with PostgreSQLUbuntuyii3-postgres.yml
Yii3 web applicationUbuntu, Windowsyii3.yml

Workflow examples

The sections below show representative workflows you can use as a starting point. Each example includes Composer caching, which speeds up repeated runs by reusing previously downloaded packages.
Tests a Laravel application on Ubuntu, Windows, and macOS across multiple PHP versions. Uses Xdebug for coverage.
# GitHub Action for Laravel
name: Testing Laravel
on: [push, pull_request]
jobs:
  laravel:
    name: Laravel (PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }})
    runs-on: ${{ matrix.operating-system }}
    strategy:
      fail-fast: false
      matrix:
        operating-system: [ubuntu-latest, windows-latest, macos-latest]
        php-versions: ['8.3', '8.4', '8.5']
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      # Docs: https://github.com/shivammathur/setup-php
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php-versions }}
          extensions: mbstring, dom, fileinfo
          coverage: xdebug

      - name: Get composer cache directory
        id: composer-cache
        shell: bash
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache composer dependencies
        uses: actions/cache@v5
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install Composer dependencies
        run: composer install --no-progress --prefer-dist --optimize-autoloader

      - name: Prepare the application
        run: |
          php -r "file_exists('.env') || copy('.env.example', '.env');"
          php artisan key:generate

      - name: Clear Config
        run: php artisan config:clear

      - name: Test with phpunit
        run: vendor/bin/phpunit --coverage-text
Tests a Laravel application with MySQL and Redis service containers. The service ports are mapped dynamically and passed to the application via environment variables.
# GitHub Action for Laravel with MySQL and Redis
name: Testing Laravel with MySQL
on: [push, pull_request]
jobs:
  laravel:
    name: Laravel (PHP ${{ matrix.php-versions }})
    runs-on: ubuntu-latest
    env:
      DB_CONNECTION: mysql
      DB_HOST: 127.0.0.1
      DB_DATABASE: laravel
      DB_USERNAME: root
      DB_PASSWORD: password
      BROADCAST_CONNECTION: log
      CACHE_STORE: redis
      QUEUE_CONNECTION: redis
      SESSION_DRIVER: redis

    # Docs: https://docs.github.com/en/actions/using-containerized-services
    services:
      mysql:
        image: mysql:latest
        env:
          MYSQL_ALLOW_EMPTY_PASSWORD: false
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: laravel
        ports:
          - 3306/tcp
        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

      redis:
        image: redis
        ports:
          - 6379/tcp
        options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
    strategy:
      fail-fast: false
      matrix:
        php-versions: ['8.3', '8.4', '8.5']
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      # Docs: https://github.com/shivammathur/setup-php
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php-versions }}
          extensions: mbstring, dom, fileinfo, mysql
          coverage: xdebug

      - name: Get composer cache directory
        id: composer-cache
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache composer dependencies
        uses: actions/cache@v5
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install Composer dependencies
        run: composer install --no-progress --prefer-dist --optimize-autoloader

      - name: Prepare the application
        run: |
          php -r "file_exists('.env') || copy('.env.example', '.env');"
          php artisan key:generate

      - name: Clear Config
        run: php artisan config:clear

      - name: Run Migration
        run: php artisan migrate -v
        env:
          DB_PORT: ${{ job.services.mysql.ports['3306'] }}
          REDIS_PORT: ${{ job.services.redis.ports['6379'] }}

      - name: Test with phpunit
        run: vendor/bin/phpunit --coverage-text
        env:
          DB_PORT: ${{ job.services.mysql.ports['3306'] }}
          REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
Tests a Symfony application on all three operating systems. Installs the common Symfony extensions and runs PHPUnit with coverage.
# GitHub Action for Symfony
name: Testing Symfony
on: [push, pull_request]
jobs:
  symfony:
    name: Symfony (PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }})
    runs-on: ${{ matrix.operating-system }}
    strategy:
      fail-fast: false
      matrix:
        operating-system: [ubuntu-latest, windows-latest, macos-latest]
        php-versions: ['8.4', '8.5', '8.6']
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      # Docs: https://github.com/shivammathur/setup-php
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php-versions }}
          extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, zip
          coverage: xdebug

      - name: Get composer cache directory
        id: composer-cache
        shell: bash
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache composer dependencies
        uses: actions/cache@v5
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install Composer dependencies
        run: composer install --no-progress --prefer-dist --optimize-autoloader

      - name: Run tests
        run: ./bin/phpunit --coverage-text
Demonstrates a multi-job workflow for CakePHP: one job for tests using PCOV coverage, a second for PHP CodeSniffer, and a third for PHPStan static analysis.
# GitHub Action for CakePHP
# Tested with https://github.com/cakephp/app
name: Testing CakePHP
on: [push, pull_request]
jobs:
  tests:
    strategy:
      matrix:
        operating-system: [ubuntu-latest, windows-latest, macos-latest]
        php-versions: ['8.4', '8.5']
    runs-on: ${{ matrix.operating-system }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php-versions }}
          extensions: mbstring, intl, pdo_sqlite, pdo_mysql
          coverage: pcov

      - name: Get composer cache directory
        id: composer-cache
        shell: bash
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache composer dependencies
        uses: actions/cache@v5
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install dependencies
        run: |
          composer install --no-progress --prefer-dist --optimize-autoloader
          composer run-script post-install-cmd --no-interaction

      - name: Test with phpunit
        run: vendor/bin/phpunit --coverage-text

  coding-standard:
    name: Coding Standard
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.5'
          extensions: mbstring, intl

      - name: Install dependencies
        run: composer install --no-progress --prefer-dist --optimize-autoloader

      - name: PHP CodeSniffer
        run: composer cs-check

  static-analysis:
    name: Static Analysis
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.5'
          extensions: mbstring, intl
          tools: phpstan

      - name: Install dependencies
        run: |
          composer install --no-progress --prefer-dist --optimize-autoloader
          composer run-script post-install-cmd --no-interaction

      - name: Static Analysis using PHPStan
        run: phpstan analyse --no-progress src/
Tests a WordPress plugin using the official wp scaffold plugin-tests scaffolding. Requires a MySQL service container and the WordPress test environment install script.
# GitHub Action for WordPress plugins
# Tested with files scaffolded by wp scaffold plugin-tests --ci=github
# Requires phpunit/phpunit and yoast/phpunit-polyfills in require-dev for vendor/bin/phpunit
name: Testing WordPress
on: [push, pull_request]
jobs:
  wordpress:
    name: WordPress (PHP ${{ matrix.php-versions }})
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        php-versions: ['8.3', '8.4', '8.5']

    # Docs: https://docs.github.com/en/actions/using-containerized-services
    services:
      mysql:
        image: mysql:latest
        env:
          MYSQL_ALLOW_EMPTY_PASSWORD: false
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: wordpress_test
        ports:
          - 3306/tcp
        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php-versions }}
          extensions: mbstring, xml, zip, intl, mysql
          coverage: none

      - name: Get composer cache directory
        id: composer-cache
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache composer dependencies
        uses: actions/cache@v5
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install system dependencies
        run: sudo apt-get update && sudo apt-get install -y subversion default-mysql-client

      - name: Install Composer dependencies
        run: composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader

      - name: Install WordPress test environment
        run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:${{ job.services.mysql.ports['3306'] }} latest true

      - name: Test with phpunit
        run: vendor/bin/phpunit
The complete set of example workflows, including database variants (MySQL, PostgreSQL) and additional frameworks, is available in the examples/ directory of the setup-php repository.

Build docs developers (and LLMs) love