Modificadores de Acesso em Detalhes
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 39 de 91.
Agora que você entende os três modificadores de acesso, vamos explorar como eles se comportam em cenários de herança. O ponto principal é que os membros protected tornam-se acessíveis às classes filhas, enquanto os membros private permanecem ocultos mesmo para as filhas.
<?php
class Vehicle {
public $brand;
protected $engineType;
private $serialNumber;
public function __construct($brand, $engine, $serial) {
$this->brand = $brand;
$this->engineType = $engine;
$this->serialNumber = $serial;
}
private function getSerial() {
return $this->serialNumber;
}
protected function getEngineInfo() {
return $this->engineType;
}
}
class Car extends Vehicle {
public function getDetails() {
return $this->brand . " - " . $this->getEngineInfo();
// $this->serialNumber causaria um erro - privado!
// $this->getSerial() também falharia - método privado!
}
}
$car = new Car("Toyota", "V6", "ABC123");
echo $car->getDetails();
Saída:
Toyota - V6A classe Car pode acessar $brand (público) e chamar getEngineInfo() (protegido), mas não tem acesso a $serialNumber ou getSerial() porque eles são privados para Vehicle. Essa distinção permite que você compartilhe alguns detalhes internos com classes filhas, mantendo outros completamente ocultos.
Ponto Chave: Use protected quando as classes filhas precisarem de acesso a dados ou métodos internos, e private quando mesmo as classes filhas não devam tocar em certos detalhes de implementação.
Desafio
FácilVamos construir um sistema de gerenciamento de dispositivos que explora como os modificadores de acesso se comportam através da herança. Você criará uma classe base Device com propriedades em diferentes níveis de visibilidade e, em seguida, a estenderá com uma classe Smartphone que demonstra quais membros as classes filhas podem ou não acessar.
Você organizará seu código em três arquivos:
Device.php— Crie uma classeDeviceque represente dispositivos eletrônicos com níveis variados de sensibilidade de dados. Inclua:- Uma propriedade
public$brandpara o nome do fabricante - Uma propriedade
protected$modelNumberpara identificação interna - Uma propriedade
private$manufacturingCodepara dados exclusivos da fábrica
privategetManufacturingCode()que retorna o código de fabricação. Adicione um métodopublicgetModelInfo()que retorna"Model: [modelNumber]". Por fim, adicione um métodopublicgetFullCode()que retorna"[brand]-[manufacturingCode]"— isso demonstra como a própria classe pode acessar seus próprios membros privados.- Uma propriedade
Smartphone.php— Crie uma classeSmartphoneque estendaDevice. Inclua o arquivo Device. O construtor deve aceitar brand, modelNumber, manufacturingCode e o nome de um sistema operacional. Chame o construtor pai com os três primeiros valores e, em seguida, armazene o OS em uma propriedade privada. Adicione um método públicogetDeviceDetails()que retorna"[brand] [modelNumber] running [os]". Observe como você pode acessar o$brandpúblico diretamente e o$modelNumberprotegido, mas não pode acessar o$manufacturingCodeprivado diretamente — você precisaria usar o método público herdadogetFullCode()em vez disso.main.php— Inclua o arquivo Smartphone. Você receberá quatro entradas: um nome de marca, um número de modelo, um código de fabricação e um sistema operacional. Crie uma instância deSmartphonecom esses valores. Imprima três linhas:- O resultado da chamada de
getDeviceDetails() - O resultado da chamada do método herdado
getModelInfo() - O resultado da chamada do método herdado
getFullCode()
- O resultado da chamada de
Este desafio destaca a distinção fundamental: sua classe Smartphone pode usar livremente o $modelNumber protegido herdado de Device, mas o $manufacturingCode privado e o getManufacturingCode() permanecem completamente ocultos — acessíveis apenas através da interface pública que a Device escolhe expor.
Folha de consulta
Na herança, membros protected são acessíveis às classes filhas, enquanto membros private permanecem ocultos até mesmo para as filhas.
<?php
class Vehicle {
public $brand;
protected $engineType;
private $serialNumber;
public function __construct($brand, $engine, $serial) {
$this->brand = $brand;
$this->engineType = $engine;
$this->serialNumber = $serial;
}
private function getSerial() {
return $this->serialNumber;
}
protected function getEngineInfo() {
return $this->engineType;
}
}
class Car extends Vehicle {
public function getDetails() {
return $this->brand . " - " . $this->getEngineInfo();
// $this->serialNumber causaria um erro - private!
// $this->getSerial() também falharia - método privado!
}
}
$car = new Car("Toyota", "V6", "ABC123");
echo $car->getDetails(); // Toyota - V6
As classes filhas podem acessar:
- Propriedades e métodos
public - Propriedades e métodos
protected
As classes filhas não podem acessar:
- Propriedades e métodos
private(estes permanecem exclusivos da classe pai)
Melhor Prática: Use protected quando as classes filhas precisarem de acesso a dados ou métodos internos, e private quando nem mesmo as classes filhas devam tocar em certos detalhes de implementação.
Experimente você mesmo
<?php
require_once 'Smartphone.php';
// Ler as entradas
$brand = trim(fgets(STDIN));
$modelNumber = trim(fgets(STDIN));
$manufacturingCode = trim(fgets(STDIN));
$os = trim(fgets(STDIN));
// TODO: Criar uma instância de Smartphone com os valores de entrada
// TODO: Imprimir o resultado de getDeviceDetails()
// TODO: Imprimir o resultado do método herdado getModelInfo()
// TODO: Imprimir o resultado do método herdado getFullCode()
?>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