Visibilité

La visibilitĂ© d'une propriĂ©tĂ©, d'une mĂ©thode ou (Ă  partir de PHP 7.1.0) d'une constante peut ĂȘtre dĂ©finie en prĂ©fixant sa dĂ©claration avec un mot-clĂ© : public, protected, ou private. Les Ă©lĂ©ments dĂ©clarĂ©s comme publics sont accessibles partout. L'accĂšs aux Ă©lĂ©ments protĂ©gĂ©s est limitĂ© Ă  la classe elle-mĂȘme, ainsi qu'aux classes qui en hĂ©ritent et Ă  la classe parente. L'accĂšs aux Ă©lĂ©ments privĂ©s est uniquement rĂ©servĂ© Ă  la classe qui les a dĂ©finis.

Visibilité des propriétés

Les propriĂ©tĂ©s des classes peuvent ĂȘtre dĂ©finies comme publiques, privĂ©es ou protĂ©gĂ©es. Les propriĂ©tĂ©s dĂ©clarĂ©es sans explicitement utiliser un mot-clef de visibilitĂ© seront automatiquement dĂ©finies comme publiques.

Exemple #1 Déclaration de propriétés

<?php
/**
* Définition de MyClass
*/
class MyClass
{
public
$public = 'Public';
protected
$protected = 'Protected';
private
$private = 'Private';

function
printHello()
{
echo
$this->public;
echo
$this->protected;
echo
$this->private;
}
}

$obj = new MyClass();
echo
$obj->public; // Fonctionne
echo $obj->protected; // Erreur fatale
echo $obj->private; // Erreur fatale
$obj->printHello(); // Affiche Public, Protected et Private


/**
* Définition de MyClass2
*/
class MyClass2 extends MyClass
{
// On peut redéclarer les propriétés publiques ou protégées, mais pas celles privées
public $public = 'Public2';
protected
$protected = 'Protected2';

function
printHello()
{
echo
$this->public;
echo
$this->protected;
echo
$this->private;
}
}

$obj2 = new MyClass2();
echo
$obj2->public; // Fonctionne
echo $obj2->protected; // Erreur fatale
echo $obj2->private; // Indéfini
$obj2->printHello(); // Affiche Public2, Protected2 et Undefined (Indéfini)

?>

Visibilité Asymétrique des Propriétés

À partir de PHP 8.4, les propriĂ©tĂ©s peuvent Ă©galement avoir leur visibilitĂ© dĂ©finie de maniĂšre asymĂ©trique, avec un champ diffĂ©rent pour la lecture (get) et l'Ă©criture (set). Plus prĂ©cisĂ©ment, la visibilitĂ© set peut ĂȘtre spĂ©cifiĂ©e sĂ©parĂ©ment, Ă  condition qu'elle ne soit pas plus permissive que la visibilitĂ© par dĂ©faut.

Exemple #2 Visibilité Asymétrique des Propriétés

<?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; // Erreur Fatale
}
}

$b = new Book('Comment utiliser PHP', 'Peter H. Peterson', 2024);

echo
$b->title; // Fonctionne
echo $b->author; // Fonctionne
echo $b->pubYear; // Erreur Fatale

$b->title = 'Comment ne pas utiliser PHP'; // Erreur Fatale
$b->author = 'Pedro H. Peterson'; // Erreur Fatale
$b->pubYear = 2023; // Erreur Fatale
?>

À partir de PHP 8.5, la visibilitĂ© set peut Ă©galement ĂȘtre appliquĂ©e aux propriĂ©tĂ©s statiques des classes.

Exemple #3 Visibilité Asymétrique des Propriétés Statiques

<?php
class Manager
{
public private(
set) static int $calls = 0;

public function
doAThing(): string
{
self::$calls++;
// Effectue d'autres opérations.
return "une chaĂźne";
}
}

$m = new Manager();

$m->doAThing(); // Fonctionne
echo Manager::$calls; // Fonctionne
Manager::$calls = 5; // Erreur fatale
?>

L'exemple ci-dessus va afficher :

1
Fatal error: Uncaught Error: Cannot modify private(set) property Manager::$calls from global scope in /some/file.php

Il y a quelques réserves concernant la visibilité asymétrique :

  • Seules les propriĂ©tĂ©s typĂ©es peuvent avoir une visibilitĂ© set sĂ©parĂ©e.
  • La visibilitĂ© set doit ĂȘtre la mĂȘme que get ou plus restrictive. C'est-Ă -dire, public protected(set) et protected protected(set) sont autorisĂ©s, mais protected public(set) provoquera une erreur de syntaxe.
  • Si une propriĂ©tĂ© est public, alors la visibilitĂ© principale peut ĂȘtre omise. C'est-Ă -dire que public private(set) et private(set) auront le mĂȘme rĂ©sultat.
  • Une propriĂ©tĂ© avec une visibilitĂ© private(set) est automatiquement final, et ne peut pas ĂȘtre redĂ©finie dans une classe enfant.
  • Obtenir une rĂ©fĂ©rence Ă  une propriĂ©tĂ© suit la visibilitĂ© set, pas get. Cela est dĂ» au fait qu'une rĂ©fĂ©rence peut ĂȘtre utilisĂ©e pour modifier la valeur de la propriĂ©tĂ©.
  • De mĂȘme, essayer d'Ă©crire dans une propriĂ©tĂ© de tableau implique Ă  la fois une opĂ©ration get et une opĂ©ration set en interne, et suivra donc la visibilitĂ© set, car c'est toujours la plus restrictive.

