Menu
Coddy logo textTech

La palabra clave final

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 24 de 91.

Si bien la herencia y la sobrescritura de métodos proporcionan flexibilidad, a veces es necesario evitar que ciertas clases o métodos sean modificados. La palabra clave final bloquea el código, asegurando que implementaciones específicas no puedan ser alteradas por clases hijas.

Cuando marcas un método como final, ninguna clase hija puede sobrescribirlo:

<?php
class BankAccount {
    protected $balance;
    
    public function __construct($balance) {
        $this->balance = $balance;
    }
    
    final public function getAccountId() {
        return "ACC-" . spl_object_id($this);
    }
}

class SavingsAccount extends BankAccount {
    public function addInterest() {
        return $this->balance * 0.05;
    }
}

$account = new SavingsAccount(1000);
echo $account->getAccountId();

Salida:

ACC-1

El método getAccountId() no puede ser sobrescrito en SavingsAccount o cualquier otra clase hija. Esto protege la funcionalidad crítica que debe permanecer consistente en todos los tipos de cuenta.

También puedes marcar una clase entera como final para evitar cualquier herencia:

<?php
final class SecurityManager {
    public function authenticate($user) {
        return "Authenticating $user";
    }
}

$security = new SecurityManager();
echo $security->authenticate("admin");

Salida:

Authenticating admin

Ninguna clase puede extender SecurityManager. Esto es útil para clases sensibles a la seguridad o cuando el diseño de la clase está completo y no debería modificarse.

Punto clave: Utiliza final en métodos para evitar la sobrescritura mientras se permite la herencia, o en clases para evitar la herencia por completo. Es una herramienta para proteger código crítico que debe funcionar exactamente como fue diseñado.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de gestión de documentos que demuestre cómo la palabra clave final protege la funcionalidad crítica de ser modificada por las clases hijas.

Crearás tres archivos que trabajan juntos para gestionar diferentes tipos de documentos, asegurando al mismo tiempo que ciertas características de seguridad permanezcan bloqueadas:

  • Document.php — Define una clase Document que sirva como base para todos los documentos. Debe tener una propiedad pública $title y una propiedad protegida $author. El constructor acepta tanto el título como el autor. Incluye un método final llamado getSignature() que devuelva "Signed by: " . $this->author — esta característica de seguridad nunca debe ser alterada por las clases hijas. También añade un método regular getContent() que devuelva "Document: " . $this->title.
  • Report.php — Define una clase Report que extienda de Document. Incluye el archivo Document al principio. Esta clase añade una propiedad $department. El constructor debe aceptar el título, el autor y el departamento — utiliza parent::__construct() para los dos primeros, luego establece el departamento. Sobrescribe el método getContent() para que devuelva "Report: " . $this->title . " (" . $this->department . ")". La clase Report hereda el método final getSignature() sin poder cambiarlo.
  • main.php — Incluye el archivo Report. Recibirás tres entradas: el título del documento, el nombre del autor y el departamento. Crea un objeto Report con estos valores. Imprime el resultado de getContent() en la primera línea, luego imprime el resultado de getSignature() en la segunda línea.

Este desafío muestra cómo los métodos final protegen la funcionalidad crítica — la generación de la firma permanece consistente en todos los tipos de documentos, mientras que otros métodos como getContent() pueden ser personalizados por cada clase hija. El Report puede cambiar cómo se muestra el contenido, pero el formato de la firma está bloqueado en la clase padre.

Hoja de referencia

La palabra clave final evita que las clases o los métodos sean modificados por clases hijas.

Métodos Finales: Marque un método como final para evitar que las clases hijas lo sobrescriban:

<?php
class BankAccount {
    protected $balance;
    
    final public function getAccountId() {
        return "ACC-" . spl_object_id($this);
    }
}

class SavingsAccount extends BankAccount {
    // Cannot override getAccountId()
}

Clases Finales: Marque una clase completa como final para evitar cualquier herencia:

<?php
final class SecurityManager {
    public function authenticate($user) {
        return "Authenticating $user";
    }
}

// Ninguna clase puede extender SecurityManager

Use final en los métodos para proteger una funcionalidad específica mientras permite la herencia, o en las clases para evitar la herencia por completo. Esto es útil para código sensible a la seguridad o cuando las implementaciones deben permanecer consistentes.

Pruébalo tú mismo

<?php
require_once 'Report.php';

// Leer entrada
$title = trim(fgets(STDIN));
$author = trim(fgets(STDIN));
$department = trim(fgets(STDIN));

// TODO: Crear un objeto Report con los valores de entrada

// TODO: Imprimir el resultado de getContent()

// TODO: Imprimir el resultado de getSignature()
?>
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos