## Abstraction de classes

PHP a des classes, méthodes et propriétés abstraites. Les classes définies comme abstraites ne peuvent pas être instanciées, et toute classe contenant au moins une méthode abstraite doit elle-aussi être abstraite. Les méthodes définies comme abstraites se contentent de déclarer la signature de la méthode et d'indiquer si elle est publique ou protégée ; elles ne peuvent pas définir l'implémentation. Les propriétés définies comme abstraites peuvent déclarer une exigence pour le comportement de `get` ou de `set`, et peuvent fournir une implémentation pour l'une de ces opérations, mais pas les deux.

Lors de l'héritage d'une classe abstraite, toutes les méthodes marquées comme abstraites dans la déclaration de la classe parente doivent être définies par la classe enfant et suivre les règles habituelles d'héritage et de compatibilité de signature.

À partir de PHP 8.4, une classe abstraite peut déclarer une propriété abstraite, publique ou protégée. Une propriété abstraite protégée peut être satisfaite par une propriété accessible en lecture/écriture depuis un contexte protégé ou public.

Une propriété abstraite peut être satisfaite soit par une propriété standard, soit par une propriété avec des hooks définis, correspondant à l'opération requise.

Exemple #1 Exemple de méthode abstraite

`<?php
abstract class AbstractClass
{
// Force les classes filles à définir cette méthode
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// méthode commune
public function printOut()
{
print $this->getValue() . "\n";
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue()
{
return "ConcreteClass1";
}
public function prefixValue($prefix)
{
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue()
{
return "ConcreteClass2";
}
public function prefixValue($prefix)
{
return "{$prefix}ConcreteClass2";
}
}
$class1 = new ConcreteClass1();
$class1->printOut();
echo $class1->prefixValue('FOO_'), "\n";
$class2 = new ConcreteClass2();
$class2->printOut();
echo $class2->prefixValue('FOO_'), "\n";
?>`

L'exemple ci-dessus va afficher :

    ConcreteClass1
    FOO_ConcreteClass1
    ConcreteClass2
    FOO_ConcreteClass2

Exemple #2 Exemple de méthode abstraite

`<?php
abstract class AbstractClass
{
// Une méthode abstraite ne doit que définir les arguments requis
abstract protected function prefixName($name);
}
class ConcreteClass extends AbstractClass
{
// Une classe enfant peut définir des arguments optionnels qui ne sont pas présents dans la signature du parent
public function prefixName($name, $separator = ".")
{
if ($name == "Pacman") {
$prefix = "Mr";
} elseif ($name == "Pacwoman") {
$prefix = "Mrs";
} else {
$prefix = "";
}
return "{$prefix}{$separator} {$name}";
}
}
$class = new ConcreteClass();
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>`

L'exemple ci-dessus va afficher :

    Mr. Pacman
    Mrs. Pacwoman

Exemple #3 Exemple de propriété abstraite

`<?php
abstract class A
{
// Les classes dérivées doivent avoir une propriété publiquement accessible en lecture.
abstract public string $readable {
get;
}
// Les classes dérivées doivent avoir une propriété modifiable en écriture, protégée ou publique.
abstract protected string $writeable {
set;
}
// Les classes dérivées doivent avoir une propriété symétrique protégée ou publique.
abstract protected string $both {
get;
set;
}
}
class C extends A
{
// Cela satisfait l'exigence et rend également la propriété modifiable, ce qui est valide.
public string $readable;
// Cela NE satisferait PAS l'exigence, car la propriété n'est pas publiquement accessible en lecture.
protected string $readable;
// Cela satisfait exactement l'exigence, donc c'est suffisant.
// La propriété ne peut être modifiée qu'à partir d'un contexte protégé.
protected string $writeable {
set => $value;
}
// Cela élargit la visibilité de protégé à public, ce qui est acceptable.
public string $both;
}
?>`

Une propriété abstraite dans une classe abstraite peut fournir des implémentations pour tout point d'ancrage, mais doit avoir soit `get` soit `set` déclarés mais non définis (comme dans l'exemple ci-dessus).

Exemple #4 Exemple de propriété abstraite avec des hooks

`<?php
abstract class A
{
// Cela fournit une implémentation par défaut (mais substituable) pour set,
// et exige que les classes dérivées fournissent une implémentation pour get.
abstract public string $foo {
get;
set {
$this->foo = $value
};
}
}
?>`