Archives de l’auteur : admin

Les classes abstraites en PHP (partie 2)

Nous avons vu précédemment que les classes abstraites étaient un bon moyen de forcer des implémentations dans les branches et les feuilles de l’arbre d’héritage et que c’était aussi un moyen d’interdire l’instanciation de classes que l’on juge trop « génériques » (on s’instancie pas un « être vivant », c’est une notion trop abstraite, on aimerait plutôt instancier Homme ou Baleine).

Une classe abstraite peut implémenter une (ou des) interfaces :

interface Reproduction {
    public function seReproduire();
}

interface Alimentation {
    public function seNourrir();
}

EtreVivant est une classe abstraite donc rien ne l’oblige à implémenter l’intégralité des fonctions (publiques, toujours !) imposées par les interfaces Reproduction et Alimentation, ce qui serait évidemment le cas si elle était concrète. Comme dans la partie 1, elle délègue cette obligation à la première classe concrète qui va la dériver…

interface Reproduction {
    public function seReproduire();
}

interface Alimentation {
    public function seNourrir();
}

abstract class EtreVivant implements Reproduction, Alimentation {}

class Baleine extends EtreVivant {

    public function seReproduire() {
        // décrivez ici de manière poétique
        // l'accouplement de ces majestueux animaux
    }
    public function seNourrir() {
        echo "Je mange du krill et du zooplancton", PHP_EOL;
    }
}

Bien entendu, une classe abstraite peut prendre en charge une partie de l’implémentation des méthodes imposées par une interface et déléguer le reste à ses filles…

interface Propulsion {
    public function pedaler();
}

interface Freinage {
    public function freiner();
}

abstract class Velo implements Propulsion, Freinage {
    public function pedaler() {
        $this->mettrePiedsSurPedales();
        $this->appuyerSurPedales();
    }

    public function mettrePiedsSurPedales() {
        echo "Je mets les pieds sur les pédales", PHP_EOL;
    }

    public function appuyerSurPedales() {
       echo "J'appuie sur les pédales", PHP_EOL;
    }
}

class BMX extends Velo {
    public function freiner() {
        echo "Les patins appuient sur les roues", PHP_EOL;
    }
}

class VTTDernierCri extends Velo {
    public function freiner() {
        echo "Les plaquettes appuient sur les disques", PHP_EOL;
    }
}

Dans notre cas, Velo, qui est abstraite, a pris en charge une partie des méthodes imposées par les interfaces(imposées…pas vraiment, puisqu’elle est abstraite); elle a choisi d’implémenter pedaler, qui provient de l’interface Propulsion. En effet, qu’on conduise un vélo de course, de descente, un BMX ou le tricycle d’un enfant, on n’y coupe pas : il faut pédaler, et toujours de la même manière !

Par contre le freinage peut être délégué aux filles car son implémentation va dépendre directement de la classe concrète…En effet un vieux vélo ne freine pas forcément de la même manière qu’un nouveau (la plupart des nouveaux vélos ont des freins à disques, les anciens – le mien 🙁 – ont encore des freins à étrier avec des patins…).

Les classes abstraites en PHP (partie 1)

Une classe abstraite est un mécanisme qui comme son nom l’indique permet d’abstraire (i.e, de rendre abstrait) une notion de votre domaine d’application. Quoi de plus générique par exemple que :

abstract class EtreVivant {
    protected $_age;
    protected $_poids;
}

Une classe abstraite peut très bien ne contenir aucune méthode abstraite ! Par contre, il suffit qu’une méthode dans une classe soit abstraite pour que la classe doive l’être à son tour !

abstract class EtreVivant {
    protected $_age;
    protected $_poids;

    abstract public function seReproduire();
}

Tous les êtres vivants savent se reproduire, qu’on  parle d’une bactérie ou d’une baleine megaptera ! Par contre, ils ne se reproduisent pas tous de la même manière…En signalant cette méthode comme étant abstraite, nous laissons donc le soin aux classes qui vont spécialiser EtreVivant d’implémenter (de concrétiser, pour employer les mêmes termes) cette méthode seReproduire.

class Requin extends EtreVivant {
    public function seReproduire() {
        echo "Je m'accouple abdomen contre abdomen", PHP_EOL;
    }
}

class Homme extends EtreVivant {
    public function seReproduire() {
        // Allons, un peu de tenue, tout de même !
    }
}

Une classe abstraite ne s’instancie pas, c’est la règle, et pas qu’en PHP ! Il vous faudra donc la dériver en une classe concrète avant de pouvoir bénéficier de ses fonctionnalités par le mécanisme d’héritage. C’est précisément ce que nous venons de faire !

Une classe abstraite peut hériter d’une classe, elle-même abstraite !

abstract class EtreVivant {
    protected $_age;
    protected $_poids;

    abstract public function seReproduire();
}

abstract class Vegetal extends EtreVivant {

}

Ici, nul besoin d’implémenter la méthode seReproduire qui est pourtant imposée par EtreVivant ! Pourquoi ? Parce que je suis dans une classe abstraite et que je n’en ai donc pas l’obligation ! Par contre, la première classe concrète dans la hiérarchie d’héritage (la première fille de Vegetal, pour parler concrètement) DEVRA obligatoirement implémenter cette méthode sous peine de déclencher une erreur fatale…


abstract class EtreVivant {
protected $_age;
protected $_poids;

abstract public function seReproduire();
}

abstract class Vegetal extends EtreVivant {}

class Rododendron extends Vegetal {}

Hélas… »PHP Fatal error:  Class Rododendron contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (EtreVivant::seReproduire) ».

Pour en finir avec le display length sur les types de données numériques de MySQL

Contrairement à la croyance populaire, écrire :


create table eleve (

id_eleve tinyint(2) unsigned NOT NULL PRIMARY KEY

) 

ne fera pas en sorte que vous vous retrouviez avec des nombres inférieurs à 99. Ce 2 entre parenthèses n’est utile que lorsque vous utilisez l’option ZEROFILL (littéralement « remplir avec des zéros »). La preuve, insérez donc 255, qui est la limite haute d’un tinyint non signé :

insert into eleve values (255);

Si vous faites :

select * from eleve;

Vous verrez bien 255 s’afficher ! Si par contre vous utilisez l’option ZEROFILL, comme suit :

create table eleve (
id_eleve tinyint(2) unsigned ZEROFILL NOT NULL PRIMARY KEY
)

Alors en insérant 1 :

insert into eleve values (1);

Vous verrez, après un nouveau select, que ce chiffre a été complété (sur la gauche, évidemment…) par autant de zéros qu’il faut pour satisfaire votre longueur d’affichage (display length), qui est de 2 !