A Palavra-chave final
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 24 de 91.
Embora a herança e a sobrescrita de métodos ofereçam flexibilidade, às vezes você precisa evitar que certas classes ou métodos sejam alterados. A palavra-chave final bloqueia seu código, garantindo que implementações específicas não possam ser alteradas por classes filhas.
Quando você marca um método como final, nenhuma classe filha pode sobrescrevê-lo:
<?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();
Saída:
ACC-1O método getAccountId() não pode ser sobrescrito em SavingsAccount ou em qualquer outra classe filha. Isso protege a funcionalidade crítica que deve permanecer consistente em todos os tipos de conta.
Você também pode marcar uma classe inteira como final para evitar qualquer herança:
<?php
final class SecurityManager {
public function authenticate($user) {
return "Authenticating $user";
}
}
$security = new SecurityManager();
echo $security->authenticate("admin");
Saída:
Authenticating adminNenhuma classe pode estender SecurityManager. Isso é útil para classes sensíveis à segurança ou quando o design da classe está completo e não deve ser modificado.
Ponto Chave: Use final em métodos para evitar a sobrescrita enquanto ainda permite a herança, ou em classes para impedir a herança completamente. É uma ferramenta para proteger código crítico que deve funcionar exatamente como projetado.
Desafio
FácilVamos construir um sistema de gerenciamento de documentos que demonstra como a palavra-chave final protege funcionalidades críticas de serem modificadas por classes filhas.
Você criará três arquivos que trabalham juntos para gerenciar diferentes tipos de documentos, garantindo que certos recursos de segurança permaneçam bloqueados:
Document.php— Defina uma classeDocumentque serve como base para todos os documentos. Ela deve ter uma propriedade pública$titlee uma propriedade protegida$author. O construtor aceita tanto o título quanto o autor. Inclua um métodofinalchamadogetSignature()que retorna"Signed by: "seguido pelo autor — este recurso de segurança nunca deve ser alterado por classes filhas. Adicione também um método regulargetContent()que retorna"Document: "seguido pelo título.Report.php— Defina uma classeReportque estendeDocument. Inclua o arquivo Document no topo. Esta classe adiciona uma propriedade$department. O construtor deve aceitar título, autor e departamento — useparent::__construct()para os dois primeiros e, em seguida, defina o departamento. Sobrescreva o métodogetContent()para retornar"Report: "seguido pelo título e o departamento entre parênteses, no formato"Report: [title] ([department])". A classeReportherda o método finalgetSignature()sem poder alterá-lo.main.php— Inclua o arquivo Report. Você receberá três entradas: o título do documento, o nome do autor e o departamento. Crie um objetoReportcom esses valores. Imprima o resultado degetContent()na primeira linha e, em seguida, imprima o resultado degetSignature()na segunda linha.
Este desafio mostra como os métodos final protegem funcionalidades críticas — a geração da assinatura permanece consistente em todos os tipos de documentos, enquanto outros métodos como getContent() podem ser personalizados por cada classe filha. O Report pode alterar como o conteúdo é exibido, mas o formato da assinatura está bloqueado na classe pai.
Folha de consulta
A palavra-chave final impede que classes ou métodos sejam modificados por classes filhas.
Métodos Finais: Marque um método como final para evitar que classes filhas o sobrescrevam:
<?php
class BankAccount {
protected $balance;
final public function getAccountId() {
return "ACC-" . spl_object_id($this);
}
}
class SavingsAccount extends BankAccount {
// Cannot override getAccountId()
}
Classes Finais: Marque uma classe inteira como final para impedir qualquer herança:
<?php
final class SecurityManager {
public function authenticate($user) {
return "Authenticating $user";
}
}
// No class can extend SecurityManager
Use final em métodos para proteger funcionalidades específicas enquanto permite a herança, ou em classes para impedir a herança inteiramente. Isso é útil para códigos sensíveis à segurança ou quando as implementações devem permanecer consistentes.
Experimente você mesmo
<?php
require_once 'Report.php';
// Ler entrada
$title = trim(fgets(STDIN));
$author = trim(fgets(STDIN));
$department = trim(fgets(STDIN));
// TODO: Criar um objeto Report com os valores de entrada
// TODO: Imprimir o resultado de getContent()
// TODO: Imprimir o resultado de getSignature()
?>Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodoA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em DetalhesGetters e SettersOcultação de InformaçãoPromoção de Construtor (8.0)Recapitulação - Sistema de Registro de Alunos10Conceitos Avançados de POO
Composição vs HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibers (PHP 8.1)Mergulho Profundo em Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA Palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto Organizado5Interfaces e Contratos
Introdução a InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataType Hinting com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos AnuláveisTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadasTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário3Propriedades de Classe
Propriedades de Instância vs EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Readonly (PHP 8.1)Recapitulação - Gerenciador de Conta Bancária6Polimorfismo
Sobrescrita de Métodos RevisitadaPolimorfismo via InterfacesType Hinting e Union TypesLate Static BindingRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos de TraitsMétodos Abstratos em TraitsTraits vs Herança12Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy