Skip to main content

🛠️ PHP Development Environment

A language is only as useful as the workshop you run it in. In this lesson you'll assemble a complete, professional PHP setup — a server to run your code, a database to store data, an editor that understands PHP, and a real debugger — and learn the three main paths to get there so you can pick the one that fits you.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Describe the components of a PHP stack and how a request flows through them
  • Choose between all-in-one packages, manual installation, and Docker for your setup
  • Locate and tune php.ini for a development-friendly configuration
  • Configure VS Code with the right extensions for PHP
  • Set up step-through debugging with Xdebug and diagnose common problems

Estimated Time: 35–45 minutes  •  Difficulty: Beginner

Hands-on: Stand up a working environment and confirm it with a phpinfo() page.

In This Lesson

The PHP Development Stack

To serve a dynamic PHP page, a few programs cooperate. A browser sends an HTTP request to a web server, which hands PHP files to the PHP interpreter; the interpreter often reads and writes a database, then returns HTML that the web server sends back.

flowchart LR B[Browser] -->|HTTP request| W[Web Server
Apache / Nginx] W -->|hands off .php| P[PHP Interpreter] P -->|SQL| D[(Database
MySQL / MariaDB)] D -->|rows| P P -->|HTML| W W -->|HTTP response| B

📖 The pieces you'll install

Web server: Apache or Nginx in production; PHP's own built-in server for local dev.

PHP interpreter: version 8.3 or 8.4 — the current supported line.

Database: MySQL or its drop-in fork MariaDB is the classic pairing; SQLite needs no server at all.

Tools: Composer (dependencies), Git (version control), and an editor.

Two ways PHP connects to a web server

In production, PHP usually runs as PHP-FPM (FastCGI Process Manager) behind Nginx, or as an Apache module. For local development you can skip all of that — PHP ships a built-in server that needs zero configuration.

Three Ways to Set Up

There's no single "right" way to install PHP. Pick the approach that matches your goals and comfort level.

ApproachBest forTrade-off
All-in-one package
(XAMPP, Laragon, MAMP)
Beginners who want one installer that bundles Apache + MySQL + PHPLess insight into how the pieces fit; can drift from production
Manual install
(package manager / Homebrew)
Understanding each component; matching a specific serverMore steps; you wire the pieces together yourself
Docker
(containers)
Reproducible, "same everywhere" environments; teamsA learning curve if you're new to containers

All-in-one packages at a glance

PackagePlatformsNotable for
XAMPPWindows, macOS, LinuxThe classic cross-platform bundle
LaragonWindowsFast, great for Laravel, pretty URLs
MAMPmacOS, WindowsFriendly GUI, popular on Mac
LocalWindows, macOSWordPress-focused workflows

✅ Our recommendation for this course

If you just want to learn PHP, install PHP directly (a one-line package-manager command) and use the built-in server — it's the fastest path and mirrors how you'll actually run scripts. Reach for Docker once you're comfortable and want production parity.

Fastest Start: the Built-in Server

You may not need Apache or Nginx locally at all. Once PHP is installed, its built-in web server runs any folder as a site in one command. First, install PHP:

# macOS (Homebrew)
brew install php

# Ubuntu / Debian
sudo apt update
sudo apt install php php-cli php-mysql php-mbstring php-xml php-curl

# Windows: download the zip from windows.php.net, unzip to C:\php,
# then add C:\php to your PATH. (Laragon/XAMPP do this for you.)

# Confirm the version (expect 8.3.x or 8.4.x)
php --version

Now serve a folder. Create index.php, then start the server:

<?php
// index.php
echo '<h1>PHP is running!</h1>';
echo '<p>Version: ' . phpversion() . '</p>';
phpinfo(); // full configuration report
# From the folder containing index.php:
php -S localhost:8000

# Open http://localhost:8000 in your browser

⚠️ Development only

The built-in server is single-process and unhardened — perfect for learning and quick tests, but never for production. Real deployments use Nginx + PHP-FPM or Apache.

