Blog

#AstuceDeCode 9 – Les constructeurs en PHP

Astuce de code.PHP
Share Button

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 !

Adrien Motte, développeur

Share Button

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>