PHP (PHP: Hypertext Preprocessor) es un lenguaje de scripting de propósito general, especialmente orientado al desarrollo web del lado del servidor. Fue creado por Rasmus Lerdorf en 1994 y actualmente está mantenido por The PHP Group. La versión estable más reciente pertenece a la rama PHP 8.x.
PHP es un lenguaje multiparadigma. Soporta los siguientes paradigmas:
El paradigma original de PHP. El código se ejecuta de forma secuencial, instrucción a instrucción, y se organiza en funciones reutilizables.
<?php
function calcularIVA(float $precio): float {
return $precio * 0.21;
}
$precio = 100.0;
$iva = calcularIVA($precio);
echo "IVA: " . $iva; // IVA: 21
Introducida formalmente en PHP 5 y madurada en PHP 7/8. Soporta:
- Clases e instancias
- Herencia (extends)
- Interfaces (interface)
- Clases abstractas (abstract)
- Rasgos / Traits (trait)
- Encapsulación (public, protected, private)
- Polimorfismo
PHP incorpora características funcionales como:
- Funciones de primera clase
- Funciones anónimas (closures)
- Funciones flecha (fn =>)
- Funciones de orden superior (array_map, array_filter, array_reduce)
<?php
$numeros = [1, 2, 3, 4, 5];
$cuadrados = array_map(fn($n) => $n ** 2, $numeros);
// [1, 4, 9, 16, 25]
A través de frameworks como ReactPHP o Swoole, PHP puede manejar programación asíncrona y orientada a eventos, aunque no es nativa del núcleo del lenguaje.
| Característica | Descripción |
|---|---|
| Tipado | Débilmente tipado por defecto; tipado estricto opcional (declare(strict_types=1)) |
| Interpretado | Ejecutado por el intérprete PHP (Zend Engine) |
| Multiplataforma | Windows, Linux, macOS |
| Integración web | Nativo en HTML; soportado por Apache, Nginx, etc. |
| Extensible | Gran ecosistema de extensiones (PDO, cURL, GD, etc.) |
| Open Source | Licencia PHP License |
<?php
// Código PHP
?>
// Etiqueta corta de salida (equivale a <?php echo)
<?= "Hola mundo" ?>
Nota de examen: La etiqueta de cierre
?>es opcional al final de un archivo PHP puro. Se recomienda omitirla para evitar espacios en blanco involuntarios.
<?php
// Comentario de una línea
# También comentario de una línea
/*
Comentario
de varias líneas
*/
/**
* Comentario PHPDoc (documentación)
* @param string $nombre
* @return string
*/
Cada instrucción termina con punto y coma ;
<?php
$a = 1;
$b = 2;
echo $a + $b; // 3
Las variables en PHP comienzan siempre con el símbolo $.
<?php
$nombre = "Juan"; // string
$edad = 30; // integer
$precio = 19.99; // float
$activo = true; // boolean
$vacio = null; // null
Regla: Los nombres de variables son sensibles a mayúsculas/minúsculas (
$nombre≠$Nombre).
| Tipo | Ejemplo | Descripción |
|---|---|---|
int |
42, -7 |
Entero |
float / double |
3.14 |
Número decimal |
string |
"hola" |
Cadena de texto |
bool |
true, false |
Booleano |
null |
null |
Valor nulo |
array |
[1, 2, 3] |
Array |
object |
new Clase() |
Objeto |
resource |
fopen(...) |
Recurso externo |
callable |
function() {} |
Función invocable |
<?php
define('PI', 3.14159); // Forma clásica
const VERSION = '1.0.0'; // Forma moderna (desde PHP 5.3)
echo PI; // 3.14159
echo VERSION; // 1.0.0
<?php
$var = "42";
var_dump($var); // string(2) "42"
is_string($var); // true
is_int($var); // false
gettype($var); // "string"
// Conversión de tipos (casting)
$entero = (int) $var; // 42
$flotante = (float) $var; // 42.0
<?php
declare(strict_types=1);
function sumar(int $a, int $b): int {
return $a + $b;
}
sumar(1, 2); // OK: 3
sumar(1, "2"); // Error: TypeError
Las superglobales son variables predefinidas que están disponibles en todos los ámbitos del script, sin necesidad de declararlas como global.
$_GETContiene los parámetros enviados por la URL (método GET).
// URL: http://ejemplo.com/pagina.php?nombre=Juan&edad=30
$nombre = $_GET['nombre']; // "Juan"
$edad = $_GET['edad']; // "30"
$_POSTContiene los datos enviados mediante formulario HTTP (método POST).
$usuario = $_POST['usuario'];
$clave = $_POST['clave'];
$_REQUESTCombina $_GET, $_POST y $_COOKIE.
$dato = $_REQUEST['campo'];
$_SESSIONAlmacena datos de sesión del usuario.
session_start();
$_SESSION['usuario'] = 'admin';
echo $_SESSION['usuario']; // admin
$_COOKIEAccede a las cookies enviadas por el cliente.
setcookie('idioma', 'es', time() + 3600);
echo $_COOKIE['idioma']; // es
$_FILESContiene información sobre archivos subidos via formulario.
$nombre = $_FILES['archivo']['name'];
$tipo = $_FILES['archivo']['type'];
$tamaño = $_FILES['archivo']['size'];
$temporal = $_FILES['archivo']['tmp_name'];
$error = $_FILES['archivo']['error'];
$_SERVERInformación sobre el servidor y el entorno de ejecución.
| Variable | Descripción |
|---|---|
$_SERVER['PHP_SELF'] |
Nombre del script actual |
$_SERVER['SERVER_NAME'] |
Nombre del servidor |
$_SERVER['HTTP_HOST'] |
Cabecera Host de la petición |
$_SERVER['REQUEST_METHOD'] |
Método HTTP (GET, POST...) |
$_SERVER['REMOTE_ADDR'] |
IP del cliente |
$_SERVER['DOCUMENT_ROOT'] |
Directorio raíz del servidor |
$_SERVER['HTTP_USER_AGENT'] |
Agente de usuario del navegador |
$_ENVVariables de entorno del sistema operativo.
$path = $_ENV['PATH'];
$GLOBALSReferencia a todas las variables globales del script.
$x = 10;
function mostrar() {
echo $GLOBALS['x']; // 10
}
$a + $b // Suma
$a - $b // Resta
$a * $b // Multiplicación
$a / $b // División
$a % $b // Módulo
$a ** $b // Exponenciación (PHP 5.6+)
$a == $b // Igual (con conversión de tipo)
$a === $b // Idéntico (igual Y mismo tipo) ← IMPORTANTE
$a != $b // Diferente
$a !== $b // No idéntico
$a <=> $b // Spaceship: -1, 0, 1 (PHP 7+)
$a && $b // AND
$a || $b // OR
!$a // NOT
$a and $b // AND (menor precedencia)
$a or $b // OR (menor precedencia)
$a xor $b // XOR
$nombre = $_GET['nombre'] ?? 'Desconocido';
// Equivale a: isset($_GET['nombre']) ? $_GET['nombre'] : 'Desconocido'
$resultado = ($edad >= 18) ? 'Mayor' : 'Menor';
$a = 5;
$a += 3; // $a = 8
$a -= 2; // $a = 6
$a .= " texto"; // Concatenación y asignación
<?php
$nota = 7;
if ($nota >= 9) {
echo "Sobresaliente";
} elseif ($nota >= 7) {
echo "Notable";
} elseif ($nota >= 5) {
echo "Aprobado";
} else {
echo "Suspenso";
}
<?php
$dia = "lunes";
switch ($dia) {
case "lunes":
case "martes":
echo "Inicio de semana";
break;
case "viernes":
echo "Fin de semana laboral";
break;
default:
echo "Día normal";
}
<?php
$estado = 2;
$mensaje = match($estado) {
1 => "Activo",
2, 3 => "En proceso",
4 => "Finalizado",
default => "Desconocido"
};
// $mensaje = "En proceso"
Diferencia clave con
switch:matchusa comparación estricta (===), no realiza type coercion y lanzaUnhandledMatchErrorsi no hay coincidencia y no haydefault.
<?php
$i = 0;
while ($i < 5) {
echo $i . " ";
$i++;
}
// 0 1 2 3 4
<?php
$i = 0;
do {
echo $i . " ";
$i++;
} while ($i < 5);
// Se ejecuta al menos una vez aunque la condición sea falsa
<?php
for ($i = 0; $i < 5; $i++) {
echo $i . " ";
}
// 0 1 2 3 4
Especialmente útil para recorrer arrays:
<?php
// Array indexado
$frutas = ["manzana", "pera", "naranja"];
foreach ($frutas as $fruta) {
echo $fruta . "\n";
}
// Array asociativo
$persona = ["nombre" => "Ana", "edad" => 25];
foreach ($persona as $clave => $valor) {
echo "$clave: $valor\n";
}
break; // Sale del bucle
continue; // Salta a la siguiente iteración
break 2; // Sale de 2 niveles de bucles anidados
<?php
function saludar(string $nombre): string {
return "Hola, $nombre!";
}
echo saludar("María"); // Hola, María!
<?php
function conectar(string $host = 'localhost', int $puerto = 3306): string {
return "Conectando a $host:$puerto";
}
conectar(); // Conectando a localhost:3306
conectar('miservidor', 5432); // Conectando a miservidor:5432
<?php
function sumarTodos(int ...$numeros): int {
return array_sum($numeros);
}
echo sumarTodos(1, 2, 3, 4, 5); // 15
<?php
function incrementar(int &$valor): void {
$valor++;
}
$n = 5;
incrementar($n);
echo $n; // 6
<?php
$multiplicar = function(int $a, int $b): int {
return $a * $b;
};
echo $multiplicar(3, 4); // 12
// Con 'use' para capturar variables externas
$factor = 10;
$multiplicarPorFactor = function(int $n) use ($factor): int {
return $n * $factor;
};
<?php
$factor = 3;
$triplicar = fn($n) => $n * $factor; // Captura automáticamente $factor
echo $triplicar(5); // 15
<?php
function factorial(int $n): int {
if ($n <= 1) return 1;
return $n * factorial($n - 1);
}
echo factorial(5); // 120
<?php
function dividir(int $a, int $b): float|false {
if ($b === 0) return false;
return $a / $b;
}
// Tipo de retorno nulo (puede retornar null)
function buscar(int $id): ?string {
// ...
return null;
}
// void: la función no retorna nada
function registrar(string $msg): void {
// ...
}
strlen($str) // Longitud
strtolower($str) // Minúsculas
strtoupper($str) // Mayúsculas
trim($str) // Elimina espacios en extremos
ltrim / rtrim // Elimina espacios izquierda/derecha
str_replace($b, $n, $str) // Reemplaza $b por $n en $str
strpos($str, $sub) // Posición de $sub en $str (false si no existe)
substr($str, $inicio, $l) // Subcadena desde $inicio de longitud $l
explode($sep, $str) // Divide string en array
implode($sep, $arr) // Une array en string
sprintf("%.2f", 3.14159) // Formatea string
str_contains($str, $sub) // Contiene subcadena (PHP 8+)
str_starts_with / str_ends_with // PHP 8+
htmlspecialchars($str) // Escapa caracteres HTML (seguridad)
count($arr) // Número de elementos
array_push($arr, $val) // Añade al final
array_pop($arr) // Elimina el último
array_shift($arr) // Elimina el primero
array_unshift($arr, $val) // Añade al principio
array_merge($a, $b) // Fusiona arrays
array_slice($arr, $ini, $l)// Porción del array
array_splice($arr, $ini) // Elimina y reemplaza
in_array($val, $arr) // Comprueba si existe el valor
array_key_exists($k, $arr)// Comprueba si existe la clave
array_keys($arr) // Devuelve las claves
array_values($arr) // Devuelve los valores
array_unique($arr) // Elimina duplicados
sort / rsort / asort // Ordenación
usort($arr, $callback) // Ordenación con función personalizada
array_map($cb, $arr) // Aplica función a cada elemento
array_filter($arr, $cb) // Filtra por condición
array_reduce($arr, $cb) // Reduce a un valor
abs($n) // Valor absoluto
ceil($n) // Redondeo hacia arriba
floor($n) // Redondeo hacia abajo
round($n, $dec) // Redondeo
pow($base, $exp) // Potencia
sqrt($n) // Raíz cuadrada
max($a, $b) // Máximo
min($a, $b) // Mínimo
rand($min, $max) // Número aleatorio
mt_rand($min, $max) // Más eficiente
time() // Timestamp Unix actual
date('Y-m-d H:i:s') // Fecha formateada
mktime($h, $m, $s, $mes, $dia, $año) // Crear timestamp
strtotime('2024-01-01') // String a timestamp
date_create('2024-01-01') // Objeto DateTime
isset($var) // ¿Está definida y no es null?
empty($var) // ¿Está vacía?
is_null($var) // ¿Es null?
is_numeric($var) // ¿Es numérica?
filter_var($email, FILTER_VALIDATE_EMAIL) // Validación
filter_var($ip, FILTER_VALIDATE_IP)
<?php
class Animal {
// Propiedades
public string $nombre;
protected int $edad;
private float $peso;
// Constructor
public function __construct(string $nombre, int $edad, float $peso) {
$this->nombre = $nombre;
$this->edad = $edad;
$this->peso = $peso;
}
// Método público
public function describir(): string {
return "Soy {$this->nombre}, tengo {$this->edad} años.";
}
// Getter y Setter
public function getPeso(): float { return $this->peso; }
public function setPeso(float $p): void { $this->peso = $p; }
}
$perro = new Animal("Rex", 3, 15.5);
echo $perro->describir();
<?php
class Perro extends Animal {
private string $raza;
public function __construct(string $nombre, int $edad, float $peso, string $raza) {
parent::__construct($nombre, $edad, $peso);
$this->raza = $raza;
}
// Sobreescritura (override)
public function describir(): string {
return parent::describir() . " Soy un {$this->raza}.";
}
public function ladrar(): string {
return "¡Guau!";
}
}
<?php
// Clase abstracta: no puede instanciarse directamente
abstract class Figura {
abstract public function area(): float;
public function describir(): string {
return "Mi área es: " . $this->area();
}
}
// Interfaz: contrato de implementación
interface Dibujable {
public function dibujar(): void;
}
class Circulo extends Figura implements Dibujable {
public function __construct(private float $radio) {}
public function area(): float {
return M_PI * $this->radio ** 2;
}
public function dibujar(): void {
echo "Dibujando círculo de radio {$this->radio}";
}
}
<?php
trait Loggable {
public function log(string $mensaje): void {
echo "[LOG] " . date('Y-m-d H:i:s') . ": $mensaje\n";
}
}
class Servicio {
use Loggable;
public function ejecutar(): void {
$this->log("Servicio ejecutado");
}
}
<?php
class Contador {
private static int $instancias = 0;
public function __construct() {
self::$instancias++;
}
public static function getInstancias(): int {
return self::$instancias;
}
}
new Contador();
new Contador();
echo Contador::getInstancias(); // 2
| Método | Descripción |
|---|---|
__construct() |
Constructor |
__destruct() |
Destructor |
__toString() |
Representación como string |
__get($nombre) |
Acceso a propiedad no definida |
__set($nombre, $valor) |
Asignación a propiedad no definida |
__isset($nombre) |
isset() sobre propiedad no definida |
__call($nombre, $args) |
Llamada a método no definido |
__clone() |
Al clonar el objeto |
| Constante | Descripción |
|---|---|
E_ERROR |
Error fatal — detiene la ejecución |
E_WARNING |
Advertencia — no detiene la ejecución |
E_NOTICE |
Aviso informativo |
E_PARSE |
Error de análisis sintáctico |
E_ALL |
Todos los errores |
<?php
function dividir(int $a, int $b): float {
if ($b === 0) {
throw new InvalidArgumentException("División por cero");
}
return $a / $b;
}
try {
$resultado = dividir(10, 0);
} catch (InvalidArgumentException $e) {
echo "Error: " . $e->getMessage();
} catch (Exception $e) {
echo "Error genérico: " . $e->getMessage();
} finally {
echo "Esto siempre se ejecuta";
}
// Crear excepciones personalizadas
class MiExcepcion extends RuntimeException {
public function __construct(string $mensaje, int $codigo = 0) {
parent::__construct($mensaje, $codigo);
}
}
PHP dispone de cuatro formas de incluir archivos:
include 'funciones.php';
include 'ruta/al/archivo.php';
E_WARNING y la ejecución continúa.
require 'configuracion.php';
require 'ruta/al/archivo.php';
E_ERROR fatal y la ejecución se detiene.
include_once 'funciones.php';
require_once 'clases/Usuario.php';
| Función | Archivo no encontrado | Inclusión múltiple |
|---|---|---|
include |
E_WARNING — continúa |
Sí, múltiple |
require |
E_ERROR — detiene |
Sí, múltiple |
include_once |
E_WARNING — continúa |
Solo una vez |
require_once |
E_ERROR — detiene |
Solo una vez |
Regla para oposiciones: Usar
require_oncepara clases críticas y configuración;includepara componentes opcionales como plantillas.
include / include_once: PHP emite un error de nivel E_WARNING ("No such file or directory") pero el script sigue ejecutándose. Las funciones y clases del archivo omitido no estarán disponibles.require / require_once: PHP emite un error fatal E_ERROR y detiene completamente la ejecución del script. No se ejecuta ninguna instrucción posterior.// Ejemplo de comportamiento
include 'archivo_inexistente.php';
echo "Esto SÍ se ejecuta"; // include: se muestra
require 'archivo_inexistente.php';
echo "Esto NO se ejecuta"; // require: script detenido
Composer es el gestor de dependencias estándar de PHP (equivalente a npm en Node.js o pip en Python).
composer.json{
"require": {
"php": ">=8.1",
"monolog/monolog": "^3.0",
"guzzlehttp/guzzle": "^7.0"
},
"autoload": {
"psr-4": {
"MiApp\\": "src/"
}
}
}
composer install # Instala dependencias de composer.lock
composer update # Actualiza dependencias
composer require vendor/paquete # Añade una dependencia
composer remove vendor/paquete # Elimina una dependencia
composer dump-autoload # Regenera el autoloader
<?php
require_once 'vendor/autoload.php'; // ¡Solo esta línea!
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = new Logger('mi_app');
$log->pushHandler(new StreamHandler('app.log', Logger::WARNING));
$log->warning("Atención: algo ocurrió");
composer install/require, si el paquete no existe en Packagist (u otro repositorio), Composer lanza un error y no instala nada.vendor/, al instanciar la clase PHP lanza un Fatal error: Class not found.<?php
// Leer archivo completo
$contenido = file_get_contents('datos.txt');
// Escribir archivo
file_put_contents('salida.txt', "contenido");
file_put_contents('salida.txt', "más\n", FILE_APPEND); // Añadir
// Leer línea a línea
$lineas = file('datos.txt', FILE_IGNORE_NEW_LINES);
// Apertura manual
$f = fopen('archivo.txt', 'r'); // r=leer, w=escribir, a=añadir
while (!feof($f)) {
$linea = fgets($f);
}
fclose($f);
// Operaciones de sistema de ficheros
file_exists('ruta') // ¿Existe?
is_file('ruta') // ¿Es archivo?
is_dir('ruta') // ¿Es directorio?
mkdir('nueva_dir') // Crear directorio
unlink('archivo.txt') // Eliminar archivo
rename('viejo', 'nuevo') // Renombrar/mover
copy('origen', 'destino') // Copiar
<?php
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=mi_bd;charset=utf8',
'usuario',
'contraseña',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
// Consulta preparada (previene SQL Injection)
$stmt = $pdo->prepare("SELECT * FROM usuarios WHERE id = :id");
$stmt->execute(['id' => 1]);
$usuario = $stmt->fetch(PDO::FETCH_ASSOC);
// Inserción
$stmt = $pdo->prepare("INSERT INTO usuarios (nombre, email) VALUES (:nombre, :email)");
$stmt->execute(['nombre' => 'Ana', 'email' => 'ana@ejemplo.com']);
$ultimo_id = $pdo->lastInsertId();
} catch (PDOException $e) {
echo "Error de BD: " . $e->getMessage();
}
Para oposiciones: PDO es la interfaz preferida porque es independiente del motor de BD (MySQL, PostgreSQL, SQLite...) y usa consultas preparadas que previenen SQL Injection.
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Sanitización de entradas
$nombre = htmlspecialchars(trim($_POST['nombre'] ?? ''));
$email = filter_var($_POST['email'] ?? '', FILTER_SANITIZE_EMAIL);
// Validación
if (empty($nombre)) {
$errores[] = "El nombre es obligatorio";
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errores[] = "Email no válido";
}
if (empty($errores)) {
// Procesar datos seguros
}
}
| Vulnerabilidad | Protección en PHP |
|---|---|
| SQL Injection | Consultas preparadas con PDO |
| XSS | htmlspecialchars() al mostrar datos |
| CSRF | Tokens de sesión en formularios |
| Subida de archivos | Validar MIME type, extensión, tamaño |
| Contraseñas | password_hash() / password_verify() |
// Contraseñas seguras
$hash = password_hash($contraseña, PASSWORD_BCRYPT);
$ok = password_verify($contraseña, $hash); // true/false
<?php
session_start(); // Siempre antes de cualquier salida HTML
$_SESSION['usuario'] = 'admin';
$_SESSION['rol'] = 'editor';
// Verificar sesión
if (!isset($_SESSION['usuario'])) {
header('Location: login.php');
exit;
}
// Cerrar sesión
session_unset(); // Elimina todas las variables
session_destroy(); // Destruye la sesión
<?php
// Crear cookie (expira en 1 hora)
setcookie('tema', 'oscuro', time() + 3600, '/', '', true, true);
// path, secure, httpOnly
// Leer cookie
$tema = $_COOKIE['tema'] ?? 'claro';
// Eliminar cookie (expira en el pasado)
setcookie('tema', '', time() - 1);
Los namespaces organizan el código y evitan colisiones de nombres.
<?php
namespace MiApp\Modelos;
class Usuario {
public function __construct(
private string $nombre,
private string $email
) {}
}
<?php
// Uso desde otro archivo
use MiApp\Modelos\Usuario;
use MiApp\Servicios\AutenticacionServicio as Auth;
$usuario = new Usuario("Juan", "juan@ejemplo.com");
$auth = new Auth();
function procesar(int|string $valor): int|string { ... }
array_slice(array: $arr, offset: 2, length: 3);
#[Route('/inicio', methods: ['GET'])]
public function inicio(): Response { ... }
class Punto {
public function __construct(
public float $x,
public float $y,
public float $z = 0.0
) {}
}
$fiber = new Fiber(function(): void {
$valor = Fiber::suspend('primer valor');
echo "Valor recibido: $valor";
});
$resultado = $fiber->start(); // "primer valor"
$fiber->resume('segundo valor'); // "Valor recibido: segundo valor"
enum Estado: string {
case Activo = 'activo';
case Inactivo = 'inactivo';
case Borrado = 'borrado';
}
$e = Estado::Activo;
echo $e->value; // 'activo'
class Punto {
public function __construct(
public readonly float $x,
public readonly float $y
) {}
}
| Concepto | Dato clave |
|---|---|
| Paradigmas | Multiparadigma: procedimental, OOP, funcional |
| Variables | Siempre comienzan con $; sensibles a mayúsculas |
| Tipos | Tipado débil por defecto; estricto con declare(strict_types=1) |
| Superglobales | $_GET, $_POST, $_SESSION, $_SERVER, $_FILES, $_COOKIE, $_ENV, $GLOBALS |
| include vs require | include → E_WARNING; require → E_ERROR fatal |
_once |
Evita inclusiones duplicadas → útil para clases |
| PDO | Interfaz BD recomendada; soporta consultas preparadas |
| Seguridad | htmlspecialchars, password_hash, PDO prepared statements |
| Composer | Gestor de dependencias; vendor/autoload.php |
| PHP 8 | match, enum, readonly, named args, union types, fibers |
| OOP | extends, implements, abstract, interface, trait |
| Excepciones | try / catch / finally; throw new Excepcion() |
Documento elaborado para preparación de oposiciones — PHP 8.x