Syntaxe de base

class

Une définition de classe basique commence par le mot-clé class, suivi du nom de la classe. Suit une paire d'accolades contenant la définition des propriétés et des méthodes appartenant à la classe.

Le nom de la classe peut être quelconque à condition que ce ne soit pas un mot réservé en PHP. Un nom de classe valide commence par une lettre ou un underscore, suivi de n'importe quel nombre de chiffres, ou de lettres, ou d'underscores. Si on devait l'exprimer sous forme d'une expression rationnelle, il s'agirait de ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.

Une classe peut contenir ses propres constantes, variables (appelées "propriétés" ou "attributs"), et fonctions (appelées "méthodes").

Exemple #1 Définition typique d'une classe

<?php
class SimpleClass
{
// déclaration d'une propriété
public $var = 'une valeur par défaut';

// déclaration des méthodes
public function displayVar() {
echo
$this->var;
}
}
?>

La pseudo-variable $this est disponible lorsqu'une méthode est appelée depuis un contexte objet. $this est la valeur de l'objet appelant.

Avertissement

Appeler une méthode non-statique statiquement lance une Error. Antérieur à PHP 8.0.0, ceci générait une notice d'obsolescence, et $this était indéfini.

Exemple #2 Quelques exemples de la pseudo-variable $this

<?php
class A
{
function
foo()
{
if (isset(
$this)) {
echo
'$this is defined (';
echo
get_class($this);
echo
")\n";
} else {
echo
"\$this is not defined.\n";
}
}
}

class
B
{
function
bar()
{
A::foo();
}
}

$a = new A();
$a->foo();

A::foo();

$b = new B();
$b->bar();

B::bar();
?>

Résultat de l'exemple ci-dessus en PHP 7 :

 $this is defined (A) Deprecated: Non-static method A::foo() should not be called statically in %s on line 27 $this is not defined. Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this is not defined. Deprecated: Non-static method B::bar() should not be called statically in %s on line 32 Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this is not defined. 

Résultat de l'exemple ci-dessus en PHP 8 :

 $this is defined (A) Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27 Stack trace: #0 {main} thrown in %s on line 27 

Classes en lecture seule (readonly)

À partir de PHP 8.2.0, une classe peut être marquée avec le modificateur readonly. Marquer une classe comme readonly ajoutera le modificateur readonly à chaque propriété déclarée, et empêchera la création de propriétés dynamiques. En outre, il est impossible d'ajouter leur prise en charge en utilisant l'attribut AllowDynamicProperties. Toute tentative de le faire déclenchera une erreur de compilation.

<?php
#[\AllowDynamicProperties]
readonly class
Foo {
}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

Comme ni les propriétés non typées ni les propriétés statiques ne peuvent être marquées avec le modificateur readonly, les classes readonly ne peuvent pas non plus les déclarer :

<?php
readonly class Foo
{
public
$bar;
}

// Fatal error: Readonly property Foo::$bar must have type
?>
<?php
readonly class Foo
{
public static
int $bar;
}

// Fatal error: Readonly class Foo cannot declare static properties
?>

Une classe readonly peut être étendu si, et seulement si, la classe enfant est également une classe readonly.

Le mot-clé new

Pour créer une instance d'une classe, le mot-clé new doit être utilisé. Un objet sera alors systématiquement créé, à moins qu'il ait un constructeur défini qui lance une exception en cas d'erreur. Les classes devraient être définies avant l'instanciation (dans certains cas, c'est impératif).

Si une variable string contenant un nom de classe est utilisée avec new, une nouvelle instance de cette classe sera créée. Si la classe est dans un espace de noms, son nom pleinement qualifié doit être utilisé.

Note:

S'il n'y a pas d'arguments à passer au constructeur de la classe, les parenthèses après le nom de la classe peuvent être omises.

Exemple #3 Création d'une instance

<?php
$instance
= new SimpleClass();

// Ceci peut également être réalisé avec une variable :
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
?>

À partir de PHP 8.0.0, l'utilisation de new avec des expressions arbitraires est supportée. Ceci permet des instantiations plus complexes si l'expression produit une string. L'expression doit être entourée de parenthèses.

Exemple #4 Créer une instance en utilisant une expression arbitraire

Dans l'exemple donné, nous montrons plusieurs exemples d'expressions arbitraires valides qui produisent un nom de classe. Ceci montre un appel de fonction, une concaténation de chaînes et la constante ::class.

<?php

class ClassA extends \stdClass {}
class
ClassB extends \stdClass {}
class
ClassC extends ClassB {}
class
ClassD extends ClassA {}

function
getSomeClass(): string
{
return
'ClassA';
}

var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>

Résultat de l'exemple ci-dessus en PHP 8 :

 object(ClassA)#1 (0) { } object(ClassB)#1 (0) { } object(ClassC)#1 (0) { } object(ClassD)#1 (0) { } 

Dans le contexte de la classe, il est possible de créer un nouvel objet avec new self et new parent.

Lors de l'assignation d'une instance déjà créée d'une classe à une variable, la nouvelle variable accédera à la même instance que l'objet qui a été assigné. Ce comportement est le même lors du passage d'une instance à une fonction. Une copie d'un objet déjà créé peut être effectuée par clonage.

Exemple #5 Assignation d'un objet

<?php

$instance
= new SimpleClass();

$assigned = $instance;
$reference =& $instance;

$instance->var = '$assigned aura cette valeur';

$instance = null; // $instance et $reference deviennent null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

L'exemple ci-dessus va afficher :

 NULL NULL object(SimpleClass)#1 (1) { ["var"]=> string(30) "$assigned aura cette valeur" } 

Il est possible de créer une instance d'un objet de quelques manières différentes :

Exemple #6 Créer de nouveaux objets

<?php
class Test
{
static public function
getNew()
{
return new static;
}
}

class
Child extends Test
{}

$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);

