Guía completa de PHP 8 para desarrolladores backend
Esta guía recoge lo esencial y práctico para llevar tus proyectos backend en PHP 8 a producción: novedades del lenguaje, buenas prácticas, seguridad, rendimiento y un ejemplo completo mínimo de API REST. Ve al grano: ejemplos de código, estructura de proyecto y por qué se hacen las cosas así.
1. ¿Qué trae PHP 8 que debes aprovechar?
- Tipado mejorado: union types, typed properties y tipos de retorno que mejoran la calidad y autocompletado.
- constructor property promotion: evita boilerplate en constructores.
- match expression: más seguro y expresivo que switch.
- Nullsafe operator (?->): evita chequeos redundantes de null.
- Atributos (Attributes): metadatos nativos, útiles para frameworks y validaciones.
- JIT: puede ayudar en ciertos escenarios CPU-bound, pero no es panacea para I/O-bound apps típicas.
2. Principios y mejores prácticas (rápido)
- Usa strict_types=1 en archivos sensibles para evitar coerción sorpresa.
- Sigue PSR (PSR-12 formateo, PSR-4 autoloading); facilita colaboración y tooling.
- Dependencias con Composer; evita commits de vendor/.
- Preferir DI (Dependency Injection) sobre singletons/globals.
- Escribe tests (unitarios/integración) y CI para pipelines automatizados.
3. Seguridad crítica
- SQL injection: usa siempre sentencias preparadas (PDO/Doctrine) y evita concatenar input en consultas.
- Validación y saneamiento: valida en la capa de entrada, no confíes en el cliente.
- Contraseñas: password_hash() y password_verify(); nunca md5/sha1.
- Escape de salida: htmlspecialchars() al renderizar; JSON con json_encode() correctamente configurado (JSON_UNESCAPED_UNICODE cuando convenga).
- Headers de seguridad: Content-Security-Policy, X-Frame-Options, Strict-Transport-Security (HSTS).
4. Rendimiento y despliegue
- Activa OPcache (config en php.ini). Esto siempre mejora latencia.
- JIT: habilítalo solo si tu app tiene hotspots CPU-bound y tras medir. No esperes mejora en la mayoría de apps I/O.
- Caching: aplica caching a resultados pesados (Redis, Memcached) y considera HTTP cache headers.
- Usa un pool de conexiones DB en procesos persistentes (p. ej. PHP-FPM con PDO persistent cuando convenga).
- Containeriza (Docker) y orquesta (Kubernetes) solo cuando lo necesites; instrumenta con métricas y traces (Prometheus, Jaeger).
5. Manejo de errores y observabilidad
- No suprimir errores en producción; loguea con nivel adecuado. Usa Monolog y envía errores críticos a un Sentry u otra plataforma.
- Preferir excepciones tipadas; captura y transforma a respuestas HTTP coherentes en el gateway.
- Instrumenta timelines de requests y long-tails para detectar latencias fuera de lo común.
6. Estructura mínima recomendada para un proyecto backend
Una estructura simple, clara y compatible con PSR-4:
project/
├─ src/
│ ├─ Controller/
│ ├─ Repository/
│ ├─ Service/
│ └─ Kernel.php
├─ public/
│ └─ index.php
├─ config/
│ └─ database.php
├─ tests/
├─ composer.json
└─ Dockerfile
7. Tutorial práctico mínimo: API REST de usuarios (SQLite + PDO)
Objetivo: un endpoint GET /users que devuelva JSON. Implementación mínima sin frameworks para mostrar DI, prepared statements y buenas prácticas.
composer.json
{
"name": "example/php8-api",
"require": {
"php": "^8.0",
"ext-pdo": "*",
"monolog/monolog": "^3.0"
},
"autoload": {
"psr-4": { "App\\": "src/" }
}
}
config/database.php
<?php
return [
'driver' => 'sqlite',
'database' => __DIR__ . '/../data/app.sqlite',
];
src/Repository/UserRepository.php
<?php
declare(strict_types=1);
namespace App\Repository;
use PDO;
class UserRepository
{
public function __construct(private PDO $pdo) {}
/**
* @return array>
*/
public function all(): array
{
$stmt = $this->pdo->query('SELECT id, username, email FROM users');
return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
}
}
src/Controller/UserController.php
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Repository\UserRepository;
class UserController
{
public function __construct(private UserRepository $repo) {}
public function index(): void
{
header('Content-Type: application/json; charset=utf-8');
echo json_encode($this->repo->all(), JSON_UNESCAPED_UNICODE);
}
}
public/index.php
<?php
declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use App\Repository\UserRepository;
use App\Controller\UserController;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// Simple bootstrap / DI
$config = require __DIR__ . '/../config/database.php';
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler(__DIR__ . '/../logs/app.log', Logger::DEBUG));
$pdo = new PDO("sqlite:" . $config['database']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userRepo = new UserRepository($pdo);
$controller = new UserController($userRepo);
// Very minimal router
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
if ($path === '/users' && $method === 'GET') {
$controller->index();
exit;
}
http_response_code(404);
echo json_encode(['error' => 'Not found']);
Crear base de datos de ejemplo
-- script: data/init.sql
CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL, email TEXT NOT NULL);
INSERT INTO users (username, email) VALUES ('alice', 'alice@example.com'), ('bob', 'bob@example.com');
-- Crear DB desde línea de comandos:
-- sqlite3 data/app.sqlite < data/init.sql
8. Por qué esta arquitectura y decisiones
- PSR-4 y autoload facilitan testing y escalado del código.
- PDO + prepared statements protegen contra inyección SQL y funcionan con múltiples DBs.
- Separación Repo / Controller permite swap de capas (por ejemplo, reemplazar SQLite por MySQL o un ORM) sin tocar controladores.
- Monolog ofrece logging estructurado; útil para enviar a sistemas externos en producción.
9. Checklist antes de producción
- Configurar OPcache y parámetros de PHP-FPM (pm.max_children, etc.).
- Bloquear display_errors en producción y usar logs centralizados.
- Habilitar HTTPS y asegurar cabeceras HTTP.
- Agregar rate limiting y protección contra CSRF si hay formularios o sesiones.
- Revisar dependencias con Composer audit / herramientas de seguridad.
10. Herramientas recomendadas
- Static analysis: PHPStan o Psalm (subir el nivel progresivamente)
- Formatter: PHP CS Fixer o phpcs con reglas PSR-12
- Profiling: Xdebug (local), Blackfire o Tideways (producción)
Consejo avanzado: integra PHPStan/ Psalm en tu CI para bloquear merges con errores estáticos y configura thresholds incrementales. Advertencia: medir primero antes de habilitar JIT en producción; su mejora depende fuertemente del tipo de carga. Siguiente paso: implementa autenticación basada en tokens (JWT o introspección con OAuth2) y añade pruebas de integración para tus endpoints.
¿Quieres comentar?
Inicia sesión con Telegram para participar en la conversación