Módulo 01: Entorno de desarrollo

Objetivos del módulo

  • Conocer las distintas formas de tener PHP 8.5 en tu ordenador y elegir la más adecuada
  • Instalar PHP 8.5 de forma nativa en Windows, macOS o Linux
  • Configurar php.ini y activar las extensiones necesarias
  • Valorar los paquetes todo-en-uno (XAMPP, Laragon) y Docker
  • Usar el servidor integrado de PHP y los comandos básicos de la CLI
  • Preparar Visual Studio Code con las extensiones adecuadas
  • Instalar Composer y configurar Xdebug para depurar paso a paso
  • Crear la estructura de tu primer proyecto y ejecutar un “Hola mundo” en la terminal y en el navegador

1. ¿Qué necesitas para programar en PHP?

📘 Concepto: Un entorno de desarrollo es el conjunto de herramientas que te permiten escribir, ejecutar y depurar código en tu propio ordenador antes de publicarlo. Es como el taller de un carpintero: necesitas las herramientas (PHP, editor), el banco de trabajo (servidor web) y los materiales (base de datos).

Para este curso necesitas:

Pieza Para qué sirve Herramienta recomendada
Intérprete PHP 8.5 Ejecuta tu código PHP 8.5 oficial
Servidor web Sirve las páginas al navegador Servidor integrado php -S (desarrollo), Apache o Nginx
Editor de código Escribir código con ayudas Visual Studio Code
Gestor de dependencias Instalar librerías Composer
Depurador Ejecutar paso a paso e inspeccionar variables Xdebug + extensión PHP Debug
Base de datos (desde el módulo 15) Guardar información MariaDB o MySQL

Las tres opciones de instalación

Opción Ventajas Inconvenientes Recomendada para
Instalación nativa Control total, ligera, aprendes cómo funciona PHP de verdad Hay que configurar cada pieza a mano Este curso (opción principal)
Paquete todo-en-uno (XAMPP, Laragon) Un instalador con Apache, PHP y MariaDB Suelen ir por detrás en versiones de PHP; ocultan la configuración Empezar rápido en Windows
Docker Entorno idéntico en cualquier máquina y en producción; varias versiones a la vez Requiere aprender Docker; más consumo de recursos Equipos de trabajo y proyectos profesionales

💡 Consejo: Te recomendamos la instalación nativa para los módulos 01-14 (solo necesitas PHP y el servidor integrado) y, cuando llegues a bases de datos (módulo 15), elegir entre instalar MariaDB o usar el compose.yaml con Docker que verás en este módulo.


2. Instalación nativa en Windows

Paso 1: Descargar PHP 8.5

  1. Entra en la sección de descargas para Windows de php.net (la antigua dirección windows.php.net/download redirige allí).
  2. Busca PHP 8.5 y descarga el ZIP de la variante VS17 x64 Non Thread Safe (un fichero con un nombre como php-8.5.x-nts-Win32-vs17-x64.zip).
Variante Cuándo usarla
Non Thread Safe (NTS) Línea de comandos, servidor integrado, FastCGI (IIS, Nginx). La que necesitas en este curso
Thread Safe (TS) Cuando PHP se carga como módulo dentro de Apache (php8apache2_4.dll)
x86 Solo para Windows de 32 bits (muy raro hoy en día)

