🛠️ 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.
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.
| Approach | Best for | Trade-off |
|---|---|---|
| All-in-one package (XAMPP, Laragon, MAMP) | Beginners who want one installer that bundles Apache + MySQL + PHP | Less insight into how the pieces fit; can drift from production |
| Manual install (package manager / Homebrew) | Understanding each component; matching a specific server | More steps; you wire the pieces together yourself |
| Docker (containers) | Reproducible, "same everywhere" environments; teams | A learning curve if you're new to containers |
All-in-one packages at a glance
| Package | Platforms | Notable for |
|---|---|---|
| XAMPP | Windows, macOS, Linux | The classic cross-platform bundle |
| Laragon | Windows | Fast, great for Laravel, pretty URLs |
| MAMP | macOS, Windows | Friendly GUI, popular on Mac |
| Local | Windows, macOS | WordPress-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
| Setting | What it controls | Development | Production |
|---|---|---|---|
display_errors | Show errors in the output | On | Off |
error_reporting | Which errors to report | E_ALL | E_ALL & ~E_DEPRECATED |
log_errors | Write errors to a log file | On | On |
memory_limit | Max memory per script | 256M | 128M |
upload_max_filesize | Max upload size | 64M | as needed |
date.timezone | Default time zone | your local zone | server zone (often UTC) |
opcache.enable | Bytecode cache | 0 (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
usestatements.
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.
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
- Install it:
sudo apt install php-xdebug(Linux),pecl install xdebug(macOS), or enable the bundled DLL in XAMPP/Laragon on Windows. - 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
- 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:
- Install PHP (or start your Docker/XAMPP stack) and run
php --version— confirm it's 8.3 or newer. - In an empty folder, create
info.phpcontaining a singlephpinfo()call. - Serve the folder with
php -S localhost:8000and openhttp://localhost:8000/info.php. - Find the "Loaded Configuration File" row — note the path to your active
php.ini. - In that
php.ini, setdisplay_errors = Onanderror_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
- PHP Manual — Installation & Configuration
- Xdebug Documentation
- VS Code — PHP Development
- Official PHP Docker images
🚀 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.