Archives du mot-clé oop

PHP 7 : les types de retour

Un futur vers les retours

On continue dans la série « Ces nouveautés qui rendent heureux » avec l’annonce de la possibilité de forcer des types de retour de fonctions dans PHP 7 ! Cette avancée majeure a fait là encore l’objet de débats assez vifs au sein de la communauté des développeurs PHP, avec des RFC critiquées, d’autres écartées et d’autres qui reviendront un jour ou l’autre d’outre-tombe !

Terminator, un type de retour

Le type de retour le plus connu au monde !

C’est l’histoire d’un type…

Scalaire ou pas, nous pouvons maintenant signifier un type de retour dans les déclarations de nos fonctions, sous la forme suivante :

<MODE D'ACCES> function <NOM> (liste de paramètres) : <TYPE DE RETOUR>

La position de ce type de retour a fait débat d’entrée de jeu, certains développeurs ne souhaitant pas le voir devant le nom de la fonction, comme c’est le cas en C ou Java, pour des raisons de commodité lors des recherches dans le code (chercher « function mafonc » n’aurait plus fonctionné si elle avait du s’appeler « function int mafonc »).

Commençons avec des types non scalaires :

function eleves(): array {
    return ["jean", "eric", null];
}

var_dump(eleves());

/*
array(3) {
  [0]=>
  string(4) "jean"
  [1]=>
  string(4) "eric"
  [2]=>
  NULL
}
*/

ou bien encore :

class Eleve {
    private $_nom;
    private $_prenom;

    public function __construct ($nom, $prenom) {
        $this->_nom = $nom;
        $this->_prenom = $prenom;
    }
}

function eleve($n, $p): Eleve {
    return new Eleve ($n, $p);
}

var_dump(eleve("Rack", "Eric"));

/*
object(Eleve)#1 (2) {
  ["_nom":"Eleve":private]=>
  string(4) "Rack"
  ["_prenom":"Eleve":private]=>
  string(4) "Eric"
}
*/

Nous avons utilisé dans l’exemple précédent des types non scalaires, respectivement tableau (array) et objet (de la classe Eleve).

Nous pouvons aussi renvoyer des types scalaires, tels que int, float, bool ou encore string :

function qi(): int {
    return 150;
}

var_dump(qi());

Si je modifie le type de retour pour essayer les quatre types susnommés, voici ce que j’obtiens :

int(150)
bool(true)
string(3) "150" 
float(150)

Pensez à activer le typage strict en faisant figurer en première ligne de votre fichier de test (ou plus proprement, dans l’autoloader de votre application) la directive maintenant bien connue de ceux qui veulent bénéficier des plus récentes fonctionnalités en matière de typage strict, à savoir:

declare(strict_types=1);

Comme toujours, il faut respecter le contrat, sinon gare ! Vous ne pouvez pas écrire :

function quotientintellectuel(): int {
    return null;
}

ou bien encore:

function quotientintellectuel(): int {
    return "150";
}

Sous peine de courroucer PHP, qui, pour le premier exemple, vous jettera à la figure un joli :

Fatal error: Uncaught TypeError: Return value of quotientintellectuel()
 must be of the type integer, null returned 

Invariance

Elle reste toujours de mise, à savoir que les signatures des méthodes héritées ou implémentées doivent rester EXACTEMENT les mêmes dans les sous-types. Ainsi, si vous écrivez ceci, vous vous provoquerez naturellement l’ire du compilateur :

class Eleve {}
 
interface EleveDao {
    function trouverParNom($nom): Eleve; 
}
 
class EleveSqlDao implements EleveDao {

    function trouverParNom($nom) {
        // mes plus belles requêtes SQL 
        return new Eleve();
    }
}
Fatal error: Declaration of EleveSqlDao::trouverParNom($nom) must be compatible with EleveDao::trouverParNom($nom): Eleve

Notez que ce comportement pourrait être modifié dans les versions futures du langage.

Peut-on renvoyer « rien » ?

Il y a eu une tentative d’introduire un type void comme en C/C++ ou Java mais cette proposition a été rejetée. Vous savez que par défaut une fonction PHP renvoie null :

function rien() {}

var_dump(rien());
# NULL

Quand on écrit void, on notifie que la fonction ne renvoie rien. Or null par défaut est retourné par PHP, ce sont deux choses différentes.

Avec void on ne renvoie rien, avec return null on renvoie « absence de valeur » !

Quid des fonctions spéciales ?

Certaines fonctions ne sont pas autorisées à faire usage des types de retour :

  • les constructeurs
  • les destructeurs
  • les fonctions de clonage

En tentant de le faire, vous provoqueriez des erreurs fatales.

En résumé

Coluche disait « Voilà une nouvelle qu’elle est bonne ! »; une délicieuse formule qui s’applique à cette nouvelle fonctionnalité qui, avec le typage strict et de nombreuses autres features, constitue une avancée majeure dans le cycle de vie de notre langage préféré. L’introduction de ces possibilités est l’occasion une fois de plus de renforcer la bonne hygiène de vos développements ! Il reste encore des points à régler (void notamment, qu’on espère voir arriver un jour !) mais tout va dans la bonne direction !

PHP : La loi de Déméter en quelques exemples

La loi de Déméter (LoD en anglais, pour Law of Demeter) est un principe de design de systèmes dits « orientés objet ». Son principe élémentaire tient en une phrase :

« Ne parle qu’à tes amis »

Ce principe de conception orientée objet à été évoqué pour la première fois en 1987 à la Northeastern University de Boston (Massachussets) par Ian Holland qui travaillait alors sur un projet du nom de Demeter. Le but de cette « loi » est de maintenir un couplage laĉhe entre les classes.