⚠️ Importante: Las compilaciones de PHP para Windows necesitan el Visual C++ Redistributable for Visual Studio 2015-2022 (versión x64). Si al ejecutar php aparece un error sobre VCRUNTIME140.dll, descárgalo desde la web de Microsoft (https://aka.ms/vs/17/release/vc_redist.x64.exe) e instálalo.

Paso 2: Descomprimir

Crea la carpeta C:\php y descomprime dentro el contenido del ZIP. Debes tener algo así:

C:\php\
├── ext\                     ← extensiones (php_mbstring.dll, php_pdo_mysql.dll...)
├── php.exe                  ← intérprete de línea de comandos
├── php-cgi.exe
├── php.ini-development      ← plantilla de configuración para desarrollo
├── php.ini-production       ← plantilla de configuración para producción
└── ...

💡 Consejo: Evita rutas con espacios o tildes (como C:\Program Files\ o C:\Users\José\). Algunas herramientas dan problemas con ellas.

Paso 3: Añadir PHP al PATH

El PATH es la lista de carpetas donde Windows busca los programas cuando escribes un comando. Añadiendo C:\php podrás escribir php desde cualquier terminal.

Con la interfaz gráfica:

  1. Pulsa Win y escribe “variables de entorno”. Abre Editar las variables de entorno del sistema.
  2. Pulsa Variables de entorno….
  3. En “Variables de usuario”, selecciona Path y pulsa Editar.
  4. Pulsa Nuevo, escribe C:\php y acepta todas las ventanas.

Con PowerShell (para tu usuario, sin permisos de administrador):

# Añade C:\php al PATH del usuario actual
$rutaActual = [Environment]::GetEnvironmentVariable('Path', 'User')
[Environment]::SetEnvironmentVariable('Path', "$rutaActual;C:\php", 'User')

Cierra todas las terminales (y VS Code) y abre una nueva. Comprueba:

php -v
PHP 8.5.x (cli) (built: ...) (NTS Visual C++ 2022 x64)
Copyright (c) The PHP Group
Zend Engine v4.5.x, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.x, Copyright (c), by Zend Technologies

⚠️ Importante: Si ves “php no se reconoce como un comando interno o externo”, el PATH no está bien o no has abierto una terminal nueva. Si ves una versión antigua (por ejemplo 7.4), es que tienes otro PHP antes en el PATH (típico si instalaste XAMPP en el pasado). Comprueba cuál se está usando con where.exe php y reordena las entradas del PATH.

Paso 4: Crear el php.ini

php.ini es el fichero de configuración de PHP. El ZIP trae dos plantillas; para desarrollo usa la primera:

Copy-Item C:\php\php.ini-development C:\php\php.ini
Plantilla Diferencias clave
php.ini-development Muestra todos los errores en pantalla (display_errors = On). Ideal para aprender
php.ini-production Oculta los errores al usuario y los registra en un log. Lo que se usa en un servidor real

Paso 5: Activar extensiones

Las extensiones añaden funcionalidades a PHP (cadenas multibyte, bases de datos, cURL…). Abre C:\php\php.ini con un editor y busca estas líneas. Quita el punto y coma inicial (;) para activarlas:

; Carpeta donde están las extensiones (descomenta esta línea en Windows)
extension_dir = "ext"

; Extensiones recomendadas para el curso
extension=curl
extension=fileinfo
extension=gd
extension=intl
extension=mbstring
extension=openssl
extension=pdo_mysql
extension=pdo_sqlite
extension=sodium
extension=sqlite3
extension=zip

Busca también estas directivas y ajústalas:

; Zona horaria (si no la configuras, date() usará UTC)
date.timezone = Europe/Madrid

; Mostrar todos los errores (ya vienen así en php.ini-development)
error_reporting = E_ALL
display_errors = On
display_startup_errors = On

; Límites razonables para desarrollo
memory_limit = 256M
upload_max_filesize = 20M
post_max_size = 25M

📘 Concepto: En php.ini, el punto y coma ; inicia un comentario. Por eso las extensiones vienen “apagadas”: están comentadas. Quitar el ; las activa.

Comprueba qué fichero de configuración está leyendo PHP:

php --ini
Configuration File (php.ini) Path:
Loaded Configuration File:         C:\php\php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

Si en “Loaded Configuration File” aparece (none), PHP no encuentra tu php.ini: revisa que se llame exactamente así (cuidado con que Windows no lo haya guardado como php.ini.txt).


3. Instalación nativa en macOS

En macOS la forma más sencilla es Homebrew, el gestor de paquetes más popular. Si no lo tienes, instálalo siguiendo las instrucciones de https://brew.sh.

# Instala la última versión estable de PHP (la rama 8.5)
brew install php

# Comprueba la versión
php -v

Si necesitas una versión concreta (por ejemplo, porque brew install php ya instale una más nueva en el futuro), el tap de Shivam Mathur ofrece todas las ramas:

brew tap shivammathur/php
brew install shivammathur/php/php@8.5
brew link --overwrite --force shivammathur/php/php@8.5

Localiza el php.ini y las extensiones:

php --ini
# Loaded Configuration File: /opt/homebrew/etc/php/8.5/php.ini

Homebrew ya incluye las extensiones más comunes (mbstring, intl, pdo_mysql, curl…). Edita ese php.ini para fijar date.timezone = Europe/Madrid.

💡 Consejo: Homebrew también instala PHP-FPM. Si más adelante quieres usarlo con Nginx, puedes arrancarlo como servicio con brew services start php. Para este curso basta con el servidor integrado.


4. Instalación nativa en Linux

Ubuntu y derivadas: repositorio ondrej/php

Los repositorios oficiales de cada versión de Ubuntu traen una versión fija de PHP que no siempre es la última. Ondřej Surý, mantenedor de los paquetes de PHP en Debian, publica un repositorio (PPA) con todas las versiones actuales:

# 1. Herramienta para añadir repositorios
sudo apt update
sudo apt install -y software-properties-common

# 2. Añadir el repositorio de Ondřej Surý
sudo add-apt-repository ppa:ondrej/php
sudo apt update

# 3. Instalar PHP 8.5 (CLI) y las extensiones del curso
sudo apt install -y php8.5-cli php8.5-common php8.5-mbstring php8.5-intl \
    php8.5-curl php8.5-xml php8.5-zip php8.5-gd php8.5-mysql php8.5-sqlite3

# 4. Comprobar
php -v

⚠️ Importante: Si instalas el paquete genérico php8.5 (sin -cli), apt instalará también Apache y su módulo de PHP. No es un problema, pero si solo quieres la línea de comandos y el servidor integrado, instala php8.5-cli.

En Debian el repositorio equivalente es packages.sury.org; sigue las instrucciones de su web para añadirlo.

Ficheros de configuración en Debian/Ubuntu

En estas distribuciones hay un php.ini por cada SAPI:

/etc/php/8.5/cli/php.ini        ← línea de comandos y servidor integrado
/etc/php/8.5/apache2/php.ini    ← Apache (si lo instalaste)
/etc/php/8.5/fpm/php.ini        ← PHP-FPM (si lo instalaste)
/etc/php/8.5/mods-available/    ← un .ini por extensión

Las extensiones se activan y desactivan con:

sudo phpenmod mbstring     # activar
sudo phpdismod xdebug      # desactivar

5. Paquetes todo-en-uno: XAMPP y Laragon

Los paquetes todo-en-uno instalan de una vez Apache, PHP, MariaDB/MySQL y phpMyAdmin.

Paquete Sistemas Ventajas A tener en cuenta
XAMPP (Apache Friends) Windows, macOS, Linux Muy conocido, gratuito, panel de control sencillo Sus versiones van muy por detrás de PHP: durante mucho tiempo su última versión ha traído PHP 8.2
Laragon Windows Rápido, permite cambiar de versión de PHP desde el menú, crea dominios .test automáticos Desde la versión 7 es de pago (la 6 fue la última gratuita); las versiones actuales incluyen PHP 8.5
Laravel Herd Windows, macOS Instalación en un clic, cambio de versión de PHP sencillo Orientado a Laravel, aunque sirve para cualquier proyecto PHP

⚠️ Importante: Para este curso necesitas PHP 8.5. Antes de usar un paquete todo-en-uno, comprueba qué versión de PHP trae. Si trae una anterior, tienes dos opciones:

  1. Actualizar el PHP del paquete: en Laragon basta con descomprimir el ZIP de PHP 8.5 en laragon\bin\php\ y seleccionarlo en el menú PHP → Version. En XAMPP hay que sustituir la carpeta xampp\php por una compilación Thread Safe de PHP 8.5 y ajustar la configuración de Apache, un proceso delicado.
  2. Usar el paquete solo para la base de datos (MariaDB y phpMyAdmin) y ejecutar tu código con el PHP 8.5 nativo.

💡 Consejo: Si ya tenías XAMPP instalado, ten cuidado con el PATH: es muy habitual que php -v muestre el PHP antiguo de XAMPP (C:\xampp\php) en lugar del 8.5 que acabas de instalar. Usa where.exe php para saber cuál se ejecuta.


6. Docker

📘 Concepto: Docker ejecuta aplicaciones dentro de contenedores: entornos aislados y ligeros que incluyen todo lo necesario (sistema base, PHP, extensiones). Es como enviar tu proyecto dentro de un contenedor de mercancías estándar: funcionará igual en tu portátil, en el de un compañero y en el servidor.

Necesitas Docker Desktop (Windows/macOS) o Docker Engine (Linux).

Imágenes oficiales de PHP

Imagen Contenido Uso
php:8.5-cli PHP de línea de comandos Ejecutar scripts, Composer, tests
php:8.5-apache PHP + Apache con mod_php Aplicaciones web clásicas
php:8.5-fpm PHP-FPM (sin servidor web) Combinado con un contenedor Nginx
php:8.5-cli-alpine Versión mínima basada en Alpine Linux Imágenes pequeñas

Prueba rápida sin instalar nada más:

docker run --rm php:8.5-cli php -v

Ejecutar un script de la carpeta actual:

# Monta la carpeta actual en /app y ejecuta hola.php
docker run --rm -v "$PWD":/app -w /app php:8.5-cli php hola.php

En PowerShell, sustituye "$PWD" por "${PWD}".

Un entorno web completo con Docker Compose

Vamos a montar Apache + PHP 8.5 + MariaDB + phpMyAdmin. Estructura del proyecto:

mi-proyecto/
├── compose.yaml
├── docker/
│   └── php/
│       └── Dockerfile
└── public/
    └── index.php

docker/php/Dockerfile:

FROM php:8.5-apache

# Extensiones del sistema necesarias para compilar extensiones de PHP
RUN apt-get update && apt-get install -y --no-install-recommends \
        libicu-dev libzip-dev \
    && rm -rf /var/lib/apt/lists/*

# Extensiones de PHP: PDO para MySQL/MariaDB, intl y zip
RUN docker-php-ext-install pdo_mysql intl zip

# Xdebug para depurar (solo en desarrollo)
RUN pecl install xdebug && docker-php-ext-enable xdebug

# Usar la configuración de desarrollo que trae la imagen
RUN cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

# Activar mod_rewrite (URLs amigables) y servir la carpeta public/
RUN a2enmod rewrite
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf

# Composer copiado desde su imagen oficial
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

compose.yaml:

services:
  web:
    build: ./docker/php
    ports:
      - "8080:80"            # http://localhost:8080
    volumes:
      - ./:/var/www/html     # tu código, sincronizado en vivo
    environment:
      XDEBUG_MODE: debug,develop
      XDEBUG_CONFIG: client_host=host.docker.internal client_port=9003
    extra_hosts:
      - "host.docker.internal:host-gateway"
    depends_on:
      - db

  db:
    image: mariadb:11.8
    environment:
      MARIADB_ROOT_PASSWORD: root
      MARIADB_DATABASE: curso_php
      MARIADB_USER: curso
      MARIADB_PASSWORD: curso
    ports:
      - "3306:3306"
    volumes:
      - datos_db:/var/lib/mysql

  phpmyadmin:
    image: phpmyadmin:5
    ports:
      - "8081:80"            # http://localhost:8081
    environment:
      PMA_HOST: db
    depends_on:
      - db

volumes:
  datos_db:

public/index.php:

<?php

declare(strict_types=1);

echo '<h1>PHP ' . PHP_VERSION . ' funcionando en Docker</h1>';

Comandos básicos:

docker compose up -d --build     # construir y arrancar en segundo plano
docker compose ps                # ver los contenedores
docker compose logs -f web       # ver los logs del servidor web
docker compose exec web php -v   # ejecutar un comando dentro del contenedor
docker compose exec web composer install
docker compose down              # parar (los datos de la BD se conservan en el volumen)

Abre http://localhost:8080 y verás la versión de PHP. phpMyAdmin estará en http://localhost:8081 (usuario root, contraseña root).

⚠️ Importante: Las contraseñas de este compose.yaml son solo para desarrollo local. Nunca uses credenciales así en un servidor real ni subas contraseñas reales a un repositorio.

💡 Consejo: Dentro de la red de Docker, tu código PHP se conecta a la base de datos usando como host el nombre del servicio (db), no localhost. Lo verás en el módulo 15.


7. La línea de comandos de PHP

Instales como instales PHP, tendrás el ejecutable php. Estos son los comandos que más usarás:

Comando Qué hace
php -v Muestra la versión de PHP
php fichero.php Ejecuta un script
php -m Lista los módulos (extensiones) cargados
php -i Muestra toda la configuración (equivale a phpinfo() en texto)
php --ini Indica qué php.ini se está usando
php -l fichero.php Comprueba la sintaxis sin ejecutar (lint)
php -r 'código' Ejecuta código directamente, sin fichero
php -a Abre el modo interactivo
php -S localhost:8000 Arranca el servidor web integrado
php --ri mbstring Muestra la configuración de una extensión concreta

Ejecutar código suelto con php -r

php -r 'echo PHP_VERSION, PHP_EOL;'
php -r 'echo date("d/m/Y H:i"), PHP_EOL;'

⚠️ Importante: Con php -r no se escribe la etiqueta <?php. Y cuidado con las comillas: en PowerShell y Bash las variables $ dentro de comillas dobles las interpreta la propia terminal. Usa comillas simples por fuera.

El modo interactivo: php -a

El modo interactivo (REPL) te permite escribir instrucciones y ver el resultado al momento. Es perfecto para probar funciones:

$ php -a
Interactive shell

php > echo strtoupper('hola');
HOLA
php > $precio = 19.99;
php > echo $precio * 3;
59.97
php > var_dump(str_contains('Curso de PHP', 'PHP'));
bool(true)
php > exit

💡 Consejo: Usa php -a como “calculadora de PHP” durante el curso: cuando dudes de qué devuelve una función, pruébala ahí en segundos.


8. El servidor web integrado

PHP incluye un pequeño servidor web para desarrollo. No necesitas instalar Apache ni Nginx para empezar.

# Sirve la carpeta actual en http://localhost:8000
php -S localhost:8000

# Sirve la carpeta public/ (lo habitual en proyectos reales)
php -S localhost:8000 -t public

# Usa un puerto distinto si el 8000 está ocupado
php -S localhost:8080

Salida en la terminal:

[Sat Oct  3 10:15:02 2026] PHP 8.5.x Development Server (http://localhost:8000) started
[Sat Oct  3 10:15:07 2026] [::1]:52144 Accepted
[Sat Oct  3 10:15:07 2026] [::1]:52144 [200]: GET /
[Sat Oct  3 10:15:07 2026] [::1]:52144 Closing

Cada petición aparece en la terminal con su código de estado, lo que resulta muy útil para depurar. Para pararlo, pulsa Ctrl + C.

⚠️ Importante: El servidor integrado es solo para desarrollo. No está pensado para soportar tráfico real ni tiene las medidas de seguridad de Apache o Nginx. Nunca lo uses en producción.


9. phpinfo(): la radiografía de tu PHP

La función phpinfo() genera una página HTML con toda la información de tu instalación: versión, php.ini cargado, extensiones, variables de entorno…

<?php
// info.php
phpinfo();
php -S localhost:8000
# Abre http://localhost:8000/info.php

Qué mirar en esa página:

Sección Qué te dice
Cabecera Versión exacta de PHP (8.5.x)
Server API Cómo se ejecuta PHP (Built-in HTTP server, Apache 2.0 Handler, FPM/FastCGI)
Loaded Configuration File Ruta del php.ini que se está usando
Secciones por extensión Si una extensión aparece, está cargada (busca mbstring, pdo_mysql, xdebug)
date Zona horaria configurada

⚠️ Importante: phpinfo() revela muchísima información sobre tu servidor que un atacante podría aprovechar. Borra info.php cuando termines y no lo subas nunca a un servidor público.

💡 Consejo: Ten en cuenta que el php.ini de la CLI y el del servidor web pueden ser distintos (sobre todo en Linux o con XAMPP). Si una extensión funciona en la terminal pero no en el navegador, compara php --ini con lo que dice phpinfo() en el navegador.


10. Visual Studio Code

Visual Studio Code es un editor gratuito, ligero y con extensiones para todo. Descárgalo desde https://code.visualstudio.com.

Extensiones recomendadas

Extensión Autor Para qué
PHP Intelephense Ben Mewburn Autocompletado, ir a la definición, detección de errores, documentación al pasar el ratón
PHP Debug Xdebug Conecta VS Code con Xdebug para depurar paso a paso
EditorConfig for VS Code EditorConfig Respeta la configuración de sangrado y codificación del proyecto
Docker / Container Tools Microsoft Gestionar contenedores desde el editor (si usas Docker)

Instálalas desde el panel de extensiones (Ctrl + Shift + X) o desde la terminal:

code --install-extension bmewburn.vscode-intelephense-client
code --install-extension xdebug.php-debug
code --install-extension editorconfig.editorconfig

💡 Consejo: Intelephense recomienda desactivar la extensión integrada de VS Code PHP Language Features para evitar sugerencias duplicadas. En el panel de extensiones busca @builtin php, y desactiva “PHP Language Features” (deja activa “PHP Language Basics”, que da el coloreado).

Configuración recomendada

Abre la configuración en JSON (Ctrl + Shift + P → Preferences: Open User Settings (JSON)) y añade:

{
    "intelephense.environment.phpVersion": "8.5.0",
    "[php]": {
        "editor.defaultFormatter": "bmewburn.vscode-intelephense-client",
        "editor.formatOnSave": true,
        "editor.tabSize": 4,
        "editor.insertSpaces": true
    },
    "files.encoding": "utf8",
    "files.eol": "\n",
    "files.trimTrailingWhitespace": true,
    "files.insertFinalNewline": true
}
Opción Efecto
intelephense.environment.phpVersion Intelephense analiza el código como PHP 8.5 (reconoce \|>, array_first()…)
editor.formatOnSave Formatea el fichero al guardar
editor.tabSize: 4 4 espacios de sangrado, como indica el estándar PSR-12/PER
files.encoding: utf8 Todos los ficheros en UTF-8 (imprescindible para tildes y eñes)
files.eol: \n Saltos de línea estilo Unix, el estándar en proyectos PHP

11. Composer

📘 Concepto: Composer es el gestor de dependencias de PHP. Permite instalar librerías de terceros (y sus dependencias) con un solo comando y genera un sistema de carga automática (autoload) de clases. Es el equivalente a npm en JavaScript o pip en Python. Lo estudiarás a fondo en el módulo 13.

Instalación en Windows

Descarga y ejecuta Composer-Setup.exe desde https://getcomposer.org/download/. El instalador detecta tu php.exe (asegúrate de que señala a C:\php\php.exe) y añade Composer al PATH.

Instalación en macOS

brew install composer

Instalación en Linux (y macOS sin Homebrew)

# Descarga el instalador
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"

# Ejecuta el instalador (genera composer.phar)
php composer-setup.php

# Borra el instalador
php -r "unlink('composer-setup.php');"

# Muévelo a una carpeta del PATH para usarlo como "composer"
sudo mv composer.phar /usr/local/bin/composer

⚠️ Importante: La página oficial de descarga incluye un paso adicional para verificar la firma (hash SHA-384) del instalador. El hash cambia con cada versión, así que cópialo siempre de getcomposer.org/download en lugar de un tutorial.

Comprobación

composer --version
# Composer version 2.x.x ...

composer diagnose
# Comprueba la configuración, la conexión con Packagist, OpenSSL...

12. Xdebug: depurar paso a paso

📘 Concepto: Depurar consiste en ejecutar el programa pausándolo en las líneas que te interesan (puntos de interrupción o breakpoints) para ver el valor de cada variable y avanzar instrucción a instrucción. Es como ver una película fotograma a fotograma para descubrir dónde se equivoca el actor. Xdebug es la extensión de PHP que lo hace posible.

Xdebug 3.5 es la primera versión con soporte oficial para PHP 8.5.

Instalación

Sistema Cómo instalarlo
Windows Descarga la DLL desde https://xdebug.org/download que coincida con tu PHP (8.5, NTS, VS17, x64). Cópiala en C:\php\ext\ y renómbrala a php_xdebug.dll
macOS pecl install xdebug
Ubuntu (PPA ondrej) sudo apt install php8.5-xdebug
Docker pecl install xdebug && docker-php-ext-enable xdebug (como en el Dockerfile anterior)

💡 Consejo: Si dudas de qué fichero descargar, usa el asistente de https://xdebug.org/wizard: pegas la salida de php -i y te dice exactamente qué DLL bajar y dónde ponerla.

Configuración

Añade al final de tu php.ini (en Ubuntu, en /etc/php/8.5/mods-available/xdebug.ini):

[xdebug]
zend_extension=xdebug

; debug   = depuración paso a paso
; develop = mensajes de error mejorados y var_dump() más legible
xdebug.mode=debug,develop

; Conectar con el editor en cada petición
xdebug.start_with_request=yes

; Dónde escucha VS Code
xdebug.client_host=127.0.0.1
xdebug.client_port=9003

⚠️ Importante: Xdebug se carga con zend_extension, no con extension. Si usas extension=xdebug, aparecerá un aviso y no funcionará.

Comprueba que está cargado:

php -v
PHP 8.5.x (cli) ...
Zend Engine v4.5.x, Copyright (c) Zend Technologies
    with Xdebug v3.5.x, Copyright (c) 2002-2026, by Derick Rethans
    with Zend OPcache v8.5.x, Copyright (c), by Zend Technologies

También puedes llamar a xdebug_info() en un script para ver un informe completo de su configuración.

💡 Consejo: Con start_with_request=yes, Xdebug intenta conectar con el editor en cada ejecución, lo que ralentiza un poco PHP y puede mostrar avisos si VS Code no está escuchando. Una alternativa es xdebug.start_with_request=trigger, que solo depura cuando la petición lleva el parámetro XDEBUG_TRIGGER (por ejemplo, http://localhost:8000/?XDEBUG_TRIGGER=1).

Configurar VS Code

En VS Code, abre el panel Ejecutar y depurar (Ctrl + Shift + D), pulsa “crear un archivo launch.json” y elige PHP. Se crea .vscode/launch.json. Déjalo así:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Escuchar Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        },
        {
            "name": "Ejecutar el script abierto",
            "type": "php",
            "request": "launch",
            "program": "${file}",
            "cwd": "${fileDirname}",
            "port": 9003
        },
        {
            "name": "Escuchar Xdebug (Docker)",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "pathMappings": {
                "/var/www/html": "${workspaceFolder}"
            }
        }
    ]
}
Configuración Cuándo usarla
Escuchar Xdebug VS Code espera conexiones. Luego ejecutas el script en la terminal o recargas la página en el navegador
Ejecutar el script abierto VS Code lanza php con el fichero que tienes abierto. Ideal para scripts de CLI
Escuchar Xdebug (Docker) Igual que la primera, pero traduce las rutas del contenedor a las de tu proyecto

Tu primera sesión de depuración

Crea depurar.php:

<?php

declare(strict_types=1);

$precios = [12.50, 8.99, 23.00];
$total = 0;

foreach ($precios as $precio) {
    $total += $precio;          // ← pon aquí un punto de interrupción (F9)
}

$iva = $total * 0.21;
echo "Total con IVA: " . ($total + $iva) . PHP_EOL;
  1. Haz clic a la izquierda del número de la línea $total += $precio; (o pulsa F9). Aparece un punto rojo.
  2. Elige la configuración Ejecutar el script abierto y pulsa F5.
  3. La ejecución se detiene en el punto rojo. En el panel Variables verás $precios, $precio y $total con sus valores.
  4. Usa los controles de depuración:
Botón / tecla Acción
F5 Continuar Sigue hasta el siguiente punto de interrupción
F10 Paso a paso por encima Ejecuta la línea actual y pasa a la siguiente
F11 Paso a paso por dentro Si la línea llama a una función tuya, entra en ella
Shift + F11 Salir Termina la función actual y vuelve a quien la llamó
Shift + F5 Detener Termina la depuración
  1. Pulsa F5 varias veces y observa cómo $total va aumentando: 12.5, 21.49, 44.49.

💡 Consejo: En el panel Inspección (Watch) puedes escribir expresiones como $total * 0.21 para ver su valor en cada pausa. Y en la Consola de depuración puedes ejecutar código PHP en el contexto del punto de pausa.


13. Tu primer proyecto

Estructura recomendada

curso-php/
├── .vscode/
│   └── launch.json        ← configuración de depuración
├── public/                ← lo ÚNICO accesible desde el navegador
│   ├── index.php
│   └── css/
│       └── estilos.css
├── src/                   ← tu código PHP (clases, funciones)
├── scripts/               ← scripts de línea de comandos
│   └── hola.php
├── .editorconfig
├── .gitignore
└── composer.json          ← cuando uses Composer

📘 Concepto: La carpeta public/ es la raíz web (document root): solo lo que hay dentro se puede pedir desde el navegador. El resto del código (configuración, clases, contraseñas de la base de datos) queda fuera de su alcance. Es una medida de seguridad básica que usan todos los frameworks.

.editorconfig:

root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.{yml,yaml,json}]
indent_size = 2

“Hola mundo” en la línea de comandos

scripts/hola.php:

<?php

declare(strict_types=1);

$nombre = $argv[1] ?? 'mundo';   // primer argumento de la terminal, o 'mundo'

echo "¡Hola, {$nombre}!" . PHP_EOL;
echo 'Estás usando PHP ' . PHP_VERSION . ' en ' . PHP_OS_FAMILY . PHP_EOL;
php scripts/hola.php
php scripts/hola.php Ana

Salida:

¡Hola, mundo!
Estás usando PHP 8.5.x en Windows
¡Hola, Ana!
Estás usando PHP 8.5.x en Windows

📘 Concepto: $argv es un array con los argumentos que recibe un script de línea de comandos. $argv[0] es el nombre del propio script y $argv[1] el primer argumento. El operador ?? devuelve 'mundo' si no existe (lo verás en el módulo 03).

“Hola mundo” en el navegador

public/index.php:

<?php
declare(strict_types=1);

$titulo   = 'Mi primer proyecto PHP';
$version  = PHP_VERSION;
$fecha    = date('d/m/Y H:i');
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= $titulo ?></title>
    <link rel="stylesheet" href="css/estilos.css">
</head>
<body>
    <main>
        <h1>¡Hola, mundo!</h1>
        <p>Esta página la ha generado <strong>PHP <?= $version ?></strong>.</p>
        <p>Fecha y hora del servidor: <?= $fecha ?></p>
    </main>
</body>
</html>

public/css/estilos.css:

body {
    font-family: system-ui, sans-serif;
    background: #f4f4f8;
    display: grid;
    place-items: center;
    min-height: 100vh;
    margin: 0;
}

main {
    background: white;
    padding: 2rem 3rem;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgb(0 0 0 / 0.08);
}

h1 {
    color: #777bb3; /* el morado del logo de PHP */
}

