Abstraction de classes

PHP 5 introduit les concepts de classes et de méthodes 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 déclarent simplement la signature de la méthode - elles ne peuvent définir son implémentation.

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 l'enfant ; de plus, ces méthodes doivent être définies avec la même visibilité, ou une visibilité moins restreinte. Par exemple, si la méthode abstraite est définie comme protégée, l'implémentation de la fonction doit être définie comme protégée ou publique, mais pas privée. De plus, les signatures de ces méthodes doivent correspondre, ce qui signifie que les types des paramètres et le nombre d'arguments requis doivent être les mêmes. Par exemple, si la classe enfant définit un argument optionnel, alors que la signature de la méthode abstraite ne le définit pas, il n'y aura aucun conflit dans la signature. Ceci s'applique aussi aux constructeurs depuis PHP 5.4. Avant la version 5.4, les signatures des constructeurs pouvaient être différentes.

Exemple #1 Exemple de classe 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 avec une classe abstraite

<?php
abstract class AbstractClass
{
    
// Notre méthode abstraite ne doit que définir les arguments requis
    
abstract protected function prefixName($name);

}

class 
ConcreteClass extends AbstractClass
{

    
// Notre classe enfant peut définir des arguments optionnels non 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

L'ancien code qui n'a pas de classe définie par l'utilisateur ou de fonction nommée 'abstract' devrait continuer à fonctionner sans modification.