Een goed ingerichte CI/CD pipeline voor PHP projecten verandert de manier waarop je software oplevert. In plaats van handmatig files uploaden via FTP of SSH, push je een commit en rolt je code automatisch uit, mits alle tests groen zijn. Dat bespaart tijd, voorkomt fouten en geeft je team het vertrouwen om vaker te releasen.
In dit artikel ontdek je hoe CI/CD pipelines werken in een PHP-context, welke tools je gebruikt en hoe je stap voor stap een pipeline opzet die test, bouwt en deployt. Je krijgt praktische voorbeelden voor GitHub Actions en GitLab CI, plus tips om je pipeline betrouwbaar én snel te houden.
Wat is CI/CD precies?
CI/CD staat voor Continuous Integration en Continuous Delivery (of Deployment). Het zijn twee gerelateerde praktijken die samen één pipeline vormen.
Continuous Integration betekent dat elke code-wijziging automatisch wordt gebouwd en getest zodra iemand een commit pusht. Zo ontdek je direct of je verandering iets breekt in plaats van een week later.
Continuous Delivery gaat een stap verder: elke succesvolle build is klaar om uitgerold te worden naar staging of productie. Bij Continuous Deployment gebeurt die uitrol zelfs volledig automatisch.
Voor PHP-projecten betekent dit concreet: je pusht naar Git, de pipeline draait composer install, voert je PHPUnit-tests uit, checkt met PHPStan of je types kloppen, en deployt bij groen licht naar de server.
Waarom je een pipeline wilt voor PHP
Handmatig deployen werkt prima, tot het misgaat. Een vergeten composer install, een bestand dat niet mee geüpload is, of een migratie die niet gedraaid heeft. Met een pipeline automatiseer je precies deze foutgevoelige stappen.
Daarnaast dwingt een pipeline kwaliteit af. Als je tests verplicht moeten slagen voor een merge, schrijft iedereen in het team beter testbare code. En omdat je altijd weet dat main werkt, durf je vaker te releasen, soms meerdere keren per dag.
Voor teams die werken met domain-driven design of event-driven architectuur is een pipeline bijna onmisbaar. Complexe codebases hebben simpelweg te veel bewegende delen om handmatig betrouwbaar te deployen.
De fases van een PHP pipeline
Een typische pipeline bestaat uit opeenvolgende stages. Elke stage moet slagen voordat de volgende start.
1. Checkout en dependencies
De pipeline cloont je repository en installeert dependencies via Composer. Cache je vendor-directory tussen runs om minuten te besparen.
2. Static analysis
Voordat je ook maar één test draait, laat je tools als PHPStan, Psalm of PHP_CodeSniffer los op je code. Ze vangen type-fouten en stijlproblemen zonder dat de code daadwerkelijk hoeft te draaien.
3. Unit en integration tests
Nu draai je je PHPUnit-testsuite. Unit tests valideren losse componenten, integration tests kijken of modules samenwerken. Overweeg parallel draaien als je suite traag is.
4. Build artefact
Voor productie genereer je een geoptimaliseerd artefact: composer install --no-dev --optimize-autoloader, assets bundelen, caches vullen. Dit artefact wordt in de volgende stage uitgerold.
5. Deployment
De laatste stap: het artefact naar staging of productie sturen. Dit kan via SSH met Deployer, via een container registry, of via een platform als Laravel Forge of Envoyer.
GitHub Actions: een werkend voorbeeld
GitHub Actions is populair omdat het direct in je repository geïntegreerd is. Je definieert een workflow in .github/workflows/ci.yml:
name: CI
on:
push:
branches: [main, develop]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: testing
ports:
- 3306:3306
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, pdo_mysql, intl
coverage: xdebug
- name: Cache Composer
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run PHPStan
run: vendor/bin/phpstan analyse
- name: Run tests
run: vendor/bin/phpunit --coverage-text
Deze workflow draait bij elke push naar main of develop en bij elke pull request. Let op het gebruik van shivammathur/setup-php, een de facto standaard action die PHP en extensies installeert.
GitLab CI: hetzelfde, andere syntax
Gebruik je GitLab? Dan definieer je je pipeline in .gitlab-ci.yml:
image: php:8.3
stages:
- quality
- test
- deploy
cache:
paths:
- vendor/
before_script:
- apt-get update && apt-get install -y git unzip
- curl -sS https://getcomposer.org/installer | php
- php composer.phar install --no-interaction
phpstan:
stage: quality
script:
- vendor/bin/phpstan analyse
phpunit:
stage: test
script:
- vendor/bin/phpunit
deploy_production:
stage: deploy
script:
- vendor/bin/dep deploy production
only:
- main
when: manual
De when: manual op de deploy-job maakt hier een Continuous Delivery flow: code wordt wel getest, maar iemand moet de deploy-knop indrukken.
Deployment strategieën voor PHP
Hoe je code op je server krijgt is minstens zo belangrijk als hoe je hem test. Een paar veelgebruikte aanpakken:
Atomic deploys met Deployer
Deployer is een PHP-deployment-tool die elke release in een aparte directory plaatst en daarna een symlink omzet. Breekt de deploy? Dan rol je terug met één commando. De downtime is praktisch nul.
Container-based deploys
Bouw je pipeline een Docker-image, push die naar een registry en draai hem in Kubernetes of op een VPS. Deze aanpak is krachtig maar vereist meer DevOps-kennis. Voor apps met veel traffic of high-performance eisen is het vaak de moeite waard.
Platform-as-a-Service
Tools als Laravel Forge, Ploi of DeployHQ nemen veel werk uit handen. Je koppelt je Git-repository en zij handelen SSH, deploy-scripts en zero-downtime af. Perfect als je je wilt focussen op code in plaats van infrastructuur.
Database migraties in je pipeline
Een subtiel maar belangrijk punt: hoe ga je om met database-wijzigingen? Een veelgebruikte volgorde:
- Zet de nieuwe code klaar (nog niet actief)
- Draai migraties die backwards-compatible zijn
- Switch de symlink naar de nieuwe code
- Draai eventuele opruim-migraties
Vermijd migraties die bestaande kolommen droppen in dezelfde release als de code-wijziging. Splits ze op: eerst deploy je code die de kolom niet meer gebruikt, dan in een latere release drop je de kolom pas. Zo kun je altijd veilig terugrollen.
Lees meer over veilig werken met databases in onze gids over PDO.
Secrets en environment variables
Je pipeline heeft toegang nodig tot gevoelige data: database-wachtwoorden, API-keys, SSH-sleutels. Commit deze nooit in Git. Gebruik in plaats daarvan:
- GitHub Actions: Repository secrets onder Settings → Secrets
- GitLab CI: CI/CD Variables onder Settings → CI/CD
- Bitbucket: Repository variables
Markeer gevoelige variabelen altijd als "protected" en "masked", zodat ze niet in logs verschijnen.
Pipeline performance: snel is belangrijk
Een trage pipeline frustreert je team. Een paar concrete optimalisaties:
Cache je vendor-directory. composer install met cache duurt seconden in plaats van minuten.
Parallelliseer jobs. Draai PHPStan, PHPUnit en linting in aparte jobs die tegelijk starten.
Gebruik de juiste PHP-image. Een kale php:8.3-cli start sneller dan een volledige php:8.3-apache.
Split tests op. Grote PHPUnit-suites kun je splitsen over meerdere runners met tools als Paratest.
Run alleen wat nodig is. Met path filters kun je bepaalde jobs skippen als alleen de documentatie gewijzigd is.
Veelgemaakte fouten
Een paar valkuilen die je beter kunt vermijden:
- Geen rollback-strategie. Denk vooraf na over hoe je terugrolt als een deploy faalt.
- Tests die alleen lokaal slagen. Vaak door een net andere database-versie of ontbrekende extensie.
- Geheime keys in logs. Check of je niets gevoeligs met
echoofvar_dumpprint. - Geen notificaties. Koppel je pipeline aan Slack of e-mail zodat je direct weet wanneer iets faalt.
- Te weinig staging-tests. Deploy eerst naar staging, laat een smoke test draaien, en pas dan naar productie.
Veelgestelde vragen
Wat is een CI/CD pipeline voor PHP?
Een CI/CD pipeline is een geautomatiseerd proces dat je PHP-code test, bouwt en uitrolt zodra je een commit pusht. Het combineert Continuous Integration (automatisch testen) met Continuous Delivery of Deployment (automatisch uitrollen naar staging of productie).
Welke tools gebruik je voor CI/CD in PHP?
Populaire keuzes zijn GitHub Actions, GitLab CI/CD, Bitbucket Pipelines en Jenkins. Voor PHP-specifieke stappen gebruik je tools zoals Composer, PHPUnit, PHPStan en Deployer. Welke tool je kiest hangt af van waar je code staat en hoeveel controle je wilt over de runners.
Wat is het verschil tussen Continuous Delivery en Continuous Deployment?
Bij Continuous Delivery is elke build klaar om uitgerold te worden, maar zet iemand handmatig de knop om. Bij Continuous Deployment gaat elke succesvolle build automatisch naar productie, zonder menselijke tussenkomst. Beide varianten vereisen een sterke testsuite.
Moet ik Docker gebruiken in mijn PHP pipeline?
Docker is handig om je pipeline-omgeving identiek te maken aan productie, vooral bij complexe afhankelijkheden of specifieke PHP-extensies. Voor kleinere projecten volstaat een kant-en-klare PHP-image van de CI-provider vaak prima.
Hoe zorg ik voor zero-downtime deploys in PHP?
Gebruik een tool als Deployer of Envoyer die via symlinks switchen tussen releases. Combineer dit met opcache-reset, database-migraties in aparte stappen en health checks na de deploy om downtime te voorkomen.
Tot slot
Een CI/CD pipeline is geen luxe meer, maar een basisvoorwaarde voor professionele PHP-ontwikkeling. Begin klein: start met een pipeline die alleen je tests draait, voeg daarna static analysis toe, en bouw uiteindelijk richting automated deployments.
Gebruik je al Laravel of Symfony? Dan is de stap vaak kleiner dan je denkt, beide frameworks hebben uitstekende documentatie rondom CI/CD. Voor meer achtergrond over moderne deployment-praktijken is de GitHub Actions documentatie een prima startpunt.
Investeer een dag in je pipeline en je hebt er jaren plezier van.