Note: Les espaces ne sont pas autorisés dans la déclaration de visibilité pour la modification. private(set) est correct. private( set ) n'est pas correct et entraßnera une erreur d'analyse.

Lorsqu'une classe Ă©tend une autre, la classe enfant peut redĂ©finir toute propriĂ©tĂ© qui n'est pas final. En le faisant, elle peut Ă©largir soit la visibilitĂ© principale, soit la visibilitĂ© set, Ă  condition que la nouvelle visibilitĂ© soit la mĂȘme ou plus large que celle de la classe parente. Cependant, il faut savoir que si une propriĂ©tĂ© private est remplacĂ©e, cela ne change pas rĂ©ellement la propriĂ©tĂ© de la classe parente, mais crĂ©e une nouvelle propriĂ©tĂ© avec un nom interne diffĂ©rent.

Exemple #4 Héritage des Propriétés Asymétriques

<?php
class Book
{
protected
string $title;
public protected(
set) string $author;
protected private(
set) int $pubYear;
}

class
SpecialBook extends Book
{
public protected(
set) string $title; // OK, car la lecture est plus large et l'Ă©criture est la mĂȘme.
public string $author; // OK, car la lecture est la mĂȘme et l'Ă©criture est plus large.
public protected(set) int $pubYear; // Erreur Fatale. Les propriétés private(set) sont finales.
}
?>

Visibilité des méthodes

Les mĂ©thodes des classes peuvent ĂȘtre dĂ©finies comme publiques, privĂ©es ou protĂ©gĂ©es. Les mĂ©thodes dĂ©clarĂ©es sans explicitement utiliser un mot-clef de visibilitĂ© seront automatiquement dĂ©finies comme publiques.

Exemple #5 Déclaration de méthodes

<?php
/**
* Définition de MyClass
*/
class MyClass
{
// Déclare un constructeur public
public function __construct() { }

// Déclare une méthode publique
public function MyPublic() { }

// Déclare une méthode protégée
protected function MyProtected() { }

// Déclare une méthode privée
private function MyPrivate() { }

// Celle-ci sera publique
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}

$myclass = new MyClass;
$myclass->MyPublic(); // Fonctionne
$myclass->MyProtected(); // Erreur fatale
$myclass->MyPrivate(); // Erreur fatale
$myclass->Foo(); // Public, Protected et Private fonctionnent


/**
* Définition de MyClass2
*/
class MyClass2 extends MyClass
{
// Celle-ci sera publique
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // Erreur fatale
}
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Fonctionne
$myclass2->Foo2(); // Public et Protected fonctionnent, non Private

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
?>

Visibilité des constantes

À partir de PHP 7.1.0, les constantes de classes peuvent ĂȘtre dĂ©finies comme publiques, privĂ©es ou protĂ©gĂ©es. Les constantes dĂ©clarĂ©es sans mot clĂ© de visibilitĂ© explicite sont dĂ©finies en tant que public.

Exemple #6 Déclaration de constantes à partir de PHP 7.1.0

<?php
/**
* Déclarons MyClass
*/
class MyClass
{
// Déclarons une constante public
public const MY_PUBLIC = 'public';

// Déclarons une constante protégée
protected const MY_PROTECTED = 'protected';

// Déclarons une constante privée
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; // Fonctionne
MyClass::MY_PROTECTED; // Erreur fatale
MyClass::MY_PRIVATE; // Erreur fatale
$myclass->foo(); // Public, Protégée et Privée fonctionnent


/**
* Déclarons MyClass2
*/
class MyClass2 extends MyClass
{
// Celle-ci sera publique
function foo2()
{
echo
self::MY_PUBLIC;
echo
self::MY_PROTECTED;
echo
self::MY_PRIVATE; // Erreur fatale
}
}

$myclass2 = new MyClass2;
echo
MyClass2::MY_PUBLIC; // Fonctionne
$myclass2->foo2(); // Public et Protégée fonctionnent, mais pas Privée
?>

Visibilité depuis d'autres objets

Les objets de mĂȘmes types ont accĂšs aux membres privĂ©s et protĂ©gĂ©s les uns des autres, mĂȘme s'ils ne sont pas la mĂȘme instance. Ceci est dĂ» au fait que les dĂ©tails spĂ©cifiques de l'implĂ©mentation sont dĂ©jĂ  connus en interne par ces objets.

Exemple #7 AccĂšs aux membres privĂ©s d'un objet du mĂȘme type

<?php
class Test
{
private
$foo;

public function
__construct($foo)
{
$this->foo = $foo;
}

private function
bar()
{
echo
'AccÚs à la méthode privée.';
}

public function
baz(Test $other)
{
// Nous pouvons modifier la propriété privée :
$other->foo = 'Bonjour';
var_dump($other->foo);

// Nous pouvons également appeler la méthode privée :
$other->bar();
}
}

$test = new Test('test');

$test->baz(new Test('other'));
?>

L'exemple ci-dessus va afficher :

string(7) "Bonjour"
AccÚs à la méthode privée.
add a note

User Contributed Notes 6 notes

up
60
pgl at yoyo dot org ¶
10 years ago
Just a quick note that it's possible to declare visibility for multiple properties at the same time, by separating them by commas.

eg:

<?php
class a
{
    protected $a, $b;