The Docker Approach

Docker packages PHP, the web server, and the database into containers that behave identically on every machine. It eliminates "works on my computer" problems and mirrors production closely. Here's a compact stack — PHP 8.3 with Apache, MySQL, and phpMyAdmin:

# compose.yaml  (run with: docker compose up -d)
services:
  web:
    image: php:8.3-apache
    ports:
      - "8080:80"
    volumes:
      - ./:/var/www/html
    depends_on:
      - db

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: app
      MYSQL_USER: dev
      MYSQL_PASSWORD: devpass
    volumes:
      - db_data:/var/lib/mysql

  phpmyadmin:
    image: phpmyadmin
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
    depends_on:
      - db

volumes:
  db_data:

With that file in your project folder:

# Start the whole stack in the background
docker compose up -d

# Your app:        http://localhost:8080
# phpMyAdmin:      http://localhost:8081

# Add PHP extensions inside the image via a Dockerfile:
#   RUN docker-php-ext-install pdo_mysql

# Stop and remove containers
docker compose down

💡 Why teams love this

A new teammate clones the repo, runs docker compose up, and has the exact same PHP version, extensions, and database as everyone else — in minutes, with nothing installed globally on their machine.

Configuring php.ini

The php.ini file controls how PHP behaves — error display, memory limits, upload sizes, time zone, and more. PHP ships two templates: php.ini-development (verbose errors, for you) and php.ini-production (quiet and hardened, for servers).

First, find which file is actually loaded:

# Show the loaded configuration file
php -i | grep "Loaded Configuration File"

# Or, in a browser, create a page with <?php phpinfo(); ?>
# and read the "Loaded Configuration File" row.

Settings that matter for development

SettingWhat it controlsDevelopmentProduction
display_errorsShow errors in the outputOnOff
error_reportingWhich errors to reportE_ALLE_ALL & ~E_DEPRECATED
log_errorsWrite errors to a log fileOnOn
memory_limitMax memory per script256M128M
upload_max_filesizeMax upload size64Mas needed
date.timezoneDefault time zoneyour local zoneserver zone (often UTC)
opcache.enableBytecode cache0 (off while editing)1 (on)

A minimal development block looks like this:

; --- Development settings in php.ini ---
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
log_errors = On
error_log = /tmp/php-error.log
date.timezone = "America/New_York"

⚠️ Never show errors in production

display_errors = On can leak file paths, queries, and secrets to attackers. On a live server, keep it Off and read log_errors output instead.

Extensions

Extra capabilities (database drivers, image processing, etc.) come from extensions. Common ones: pdo_mysql, mbstring, curl, gd, zip, intl. Enable them in php.ini or install them per platform:

# Ubuntu/Debian
sudo apt install php-mysql php-mbstring php-gd

# In a Dockerfile
RUN docker-php-ext-install pdo_mysql gd

VS Code for PHP

A tuned editor turns PHP from "type and pray" into a guided experience with autocompletion, instant error highlighting, and jump-to-definition. VS Code is free, fast, and — with a couple of extensions — an excellent PHP environment. PhpStorm is the powerful paid alternative if you prefer a full IDE.

