Visibilidade
A visibilidade de uma propriedade ou método ou constante pode ser definida prefixando a
declaração com as palavras-chave public
,
protected
ou
private
. Membros de classes declarados como públicos podem ser
acessados de qualquer lugar. Membros declarados como protegidos pode ser acessados
na própria classe ou de classes referenciadas por herança
acima. Membros declarados como privados só podem ser acessados por classes
que definem esse membro.
Visibilidade de propriedades
Propriedades de classes podem ser declarados como públicas, privadas ou protegidas. Propriedades declaradas sem visibilidade são definidas como públicas.
Example #1 Declaração de propriedade
<?php
/**
* Define MinhaClasse
*/
class MinhaClasse
{
public $publica = 'Public';
protected $protegida = 'Protected';
private $privada = 'Private';
function imprimeAlo()
{
echo $this->publica;
echo $this->protegida;
echo $this->privada;
}
}
$obj = new MinhaClasse();
echo $obj->publica; // Funciona
echo $obj->protegida; // Erro Fatal
echo $obj->privada; // Erro Fatal
$obj->imprimeAlo(); // Mostra Public, Protected e Private
/**
* Define MinhaClasse2
*/
class MinhaClasse2 extends MinhaClasse
{
// Nós podemos redeclarar as propriedades públicas e protegidas mas não as privadas
public $publica = 'Public2';
protected $protegida = 'Protected2';
function imprimeAlo()
{
echo $this->publica;
echo $this->protegida;
echo $this->privada;
}
}
$obj2 = new MinhaClasse2();
echo $obj2->publica; // Funciona
echo $obj2->protegida; // Erro fatal
echo $obj2->privada; // Não definida
$obj2->imprimeAlo(); // Mostra Public, Protected2, Undefined
?>
Visibilidade de propriedade assimétrica
A partir do PHP 8.4, as propriedades também podem ter sua
visibilidade definida de forma assimétrica, com escopo diferente para
leitura (get
) e escrita (set
).
Especificamente, a visibilidade set
pode ser
especificada separadamente, desde que não seja mais permissiva que a
visibilidade padrão.
Example #2 Visibilidade de propriedade assimétrica
<?php
class Book
{
public function __construct(
public private(set) string $title,
public protected(set) string $author,
protected private(set) int $pubYear,
) {}
}
class SpecialBook extends Book
{
public function update(string $author, int $year): void
{
$this->author = $author; // OK
$this->pubYear = $year; // Erro fatal
}
}
$b = new Book('How to PHP', 'Peter H. Peterson', 2024);
echo $b->title; // Funciona
echo $b->author; // Funciona
echo $b->pubYear; // Erro fatal
$b->title = 'How not to PHP'; // Erro fatal
$b->author = 'Pedro H. Peterson'; // Erro fatal
$b->pubYear = 2023; // Erro fatal
?>
Existem algumas advertências em relação à visibilidade assimétrica:
-
Somente propriedades tipadas podem ter uma visibilidade
set
separada. -
A visibilidade
set
deve ser a mesma deget
ou mais restritiva. Ou seja,public protected(set)
eprotected protected(set)
são permitidos, masprotected public(set)
causará um erro de sintaxe. -
Se uma propriedade for
public
, a visibilidade principal poderá ser omitida. Ou seja,public private(set)
eprivate(set)
terão o mesmo resultado. -
Uma propriedade com visibilidade
private(set)
é automaticamentefinal
e não pode ser declarada novamente em uma classe filha. -
A obtenção de uma referência para uma propriedade segue a visibilidade
set
, nãoget
. Isso ocorre porque uma referência pode ser usada para modificar o valor da propriedade. -
Da mesma forma, tentar escrever em uma propriedade de array envolve uma operação
get
eset
internamente e, portanto, seguirá a visibilidadeset
, como é sempre a mais restritiva.
Quando uma classe estende outra, a classe filha pode redefinir
qualquer propriedade que não seja final
. Ao fazer isso,
pode ampliar a visibilidade principal ou a visibilidade set
,
desde que a nova visibilidade seja igual ou mais ampla
que a classe pai. Entretanto, esteja ciente de que se uma propriedade private
for substituída, ela na verdade não altera a propriedade da classe pai,
mas cria uma nova propriedade com um nome interno diferente.
Example #3 Herança de propriedade assimétrica
<?php
class Book
{
protected string $title;
public protected(set) string $author;
protected private(set) int $pubYear;
}
class SpecialBook extends Book
{
public protected(set) $title; // OK, pois a leitura é mais ampla e a escrita igual.
public string $author; // OK, pois a leitura é a mesma e a escrita é mais ampla.
public protected(set) int $pubYear; // Erro fatal. propriedades private(set) são finais.
}
?>
Visibilidades de métodos
Métodos de classe podem ser definidos como público, privado ou protegido. Métodos sem qualquer declaração explícita serão definidos como público.
Example #4 Declaração de método
<?php
/**
* Define MinhaClasse
*/
class MinhaClasse
{
// Declara um construtor público
public function __construct() { }
// Declara um método público
public function MeuPublico() { }
// Declara um método protegido
protected function MeuProtegido() { }
// Declara um método privado
private function MeuPrivado() { }
// Esse é público
function Foo()
{
$this->MeuPublico();
$this->MeuProtegido();
$this->MeuPrivado();
}
}
$minhaclasse = new MinhaClasse;
$minhaclasse->MeuPublico(); // Funciona
$minhaclasse->MeuProtegido(); // Erro Fatal
$minhaclasse->MeuPrivado(); // Erro Fatal
$minhaclasse->Foo(); // Public, Protected e Private funcionam
/**
* Define MinhaClasse2
*/
class MinhaClasse2 extends MinhaClasse
{
// Esse é public
function Foo2()
{
$this->MeuPublico();
$this->MeuProtegido();
$this->MeuPrivado(); // Erro Fatal
}
}
$minhaclasse2 = new MinhaClasse2;
$minhaclasse2->MeuPublico(); // Funciona
$minhaclasse2->Foo2(); // Public e Protected funcionam, Private não
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic
?>
Visibilidade de constantes
A partir do PHP 7.1.0, constantes de classe podem ser definidas como públicas, protegidas ou privadas. Constantes declaradas sem visibilidade explícita são definidas como públicas.
Example #5 Declaração de constantes (desde o PHP 7.1.0)
<?php
/**
* Define MyClass
*/
class MyClass
{
// Declara uma constante pública
public const MY_PUBLIC = 'public';
// Declara uma constante protegida
protected const MY_PROTECTED = 'protected';
// Declara uma constante privada
private const MY_PRIVATE = 'private';
public function foo()
{
echo self::MY_PUBLIC;
echo self::MY_PROTECTED;
echo self::MY_PRIVATE;
}
}
$myclass = new MyClass();
MyClass::MY_PUBLIC; // Funciona
MyClass::MY_PROTECTED; // Erro fatal
MyClass::MY_PRIVATE; // Erro fatal
$myclass->foo(); // Todos os acessos funcionam dentro do método
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// This is public
function foo2()
{
echo self::MY_PUBLIC;
echo self::MY_PROTECTED;
echo self::MY_PRIVATE; // Fatal Error
}
}
$myclass2 = new MyClass2;
echo MyClass2::MY_PUBLIC; // Funciona
$myclass2->foo2(); // Public and Protected funcionam, mas não Private
?>
Visibilidade de outros objetos
Objetos do mesmo tipo terão acesso a outros mementos privados e protegidos mesmo que não sejam da mesma instância. Isso acontece por que os detalhes específicos de implementação já são conhecidos dentro destes objetos.
Example #6 Acessando membros privados entre objetos do mesmo tipo
<?php
class Test
{
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
private function bar()
{
echo 'Acessou o método privado.';
}
public function baz(Test $other)
{
// Pode-se alterar a propriedade privada:
$other->foo = 'hello';
var_dump($other->foo);
// Pode-se chamar método privado:
$other->bar();
}
}
$test = new Test('test');
$test->baz(new Test('other'));
?>
O exemplo acima produzirá:
string(5) "hello" Acessou o método privado.