Ce que permet LoD

LoD nous donne pour principe la chose suivante :

Une méthode dans un objet donné doit seulement invoquer les méthodes des types d’objets suivants : l’objet lui-même, ses objets paramètres, les objets qu’il crée, les objets qu’il a en composition

L’objet lui-même


class A {
    public function __construct() {
        $this->_faireUnTruc();
    }

    protected function _faireUnTruc() {}
}

L’objet instance de A sera autorisé à appeler ses propres fonctions (tout de même…)

Ses paramètres


class B {
    public function faireQuelqueChose() {}
}

class A {
    public function __construct(B $b) {
        $b->faireQuelqueChose();
    }

    protected function _faireUnTruc() {}
}

N’importe quel objet créé dans la classe

class C {
    public function faireDesMiracles() {}
}

class A {
    public function __construct() {
        		$c = new C;
        		$c->faireDesMiracles();
    }
}

Les objets en composition

class D {
    public function faireAutreChose() {}
}

class A {
    private $_d;

    public function __construct() {
        $c = new D;
    }

    public function faireDesChoses() {
        $this->_d->faireAutreChose();
    }
}

Ce qui remet en cause LoD

class C {
    public function faireBeaucoupDeChoses() {}
}

class B {
    private $_c;

    public function __construct(C $c) {
        $this->_c = $c;
    }

    public function getC() {
        return $this->_c;
    }
}

class A {
    private $_d;

    public function __construct() {
        $c = new C;
        $b = new B($c);
        $b->getC()->faireBeaucoupDeChoses();
    }
}

Dans cet exemple, ce n’est pas le chaînage des méthodes en lui-même qui pose un problème mais le fait que A fasse appel à C à travers B. Idéalement, A fait appel à B qui lui, délègue le service demandé à C de sorte que nous n’aurions plus que :

$b->faireBeaucoupDeChoses();

et


class B {
    private $_c;

    public function __construct(C $c) {
        $this->_c = $c;
    }

    public function faireBeaucoupDeChoses() {
        return $this->_c->faireBeaucoupDeChoses();
    }
}

Ici, chaque classe parle à ses amis les plus proches (A à B, B à C) et Déméter n’en sera pas offusquée !

Pour en savoir plus…

Un billet du blog d’Avdi Grimm (anglais)

La page du projet Demeter (anglais)

Les principes SOLID expliquées à ma fille

Ma fille ne comprend rien à l’informatique. Il faut dire qu’à 6 ans, on a autre chose à faire que de se passionner pour ces choses bizarres ! Et puis l’informatique ça a l’air compliqué ! On voit souvent Papa se prendre la tête à deux mains en se demandant pourquoi c’est fait de manière si compliquée alors que le problème adressé est on ne peut plus simple. J’ai tout de même essayé de m’imaginer en train d’expliquer à ma petite tête brune à couettes les principes SOLID, énoncés par « Uncle Bob » il y a maintenant plus d’une décennie.

Commençons par le commencement : le S de SOLID, c’est pour Single Responsibility (responsabilité unique) : une classe n’est pas comme ces équipiers qu’on voit au comptoir des fast-foods; elle ne doit pas faire le drive-in, servir les boissons, nettoyer les tables, faire chauffer les frites, non : UNE SEULE chose à la fois.

Le O c’est pour Open/Closed (ouvert/fermé) : une classe doit être fermée à la modification (de son code source) mais ouverte à l’extension : on n’essaie pas de faire rentrer un carré dans un rond, on crée une « forme », qu’on spécialisera ensuite en rond, carré, losange, triangle, etc.

Le L rend hommage à Madame Barbara Liskov et son principe de substitution: mon objet chimpanzé de la classe Singe a une méthode manger(Fruit) : la banane, la mangue et la noix de coco sont des fruits; ma méthode manger doit avoir le même comportement que je fasse manger(Banane), manger(Mangue) ou manger(Coco), c’est à dire si je substitue le sous-type Banane, Mangue ou Coco au super-type Fruit.

Le I évoque la ségrégation des interfaces (Interface Segregation) : certains animaux savent voler, le singe est un animal mais ne sait pas voler. Pourquoi le faire dépendre d’une classe Animal qui implémenterait une interface AnimalVolant si on sait qu’il ne volera jamais ? Ce principe est très simple : une classe ne doit pas dépendre d’interfaces dont elle n’a pas l’utilité ! L’objectif est ici, une fois de plus, de réduire le couplage inutile entre les classes.

Le dernier de ces 5 principes est le principe d’inversion des dépendances (D pour Dependency Inversion). A est client de B, lui-même client de C; on peut dire que A dépend de B qui dépend de C. Prenons A et B: ce n’est plus A qui va dépendre de B, mais A qui va dire à B ce dont il a besoin. B ne dit plus à A « voilà comment je fonctionne, débrouille toi ! », c’est A qui dit à B « voilà ce dont j’ai besoin, donne le moi ! »…Nous avons donc bien inversé le rapport de force entre fournisseur et client !

Allez, je vous laisse, j’ai un match entre les Littlest Pet Shop et les My little Pony à gérer…

IMG_3521

Sources :

Pour ceux que l’anglais ne rebute pas, je vous conseille l’excellent site d’Oncle Bob et ses hilarants (autant qu’instructifs) codecastsCleanCoders

Toujours dans la langue de Shakespeare…

http://aspiringcraftsman.com/2008/12/28/examining-dependency-inversion/