    public $c, $d;

    private $e, $f;
}
?>
up
11
Joshua Watt ¶
19 years ago
I couldn't find this documented anywhere, but you can access protected and private member varaibles in different instance of the same class, just as you would expect

i.e.

<?php
class A
{
    protected $prot;
    private $priv;
    
    public function __construct($a, $b)
    {
        $this->prot = $a;
        $this->priv = $b;
    }
    
    public function print_other(A $other)
    {
        echo $other->prot;
        echo $other->priv;
    }
}

class B extends A
{
}

$a = new A("a_protected", "a_private");
$other_a = new A("other_a_protected", "other_a_private");

$b = new B("b_protected", "ba_private");

$other_a->print_other($a); //echoes a_protected and a_private
$other_a->print_other($b); //echoes b_protected and ba_private

$b->print_other($a); //echoes a_protected and a_private
?>
up
7
jc dot flash at gmail dot com ¶
13 years ago
if not overwritten, self::$foo in a subclass actually refers to parent's self::$foo 
<?php
class one
{
    protected static $foo = "bar";
    public function change_foo($value)
    {
        self::$foo = $value;
    }
}

class two extends one
{
    public function tell_me()
    {
        echo self::$foo;
    }
}
$first = new one;
$second = new two;

$second->tell_me(); // bar
$first->change_foo("restaurant");
$second->tell_me(); // restaurant
?>
up
3
alperenberatdurmus at gmail dot com ¶
3 years ago
Dynamic properties are "public".
<?php
class MyClass {
    public function setProperty($value) {
        $this->dynamicProperty = $value;
    }
}
$obj = new MyClass();
$obj->setProperty('Hello World');
echo $obj->dynamicProperty; // Outputs "Hello World"
?>

This usage is the same as well:
<?php
class MyClass {
}
$obj = new MyClass();
$obj->dynamicProperty = 'Hello World';
echo $obj->dynamicProperty; // Outputs "Hello World"
?>
up
5
bishop at php dot net ¶
9 years ago
> Members declared protected can be accessed only within 
> the class itself and by inherited classes. Members declared 
> as private may only be accessed by the class that defines 
> the member.

This is not strictly true. Code outside the object can get and set private and protected members:

<?php
class Sealed { private $value = 'foo'; }

$sealed = new Sealed;
var_dump($sealed); // private $value => string(3) "foo"

call_user_func(\Closure::bind(
    function () use ($sealed) { $sealed->value = 'BAZ'; },
    null,
    $sealed
));

var_dump($sealed); // private $value => string(3) "BAZ"

?>

The magic lay in \Closure::bind, which allows an anonymous function to bind to a particular class scope. The documentation on \Closure::bind says:

> If an object is given, the type of the object will be used
> instead. This determines the visibility of protected and
> private methods of the bound object.

So, effectively, we're adding a run-time setter to $sealed, then calling that setter. This can be elaborated to generic functions that can force set and force get object members:

<?php
function force_set($object, $property, $value) {
    call_user_func(\Closure::bind(
        function () use ($object, $property, $value) {
            $object->{$property} = $value;
        },
        null,
        $object
    ));
}

function force_get($object, $property) {
    return call_user_func(\Closure::bind(
        function () use ($object, $property) {
            return $object->{$property};
        },
        null,
        $object
    ));
}

force_set($sealed, 'value', 'quux');
var_dump(force_get($sealed, 'value')); // 'quux'

?>

You should probably not rely on this ability for production quality code, but having this ability for debugging and testing is handy.
up
1
kostya at eltexsoft dot com ¶
4 years ago
I see we can redeclare private properties into child class 
<?php   
 class A{
        private int $private_prop = 4;
        protected int $protected_prop = 8;
    }

    class B extends A{
        private int $private_prop = 7; // we can redeclare private property!!!
        public function printAll() {
            echo $this->private_prop;
            echo $this->protected_prop;
    }
    }

    $b = new B;
    $b->printAll(); // show 78
}
?>