#AstuceDeCode 9 – Les constructeurs en PHP

En PHP, on a un petit souci avec les classes, qui n’ont pas autant de features que les autres langages. Aujourd’hui, nous allons voir comment s’en sortir proprement pour pouvoir appeler plusieurs constructeurs dans une classe PHP.

En effet, en PHP, il n’y a pas de possibilité de surcharger les constructeurs de classe pour pouvoir les appeler avec différents arguments, comme dans pas mal d’autre langages, comme le C# par exemple:


public class Foo
{
     public int bar;

 public Foo()
 {
  // Trucs à initialiser communs aux deux constructions
 }
     public Foo(int arg1)
  :this()
     {
         bar = arg1;
     }
     public Foo(int arg2, int arg3)
  :this()
     {
         bar = arg2 + arg3;
     }
}

La, en PHP, on n’a pas de solution égale à ça, pas moyen de dupliquer le magique _construct() en fonction des besoins.

Dans ce cas là, j’ai souvent vu du code avec pas mal de conditions dans le constructeurs, un peu comme celui-là:


class Foo {
 public $bar;

 function __construct()
 {
  switch(func_num_args())
  {
   case 1:
    $this->bar = func_get_arg(0);
    break;
   case 2:
    $this->bar = func_get_arg(0) + func_get_arg(1);
    break;
  }
  // Trucs à initialiser communs aux deux constructions
 }
}

// Initialisation
$a = new Foo(42); // Bar = 42
$b = new Foo(20, 15); // Bar = 35

Bon. Ce code amène un gros souci…

Si on a un tant soit peu d’ambition pour notre classe Foo, et qu’on voudrait faire plus de deux simples constructeurs, ça va vite devenir la capharnaüm la-dedans. Sans compter que dans l’exemple, il n’y a que le nombre d’arguments de vérifiés.
Imaginez que vous voulez faire une construction différente en passant un array, un int, ou autre chose dans le constructeur. Il faudra faire d’autant plus de conditions qui deviendrons vite illisibles à cet endroit.
Bref, un code qui sera compliqué à maintenir, et à relire.

Il existe pourtant une méthode pour faire de la multi-construction en PHP que j’utilise souvent. Enfin, pas vraiment… C’est plutôt une feinte avec des helpers statiques dans la classe. Oui, ça n’envoie pas du rêve, mais c’est quand même bien utile pour éviter le plat de spaghettis, vous vous remercierez plus tard quand vous devrez agrandir votre classe. 🙂


class Foo {
 public $bar;

 function __construct() {
  // Trucs à initialiser communs aux deux constructions
 }

 static public function __construct_with_one_arg($arg) {
  $instance = new static();
  $instance->bar = $arg;
  return $instance;
 }

 static public function __construct_with_two_args($arg1, $arg2) {
  $instance = new static();
  $instance->bar = $arg1 + $arg2;
  return $instance;
 }
}

//Initialisation
$a = Foo::__construct_with_one_arg(42); // Bar = 42
$b = Foo::__construct_with_two_args(20, 15); // Bar = 35

Cette méthode a pas mal d’avantages :

– Déjà, nous évitons le code illisible « spaghetti » en cas de code complexe. Comme par exemple avec 4 ou 5 constructions différentes, il va être compliqué de débuger ça si on a une grosse masse de conditions, alors qu’ici, on aura une fonction par construction et une fonction pour l’initialisation commune.

– Ensuite, l’héritage ! Imaginons une classe enfant qui hérite de Foo, et qui devrait avoir un autre constructeur. Avec les conditions dans le « __construct() », on risque de mettre un temps incroyable pour rajouter une autre construction, suivant sa condition. Alors qu’ici, on a juste à rajouter une fonction statique, ou même réécrire un constructeur, et même hériter simplement du code commun du parent avec un « parent::__construct() ».

– Enfin, mais c’est personnel, je trouve cela plus « parlant » d’instancier sa classe via ceci


$a = Foo::__construct_with_one_arg(42);

que par un simple « new() », ce qui peut faire gagner du temps lors d’un debug, ou d’une relecture.

BONUS STAGE

Si vous ajoutez des « return $this » à vos setters, vous pouvez même ‘chainer’ les appels, pour rendre cela très explicite, et human-friendly (et vous adonner, tel un JAVAiste ou autre, au method chaining).


class Foo {
 public $bar;
 public $baz;

 // ...

 public function set_baz($arg) {
  $this->baz = $arg;
  return $this;
 }
}
// Appel en chaine
$a = Foo::__construct_with_one_arg(42)->set_baz("Hello le monde !");
// Et le setter marche aussi sans le chainer
$a->set_baz("Hola mundo !");

Voila, une petite astuce de PHP pour rendre le code plus lisible, qui, personnellement, m’évite de m’user la rétine trop souvent lors d’un retour sur du code. J’espère qu’elle vous sera utile, et qu’elle aidera à aller plus loin en PHP !

Envie de partager votre astuce de code ?

Cette astuce de code vous est proposé par Adrien !

Jobprod

Recent Posts

Communauté Tech et féminine : Interview avec Helvira de Motiv’her

Elles sont passées où les femmes dans la tech ? Entre le manque de représentation…

1 jour ago

Consommer des APIs HTTP en PHP comme un pro avec Nicolas Grekas.

Dans cette vidéo, on interview Nicolas Grekas, contributeur clé de Symfony, pour discuter de sa…

1 jour ago

Trouver son job grâce à WeLoveDevs.

 Comment trouver son job dans la tech ? Marie a la réponse ! Grâce à…

3 jours ago

Adobe, L’empire créatif.

Adobe, l'empire créatif, et pas des moindres ! Belle ascension de la part de ces…

7 jours ago

La MAO musique ou musique assistée par ordinateur

Est-ce plus simple de créer des morceaux avec les outils de Musique Assistée par Ordinateur…

7 jours ago