PHP
Tutorial PHP: Constructores y destructores
Aprende a usar PHP métodos __construct() y __destruct() para inicializar y destruir objetos eficazmente, optimizando aplicaciones.
Aprende PHP y certifícateMétodo __construct()
El método __construct() es la función especial que PHP utiliza como constructor de una clase. Se invoca automáticamente al crear una nueva instancia, permitiendo inicializar propiedades o ejecutar código necesario antes de que el objeto sea usado.
En PHP, se define el constructor dentro de una clase utilizando el nombre __construct()
. A continuación, se muestra un ejemplo básico:
<?php
class Usuario
{
public $nombre;
public function __construct($nombre)
{
$this->nombre = $nombre;
echo "Usuario {$this->nombre} creado.\n";
}
}
$usuario = new Usuario("María");
En este ejemplo, al crear un nuevo objeto de la clase Usuario
, el constructor recibe un parámetro $nombre
y lo asigna a la propiedad $nombre
. Además, imprime un mensaje indicando que el usuario ha sido creado.
El constructor puede aceptar tantos parámetros como sean necesarios para inicializar el objeto. Esto permite pasar valores personalizados al crear instancias de la clase.
Es posible definir valores por defecto en los parámetros del constructor. Por ejemplo:
<?php
class Producto
{
public $nombre;
public $precio;
public function __construct($nombre = "Producto Genérico", $precio = 0.0)
{
$this->nombre = $nombre;
$this->precio = $precio;
echo "Producto {$this->nombre} con precio {$this->precio} creado.\n";
}
}
$producto = new Producto();
$productoPersonalizado = new Producto("Libro", 15.99);
En este caso, si no se proporcionan argumentos al crear un nuevo Producto
, se utilizarán los valores por defecto. Esto aporta flexibilidad en la inicialización de objetos.
Cuando se trabaja con herencia, el constructor de la clase hija puede llamar al constructor de la clase padre utilizando parent::__construct()
. Esto es útil para asegurar que las propiedades heredadas se inicialicen correctamente. Ejemplo:
<?php
class Vehiculo
{
public $marca;
public function __construct($marca)
{
$this->marca = $marca;
echo "Vehículo de marca {$this->marca} creado.\n";
}
}
class Coche extends Vehiculo
{
public $modelo;
public function __construct($marca, $modelo)
{
parent::__construct($marca);
$this->modelo = $modelo;
echo "Coche modelo {$this->modelo} creado.\n";
}
}
$coche = new Coche("Toyota", "Corolla");
En este ejemplo, Coche
extiende de Vehiculo
y su constructor llama a parent::__construct($marca)
para inicializar la propiedad $marca
.
A partir de PHP 8.0, se introdujo la promoción de propiedades del constructor, que permite declarar y asignar propiedades directamente en la firma del constructor. Esto simplifica el código y mejora su legibilidad:
<?php
class Punto
{
public function __construct(
public float $x = 0.0,
public float $y = 0.0
) {
echo "Punto en coordenadas ({$this->x}, {$this->y}) creado.\n";
}
}
$punto = new Punto(5.5, 10.2);
Aquí, las propiedades $x
y $y
se declaran y asignan en el constructor, reduciendo la cantidad de código necesario.
El método __construct() es esencial para asegurar que los objetos se crean en un estado válido y listo para su uso. Al inicializar correctamente las propiedades y ejecutar cualquier lógica necesaria, se mejora la confiabilidad y consistencia de las aplicaciones desarrolladas en PHP.
Método __destruct()
El método __destruct() es una función especial en PHP que actúa como destructor de una clase. Se invoca automáticamente cuando un objeto es destruido o liberado de la memoria, permitiendo ejecutar código de limpieza o liberar recursos antes de que el objeto deje de existir.
El destructor se define dentro de una clase utilizando el nombre __destruct()
, sin parámetros. A continuación, se muestra un ejemplo básico:
<?php
class ArchivoTemporal
{
private $ruta;
public function __construct($nombre)
{
$this->ruta = "/tmp/{$nombre}";
file_put_contents($this->ruta, "Contenido temporal\n");
echo "Archivo temporal {$this->ruta} creado.\n";
}
public function __destruct()
{
if (file_exists($this->ruta)) {
unlink($this->ruta);
echo "Archivo temporal {$this->ruta} eliminado.\n";
}
}
}
$archivo = new ArchivoTemporal("datos.txt");
echo "Procesando el archivo temporal...\n";
En este ejemplo, la clase ArchivoTemporal
crea un archivo en el constructor y lo elimina en el destructor. Al finalizar el script o cuando el objeto es destruido, el método __destruct()
se ejecuta automáticamente, garantizando que el archivo temporal se elimine.
El destructor es útil para liberar recursos externos como archivos, conexiones de base de datos o sockets de red. Esto ayuda a prevenir fugas de recursos y asegura que los recursos se limpien adecuadamente.
Es importante tener en cuenta que el destructor se invoca en los siguientes casos:
- Cuando el script termina su ejecución.
- Cuando se elimina el último referente al objeto (por ejemplo, al asignar
null
a la variable). - Cuando el objeto se sale de su alcance (en entornos sin recolector de basura).
Otro ejemplo común es el cierre de conexiones de base de datos:
<?php
class ConexionBD
{
private $conexion;
public function __construct($dsn, $usuario, $contraseña)
{
try {
$this->conexion = new PDO($dsn, $usuario, $contraseña);
echo "Conexión a la base de datos establecida.\n";
} catch (PDOException $e) {
echo "Error de conexión: " . $e->getMessage() . "\n";
}
}
public function __destruct()
{
$this->conexion = null;
echo "Conexión a la base de datos cerrada.\n";
}
}
$bd = new ConexionBD('mysql:host=localhost;dbname=test', 'root', 'password');
// Operaciones con la base de datos
En este caso, el destructor asigna null
a la propiedad $conexion
, cerrando la conexión a la base de datos. Esto es especialmente útil en scripts largos o aplicaciones que manejan múltiples conexiones.
Es posible forzar la ejecución del destructor antes del final del script destruyendo el objeto manualmente:
<?php
$recurso = new RecursoExterno();
// Uso del recurso
unset($recurso); // El destructor se ejecuta aquí
echo "El objeto ha sido destruido.\n";
Al utilizar unset($recurso)
, se elimina la referencia al objeto y el destructor se ejecuta inmediatamente. Esto es útil cuando se necesita liberar recursos en un punto específico del código.
En el contexto de herencia, si una clase hija define un destructor, es aconsejable llamar al destructor de la clase padre para asegurar que todos los recursos se liberen correctamente:
<?php
class Logger
{
protected $archivo;
public function __construct($ruta)
{
$this->archivo = fopen($ruta, 'a');
}
public function __destruct()
{
fclose($this->archivo);
echo "Archivo de log cerrado.\n";
}
}
class LoggerDetallado extends Logger
{
public function __destruct()
{
// Acciones adicionales antes de cerrar
echo "Escribiendo resumen final.\n";
parent::__destruct();
}
}
$logger = new LoggerDetallado("app.log");
// Registro de eventos
En este ejemplo, LoggerDetallado
sobrescribe el destructor para realizar acciones adicionales y luego llama a parent::__destruct()
para asegurar que el archivo de log se cierre apropiadamente.
Es esencial utilizar el método __destruct() cuando se manejan recursos que no son gestionados automáticamente por PHP, como conexiones o archivos abiertos. De esta manera, se garantiza que la aplicación maneje los recursos de forma eficiente y segura.
Inicialización de propiedades
La inicialización de propiedades en una clase PHP es un paso crucial para garantizar que los objetos comiencen en un estado consistente y válido. Existen varias formas de asignar valores iniciales a las propiedades, más allá del constructor, aprovechando características del lenguaje que aportan claridad y eficiencia al código.
Una forma común de inicializar propiedades es asignando valores por defecto en su declaración dentro de la clase. Esto permite establecer un estado inicial sin necesidad de incluir lógica adicional en el constructor:
<?php
class Configuracion
{
public string $idioma = 'es';
public int $elementosPorPagina = 10;
public bool $modoOscuro = false;
}
$config = new Configuracion();
echo "Idioma: {$config->idioma}\n";
echo "Elementos por página: {$config->elementosPorPagina}\n";
echo "Modo oscuro: " . ($config->modoOscuro ? 'Activado' : 'Desactivado') . "\n";
En este ejemplo, las propiedades $idioma
, $elementosPorPagina
y $modoOscuro
tienen valores iniciales asignados directamente en su declaración. Al crear una instancia de Configuracion
, estos valores están disponibles inmediatamente sin necesidad de un constructor.
Con la introducción de los tipos de propiedad en PHP 7.4, es posible declarar el tipo de las propiedades y asignarles valores por defecto que sean compatibles con dichos tipos. Esto mejora la seguridad y la legibilidad del código:
<?php
class Usuario
{
public string $nombre = 'Anónimo';
public ?string $email = null;
public array $roles = [];
}
$usuario = new Usuario();
echo "Nombre: {$usuario->nombre}\n";
echo "Email: " . ($usuario->email ?? 'No asignado') . "\n";
echo "Roles: " . implode(', ', $usuario->roles) . "\n";
Aquí, las propiedades tipadas garantizan que los valores asignados sean del tipo especificado, y los valores por defecto proporcionan un estado inicial consistente.
Las propiedades estáticas también pueden ser inicializadas en su declaración. Dado que pertenecen a la clase y no a las instancias, es útil para valores compartidos entre todos los objetos de la misma clase:
<?php
class Sesion
{
public static int $usuariosActivos = 0;
public function __construct()
{
self::$usuariosActivos++;
echo "Nuevo usuario inició sesión. Total: " . self::$usuariosActivos . "\n";
}
public function __destruct()
{
self::$usuariosActivos--;
echo "Un usuario cerró sesión. Total: " . self::$usuariosActivos . "\n";
}
}
$sesion1 = new Sesion();
$sesion2 = new Sesion();
unset($sesion1);
En este caso, la propiedad estática $usuariosActivos
se inicializa a 0
y se incrementa o decrementa según se creen o destruyan instancias de Sesion
. Esto permite llevar un conteo global de usuarios activos.
La inicialización tardía de propiedades puede ser útil cuando el valor inicial depende de una condición o cálculo complejo. En lugar de asignar el valor en la declaración o en el constructor, se puede utilizar un método específico o un getter con lazy loading:
<?php
class Reporte
{
private ?array $datos = null;
public function obtenerDatos(): array
{
if ($this->datos === null) {
echo "Cargando datos...\n";
$this->datos = $this->cargarDatos();
}
return $this->datos;
}
private function cargarDatos(): array
{
// Simulación de carga de datos intensiva
sleep(2);
return ['ventas' => 1000, 'ingresos' => 50000];
}
}
$reporte = new Reporte();
$datos = $reporte->obtenerDatos();
echo "Ventas: {$datos['ventas']}\n";
echo "Ingresos: {$datos['ingresos']}\n";
Con este enfoque, la propiedad $datos
se inicializa solo cuando es necesaria, optimizando el uso de recursos. La inicialización tardía es especialmente beneficiosa cuando el proceso de obtención del valor es costoso en términos de tiempo o recursos.
Es importante mencionar que, a partir de PHP 8.1, se introdujeron las propiedades de solo lectura utilizando la palabra clave readonly
. Estas propiedades deben ser inicializadas en la declaración o en el constructor, ya que no pueden modificarse posteriormente:
<?php
class Pedido
{
public readonly int $numero;
public readonly DateTime $fecha;
public function __construct(int $numero)
{
$this->numero = $numero;
$this->fecha = new DateTime();
}
}
$pedido = new Pedido(12345);
echo "Pedido Nº {$pedido->numero} realizado el {$pedido->fecha->format('d-m-Y H:i')}\n";
Las propiedades readonly
garantizan que su valor no cambiará una vez asignado, aportando mayor integridad al estado del objeto.
En situaciones donde se requiere validación o procesamiento adicional al asignar valores a las propiedades, es recomendable utilizar métodos setters. Esto permite centralizar la lógica y asegurar que las propiedades reciben valores válidos:
<?php
class CuentaBancaria
{
private float $saldo = 0.0;
public function depositar(float $monto): void
{
if ($monto <= 0) {
throw new InvalidArgumentException("El monto a depositar debe ser positivo.\n");
}
$this->saldo += $monto;
echo "Depósito de {$monto} realizado. Saldo actual: {$this->saldo}\n";
}
public function obtenerSaldo(): float
{
return $this->saldo;
}
}
$cuenta = new CuentaBancaria();
$cuenta->depositar(100.50);
echo "Saldo final: {$cuenta->obtenerSaldo()}\n";
Al encapsular la inicialización y modificación de la propiedad $saldo
, se asegura que el objeto CuentaBancaria
mantiene un estado coherente y seguro.
Por último, es buena práctica combinar diferentes métodos de inicialización para lograr un código limpio y mantenible. La elección entre inicializar una propiedad en su declaración, en el constructor, o mediante métodos específicos dependerá del contexto y las necesidades de la aplicación.
La correcta inicialización de propiedades es fundamental para el diseño de clases robustas y fiables en PHP. Al aprovechar las características del lenguaje y aplicar buenas prácticas, se contribuye al desarrollo de aplicaciones más seguras y eficientes.
Todas las lecciones de PHP
Accede a todas las lecciones de PHP y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Php
Introducción Y Entorno
Instalación Y Primer Programa De Php
Introducción Y Entorno
Tipos De Datos, Variables Y Constantes
Sintaxis
Operadores Y Expresiones
Sintaxis
Estructuras De Control
Sintaxis
Funciones Y Llamada De Funciones
Sintaxis
Cadenas De Texto Y Manipulación
Sintaxis
Manejo De Números
Sintaxis
Manejo De Fechas Y Tiempo
Sintaxis
Manejo De Arrays
Sintaxis
Introducción A La Poo En Php
Programación Orientada A Objetos
Clases Y Objetos
Programación Orientada A Objetos
Constructores Y Destructores
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Interfaces
Programación Orientada A Objetos
Traits
Programación Orientada A Objetos
Namespaces
Programación Orientada A Objetos
Autoloading De Clases
Programación Orientada A Objetos
Manejo De Errores Y Excepciones
Programación Orientada A Objetos
Manejo De Archivos
Programación Orientada A Objetos
Patrones De Diseño
Programación Orientada A Objetos
Introducción A Los Formularios En Php
Formularios
Procesamiento De Datos De Formularios
Formularios
Manejo De Archivos En Formularios
Formularios
Redirecciones Y Retroalimentación Al Usuario
Formularios
Formularios Dinámicos Y Separación De Lógica
Formularios
Introducción A La Persistencia En Php
Persistencia
Conexión A Bases De Datos
Persistencia
Consultas Y Operaciones Crud
Persistencia
Gestión De Transacciones
Persistencia
Manejo De Errores Y Excepciones En Base De Datos
Persistencia
Patrones De Acceso A Datos
Persistencia
Concepto De Sesiones En Php
Sesiones Y Cookies
Configuración De Sesiones
Sesiones Y Cookies
Cookies
Sesiones Y Cookies
Manejo Avanzado De Sesiones Y Cookies
Sesiones Y Cookies
Principales Vulnerabilidades En Php
Seguridad
Seguridad En Formularios Y Entrada De Datos
Seguridad
Protección Frente A Inyección Sql
Seguridad
Gestión De Contraseñas Y Cifrado
Seguridad
Seguridad En Sesiones Y Cookies
Seguridad
Configuraciones De Php Para Seguridad
Seguridad
Introducción Al Testing En Php
Testing
Phpunit
Testing
Cobertura De Código En Testing
Testing
Test Doubles (Mocks, Stubs, Fakes, Spies)
Testing
Pruebas De Integración Y Funcionales
Testing
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender el propósito del método __construct() y su uso.
- Aprender cómo se inicializan las propiedades de una clase en PHP.
- Entender el método __destruct() y su rol en la gestión de recursos.
- Aplicar promociones de propiedades del constructor desde PHP 8.0.
- Conocer el significado de propiedades readonly introducidas en PHP 8.1.
- Implementar buenas prácticas para asegurar estados válidos al crear y destruir objetos.