$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);

$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>

L'exemple ci-dessus va afficher :

 bool(true) bool(true) bool(true) 

Il est possible d'accéder à un membre d'un objet nouvellement créé en une seule expression :

Exemple #7 Accéder un membre d'un objet nouvellement créé

<?php
echo (new DateTime())->format('Y');
?>

Résultat de l'exemple ci-dessus est similaire à :

 2016 

Note: Antérieur à PHP 7.1, les arguments ne sont pas évalués s'il n'y a pas de fonction constructeur définie.

Propriétés et méthodes

Les propriétés et méthodes de classe vivent dans des "espaces de noms" séparé, donc il est possible d'avoir une propriété et une méthode avec le même nom. Faire référence à la fois a une propriété ainsi qu'une méthode ont la même notation, et le fait qu'une propriété sera accédée ou qu'une méthode sera appelée, dépend seulement du contexte, c'est-à-dire si l'utilisation est un accès variable ou un appel de fonction.

Exemple #8 Accès de propriété contre appel de méthode

<?php
class Foo
{
public
$bar = 'property';

public function
bar() {
return
'method';
}
}

$obj = new Foo();
echo
$obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;

L'exemple ci-dessus va afficher :

 property method 

Ceci signifie qu'appeler une fonction anonyme qui a été assigné à une propriété n'est pas possible directement. Au lieu de cela, la propriété doit d'abord être affectée à une variable. Il est possible d'appeler ce genre de propriété directement en la mettant entre parenthèses.

Exemple #9 Appeler une fonction anonyme enregistrée dans une propriété

<?php
class Foo
{
public
$bar;

public function
__construct() {
$this->bar = function() {
return
42;
};
}
}

$obj = new Foo();

echo (
$obj->bar)(), PHP_EOL;

L'exemple ci-dessus va afficher :

 42 

Le mot-clé extends

Une classe peut hériter des constantes, méthodes et des propriétés d'une autre classe en utilisant le mot-clé extends dans la déclaration. Il n'est pas possible d'étendre plusieurs classes : une classe peut uniquement hériter d'une seule classe de base.

Les constantes, méthodes et propriétés héritées peuvent être redéfinies en les redéclarant avec le même nom que dans la classe parente. Cependant, si la classe parente a défini une méthode ou constante comme final, alors celles-ci ne peuvent pas être redéfinies. Il est possible d'accéder aux méthodes ou propriétés statiques redéfinies en y faisant référence avec l'opérateur parent::.

Note: À partir de PHP 8.1.0, les constantes peuvent être déclaré comme finale.

Exemple #10 Héritage simple d'une classe

<?php
class ExtendClass extends SimpleClass
{
// Redéfinition de la méthode parente
function displayVar()
{
echo
"Classe étendue\n";
parent::displayVar();
}
}

$extended = new ExtendClass();
$extended->displayVar();
?>

L'exemple ci-dessus va afficher :

 Classe étendue une valeur par défaut 

Règles de compatibilité de signature

Lors de la surcharge d'une méthode, sa signature doit être compatible avec la méthode parente. Sinon, une erreur fatale est émise, ou, antérieur à PHP 8.0.0, une erreur de niveau E_WARNING est générée. Une signature est compatible si elle respecte les règles de variance, rend un paramètre obligatoire optionnel, et seulement si tous les nouveaux paramètres sont optionnels et assouplissent les régles de visibilité. Ceci est connu sous le Principe de Substitution de Liskov (Liskov Substitution Principle), ou simplement LSP. Le constructeur, et les méthodes private sont exclus de ces règles de compatibilité des signatures, et par conséquent n'émettront pas d'erreur fatale en cas de signature incompatible.

