PHP 8: Modern PHP Development · Performance and Deployment
Docker for PHP Applications
Build lean, secure production images with multi-stage Dockerfiles.
Use the official php:8.4-fpm (or -cli) images, install only the extensions you need with docker-php-ext-install, install Composer dependencies in a build stage, and copy the optimized vendor/ into a slim runtime image. Run as a non-root user, use the production php.ini, enable OPcache, and pair the FPM container with Nginx (or use FrankenPHP/RoadRunner as an all-in-one application server).
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist --optimize-autoloader
FROM php:8.4-fpm-alpine
RUN docker-php-ext-install pdo_pgsql opcache \
&& mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/opcache.ini $PHP_INI_DIR/conf.d/opcache.ini
WORKDIR /var/www/app
COPY --from=vendor /app/vendor ./vendor
COPY . .
RUN chown -R www-data:www-data storage
USER www-data
Common pitfalls
- Shipping dev dependencies and Composer in the runtime image.
- Running as root.
- Rebuilding vendor on every code change because COPY order breaks layer caching.
Key points
- Multi-stage: Composer stage → slim runtime
- Production php.ini + OPcache
- Non-root user
Further reading: Official PHP Docker images
Practice questions
Why copy composer.json/lock before the rest of the source?
Answer
Docker caches layers; dependencies are reinstalled only when those files change, not on every code edit, speeding up builds.
What are FrankenPHP and RoadRunner?
Answer
Application servers that can keep PHP workers alive between requests (worker mode), serving HTTP directly. They reduce bootstrap overhead but require care with state leaking between requests.
Open in the app to mark lessons complete, take notes and track your progress.