💡 Essential VS Code extensions

  • PHP Intelephense — the big one: code completion, hover docs, go-to-definition, error checking. (Disable VS Code's built-in "PHP Language Features" to avoid duplicate suggestions.)
  • PHP Debug (by Xdebug) — connects the editor to Xdebug for breakpoints.
  • PHP DocBlocker — generates docblock comments as you type /**.
  • PHP Namespace Resolver — auto-imports and sorts use statements.

After installing, point VS Code at your PHP binary so it can validate and run code. Open Settings and set:

// settings.json
{
  "php.validate.executablePath": "/usr/bin/php",
  "intelephense.environment.phpVersion": "8.3.0",
  "editor.formatOnSave": true
}

On Windows the path is typically C:\\php\\php.exe or, with Laragon, something like C:\\laragon\\bin\\php\\php-8.3\\php.exe.

Real Debugging with Xdebug

Sprinkling var_dump() and echo everywhere works, but it's slow and messy. Xdebug lets you set a breakpoint, pause execution on that exact line, and inspect every variable in scope — the way a professional debugs.

flowchart LR A[Browser hits
your PHP page] --> B[Xdebug pauses
at breakpoint] B --> C[VS Code shows
variables & call stack] C --> D[Step / resume /
inspect]

Basic debugging you already have

<?php
$user = ['name' => 'Ada', 'roles' => ['admin']];

var_dump($user);   // type + value, great for arrays/objects
print_r($user);    // human-readable structure
error_log('reached checkout step'); // write to the error log

Setting up Xdebug

  1. Install it: sudo apt install php-xdebug (Linux), pecl install xdebug (macOS), or enable the bundled DLL in XAMPP/Laragon on Windows.
  2. Configure it in php.ini:
[xdebug]
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.client_host=localhost
  1. Add a launch configuration so VS Code listens for Xdebug. Create .vscode/launch.json:
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Listen for Xdebug",
      "type": "php",
      "request": "launch",
      "port": 9003
    }
  ]
}

Press F5, click in the gutter to set a breakpoint, then load your page. Execution stops on that line and the sidebar shows every variable.

⚠️ Port 9003, not 9000

Xdebug 3 switched the default debug port from 9000 to 9003. If breakpoints never trigger, a stale 9000 in either php.ini or launch.json is the usual culprit — make both say 9003.

Hands-on Exercise

🏋️ Stand up and verify your environment

Objective: Get PHP running, confirm the configuration, and prove your editor is wired up.

Instructions:

  1. Install PHP (or start your Docker/XAMPP stack) and run php --version — confirm it's 8.3 or newer.
  2. In an empty folder, create info.php containing a single phpinfo() call.
  3. Serve the folder with php -S localhost:8000 and open http://localhost:8000/info.php.
  4. Find the "Loaded Configuration File" row — note the path to your active php.ini.
  5. In that php.ini, set display_errors = On and error_reporting = E_ALL, restart the server, and confirm a deliberate typo (e.g. echo $undefined_var;) now shows a warning on screen.
💡 Hint

The built-in server must be restarted (stop with Ctrl+C, start again) after editing php.ini — it reads the config only at startup. If your changes seem ignored, you likely edited a different php.ini than the one phpinfo() reported.

✅ What success looks like
<?php
// info.php
phpinfo();

The phpinfo() page renders a large table. Near the top, "Loaded Configuration File" points to your active php.ini (for example /etc/php/8.3/cli/php.ini). After enabling error display and restarting, referencing an undefined variable prints a visible Warning: Undefined variable message instead of failing silently — proof your dev config is live.

🎯 Quick Quiz

Question 1: Which tool is appropriate for local development only, never production?

Question 2: You edited php.ini but the change had no effect on your built-in server. What's the most likely fix?

Question 3: Xdebug breakpoints never trigger. Which setting is the classic cause in Xdebug 3?

Summary & Quiz

🎉 Key Takeaways

  • A PHP stack = web server + PHP interpreter + database, plus Composer, Git, and an editor.
  • Choose among all-in-one packages, manual install, or Docker based on your goals.
  • PHP's built-in server (php -S) is the fastest way to run code locally — dev only.
  • php.ini controls behaviour; enable error display for development, disable it in production.
  • Tune VS Code with Intelephense and PHP Debug, and point it at your PHP binary.
  • Xdebug gives real breakpoints — remember port 9003.

📚 Further Reading

🚀 What's Next?

Your workshop is ready. The one tool we mentioned but haven't set up is Composer — PHP's dependency manager. Next you'll learn to pull in third-party libraries, autoload your own classes, and manage versions like a pro.

🎉 Environment ready!

You can run, configure, and debug PHP. Time to give it superpowers with Composer.