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;
}
?>
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.
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)
?>
à 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 :
set séparée.
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.
public, alors la visibilitĂ© principale peut ĂȘtre
omise. C'est-Ă -dire que public private(set) et private(set)
auront le mĂȘme rĂ©sultat.
private(set)
est automatiquement final, et ne peut pas ĂȘtre redĂ©finie dans une classe enfant.
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Ă©.
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.
}
?>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
?>Ă 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
?>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.
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;
}
?>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
?>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
?>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"
?>> 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.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
}
?>