Exemple #11 Méthodes enfant compatibles

<?php
class Base
{
public function
foo(int $a) {
echo
"Valid\n";
}
}
class
Extend1 extends Base
{
function
foo(int $a = 5)
{
parent::foo($a);
}
}
class
Extend2 extends Base
{
function
foo(int $a, $b = 5)
{
parent::foo($a);
}
}
$extended1 = new Extend1();
$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);

L'exemple ci-dessus va afficher :

 Valid Valid 

Les exemples suivants démontrent qu'une méthode enfant qui supprime un paramètre, ou rend un paramètre optionnel obligatoire, n'est pas compatible avec la méthode parente.

Exemple #12 Erreur fatale quand une méthode enfant supprime un paramètre

<?php
class Base
{
public function
foo(int $a = 5) {
echo
"Valid\n";
}
}
class
Extend extends Base
{
function
foo()
{
parent::foo(1);
}
}

Résultat de l'exemple ci-dessus en PHP 8 est similaire à :

 Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13 

Exemple #13 Erreur fatale quand une méthode enfant rend un paramètre optionnel obligatoire

<?php
class Base
{
public function
foo(int $a = 5) {
echo
"Valid\n";
}
}
class
Extend extends Base
{
function
foo(int $a)
{
parent::foo($a);
}
}

Résultat de l'exemple ci-dessus en PHP 8 est similaire à :

 Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13 
Avertissement

Renommer un paramètre d'une méthode dans une classe enfant n'est pas une incompatibilité de signature. Cependant, ceci est découragé car ceci va résulter en une Error lors du runtime si les arguments nommés sont utilisés.

Exemple #14 Erreur lors de l'utilisation des arguments nommés et que les paramètres ont été renommés dans une classe enfant

<?php
class A {
public function
test($foo, $bar) {}
}
class
B extends A {
public function
test($a, $b) {}
}
$obj = new B;
// Pass parameters according to A::test() contract
$obj->test(foo: "foo", bar: "bar"); // ERROR!

Résultat de l'exemple ci-dessus est similaire à :

 Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14 Stack trace: #0 {main} thrown in /in/XaaeN on line 14 

::class

Le mot clé class est également utilisé pour la résolution des noms de classes. Il est possible d'obtenir le nom complètement qualifié d'une classe ClassName en utilisant ClassName::class. C'est particulièrement utile avec les classes utilisant des espaces de noms.

Exemple #15 Résolution de nom de classe

<?php
namespace NS {
class
ClassName {
}

echo
ClassName::class;
}
?>

L'exemple ci-dessus va afficher :

 NS\ClassName 

Note:

La résolution du nom de classe en utilisant ::class est une transformation lors de la compilation. C'est-à-dire à l'instant où la chaine du nom de classe est créé aucun autochargement n'a encore eu lieu. Par conséquent, les noms de classes sont étendues même si la classe n'existe pas. Aucune erreur n'est émise dans ce cas là.

Exemple #16 Résolution de nom de classe manquante

<?php
print Does\Not\Exist::class;
?>

L'exemple ci-dessus va afficher :

 Does\Not\Exist 

À partir de PHP 8.0.0, ::class peut être utilisé sur les objets. Cette résolution se produit lors de l'exécution, et non lors de la compilation. Ses effets sont les mêmes que d'appeler get_class() sur l'objet.

Exemple #17 Résolution du nom d'un objet

<?php
namespace NS {
class
ClassName {
}
}
$c = new ClassName();
print
$c::class;
?>

L'exemple ci-dessus va afficher :

 NS\ClassName 

Méthodes et propriétés nullsafe

À partir de PHP 8.0.0, les méthodes et propriétés peuvent aussi être accédés avec l'opérateur "nullsafe": ?->. L'opérateur nullsafe fonctionne à l'identique que l'accès de propriétés ou méthodes comme si dessus, à l'exception que si l'objet qui est déréférencé est null alors null sera retourné au lieu de lancer une exception. Si le déréférencement fait par d'une chaîne, le reste de la chaîne est ignoré.

L'effet est similaire à entourer chaque accès par une vérification avec is_null() d'abord, mais plus compact.

Exemple #18 Opérateur nullsafe

<?php

// À partir de PHP 8.0.0, cette ligne:
$result = $repository?->getUser(5)?->name;

// Est équivalente à bloc de code suivant :
if (is_null($repository)) {
$result = null;
} else {
$user = $repository->getUser(5);
if (
is_null($user)) {
$result = null;
} else {
$result = $user->name;
}
}
?>

Note:

L'opérateur nullsafe est mieux utilisé quand null est considéré une valeur valide et potentiellement attendu pour une propriété ou valeur de retour d'une méthode. Pour indiquer une erreur, lancer une exception est préférable.

To Top