Arranca el servidor desde la raíz del proyecto:

php -S localhost:8000 -t public

Abre http://localhost:8000. Verás tu página con la versión de PHP y la fecha. Recarga: la hora cambia en cada petición, porque PHP genera la página de nuevo cada vez.

✏️ Ejercicio: Abre “Ver código fuente” en el navegador (Ctrl + U) y comprueba que no queda ni rastro del código PHP: solo HTML.

Errores comunes al empezar

Problema Causa probable Solución
El navegador muestra el código PHP o descarga el fichero Has abierto el fichero con doble clic (file:///) Accede siempre por http://localhost:8000
php no se reconoce como comando PHP no está en el PATH o la terminal es antigua Revisa el PATH y abre una terminal nueva
php -v muestra otra versión Otro PHP (XAMPP, etc.) va antes en el PATH where.exe php (Windows) o which php (Linux/macOS)
Call to undefined function mb_strlen() Extensión mbstring desactivada Descomenta extension=mbstring en php.ini
Failed to listen on localhost:8000 El puerto está ocupado Usa otro puerto: php -S localhost:8080
Las tildes se ven como á Fichero no guardado en UTF-8 o falta <meta charset> Guarda en UTF-8 y añade <meta charset="UTF-8">
La hora sale con 1 o 2 horas de diferencia Zona horaria no configurada date.timezone = Europe/Madrid en php.ini

14. Ejercicios

Ejercicio 1: Instalación verificada

Instala PHP 8.5 con el método que prefieras y guarda en un fichero entorno.txt la salida de estos comandos: php -v, php --ini y php -m. Comprueba que aparecen mbstring, intl, pdo_mysql y openssl.

Ejercicio 2: Configura tu php.ini

Modifica tu php.ini para que la zona horaria sea Europe/Madrid y memory_limit sea 512M. Verifica los cambios sin abrir el fichero, usando:

php -r 'echo ini_get("date.timezone"), " - ", ini_get("memory_limit"), PHP_EOL;'

Ejercicio 3: Explora el modo interactivo

Abre php -a y averigua el resultado de estas expresiones. Anota cada resultado:

  • echo PHP_VERSION;
  • echo PHP_OS_FAMILY;
  • echo strrev('reconocer');
  • echo str_repeat('=-', 10);
  • echo date('l');
  • var_dump(10 / 4);

Ejercicio 4: Página de diagnóstico

Crea public/diagnostico.php que muestre en una tabla HTML: la versión de PHP (PHP_VERSION), el sistema operativo (PHP_OS_FAMILY), la zona horaria (date_default_timezone_get()), la ruta del php.ini (php_ini_loaded_file()) y si están cargadas las extensiones mbstring, intl y xdebug (usa extension_loaded('mbstring'), que devuelve true o false). Sírvela con php -S y ábrela en el navegador.

Ejercicio 5: Depura un bucle

Escribe un script que sume los números del 1 al 10 con un bucle for (puedes copiar la estructura del ejemplo de depuración y adaptarla). Pon un punto de interrupción dentro del bucle y, usando solo el depurador, apunta el valor de la variable acumuladora en cada vuelta. ¿En qué vuelta supera el valor 20?

Ejercicio 6: Entorno con Docker

Monta el entorno de la sección 6 con docker compose up -d --build. Comprueba que:

  1. http://localhost:8080 muestra la versión de PHP 8.5.
  2. docker compose exec web php -m incluye pdo_mysql y xdebug.
  3. Puedes entrar en phpMyAdmin (http://localhost:8081) y ver la base de datos curso_php.

Ejercicio 7: Saludo con argumentos

Amplía scripts/hola.php para que acepte dos argumentos: nombre y ciudad (php scripts/hola.php Ana Sevilla) y muestre “¡Hola, Ana de Sevilla!”. Si falta la ciudad, debe mostrar solo “¡Hola, Ana!”. Pista: $argv[2] ?? null.


Resumen

Concepto Comando / sintaxis
Ver versión php -v
Ver extensiones php -m
Ver php.ini cargado php --ini
Configuración completa php -i o phpinfo()
Comprobar sintaxis php -l fichero.php
Ejecutar código suelto php -r 'echo 1 + 1;'
Modo interactivo php -a
Servidor integrado php -S localhost:8000 -t public
Activar extensión extension=mbstring en php.ini
Activar Xdebug zend_extension=xdebug + xdebug.mode=debug
Puerto de Xdebug 9003
Instalar librería composer require vendor/paquete
Docker CLI docker run --rm php:8.5-cli php -v
Docker web php:8.5-apache + compose.yaml con MariaDB
Ubuntu ppa:ondrej/php → apt install php8.5-cli
macOS brew install php
Windows ZIP VS17 x64 Non Thread Safe en C:\php + PATH