Classes & PHP

PHP5

PHP5 offre, grâce au Zend Engine 2, une gestion complète de la programmation objet. Je vais donc présenter une à une les différentes nouveautés de PHP5.

Visibilité

Dans PHP4, tous les attributs et méthodes sont visibles que ce soit à l'intérieur même de la classe ou de l'extérieur. PHP5 introduit les 3 niveaux de visibilité :

Voici un exemple :

class A {
	public $var1;
	protected $var2;
	private $var3;

	public function method1()
	{
		// Do stuff...
	}

	protected function method2()
	{
		// Do stuff...
	}

	private function method3()
	{
		// Do stuff too...
	}
}

Télécharger le code de l'exemple

Classe abstraite

Une classe abstraite est une classe dont toutes les méthodes ne sont pas définies. Elle ne peut être instanciée. Elle permet de prototyper les classes. Une classe ne peut hériter que d'une seule classe qu'elle soit abstraite ou non.

Voici un exemple :

abstract class AbstractClass
{
	public function method1()
	{
		echo __METHOD__."\n";
	}

	public abstract function method2();
}

class ImplementedClass extends AbstractClass
{
	public function method2()
	{
		echo __METHOD__."\n";
	}
}

$a = new ImplementedClass();
$a->method1();
$a->method2();

Ceci produira :

AbstractClass::method1
ImplementedClass::method2

Télécharger le code de l'exemple

Interface

Une interface est le prototype d'une classe, elle n'implémente pas les méthodes. Une classe peut implémenter plusieurs interfaces.

Voici un exemple :

interface People
{
	public function getName();
}

class PeopleImpl implements People
{
	public function getName()
	{
		return 'Guy Liguili';
	}
}

$a = new PeopleImpl();
echo "Nom : ".$a->getName()."\n";

Télécharger le code de l'exemple

Typage

Les classes abstraites et surtout les interfaces présentent bien peu d'intérêt si l'on ne peut pas typer les données.

interface A
{
	public function a(A $a);
}

interface B
{
	public function b(B $b);
}

class Test implements A, B
{
	public function a(A $a)
	{
		echo __METHOD__."\n";
	}

	public function b(B $b)
	{
		echo __METHOD__."\n";
	}
}

$t = new Test();
$t->a($t);
$t->b($t);

Si l'on tente de fournir un objet qui ne soit pas du type demandé, une erreur est générée. Cependant, cette technique ne fonctionne qu'avec les objets, les types de base ne peuvent être spécifiés.

Le code suivant :

public function test(ClassName $o)
{
	// Do stuff...
}

est identique à celui-ci :

function foo($o)
{
	if (!is_a($o, 'ClassName'))
		die("Argument 1 must be an instance of ClassName");
}

Télécharger le code de l'exemple

Mot-clé final

Le mot clé final indique que l'attibut, la méthode ou la classe ne peuvent être surchargés.

class Test
{
	public final function test()
	{
		// Do stuff... cannot be overload !
	}
}

Clonage

Etant donné que les objets sont passés par référence et non plus par copie, il devient parfois nécessaire de pouvoir copier un objet explicitement, c'est le role du mot-clé clone.

class Dog
{
	public $nick;
}

$a = new Dog();
$a->nick = 'Raoul le pitbull';
$b = clone $a;
$b->nick = 'Hubert le cocker';

echo $a->nick."\n";
echo $b->nick."\n";
echo "--------------------\n";

class Paper
{
	public $type = 'original';

	function __clone()
	{
		$this->type = 'copie';
	}
}

$c = new Paper();
$d = clone $c;

echo $c->type."\n";
echo $d->type."\n";

Ceci produira :

Raoul le pitbull
Hubert le cocker
--------------------
original
copie

On peut donc soit laisser PHP prendre en main le clonage soit le définir explicitement via la méthode __clone.

Télécharger le code de l'exemple

Constructeurs & destructeurs

Dans PHP4, les constructeurs portaient le nom de la classe. Dans PHP5, ils sont renommés et s'appellent __construct. Les appels au constructeur parent doivent toujours être explicites. D'autre part, les destructeurs sont cette fois-ci gérés par défaut avec la méthode __destruct.

Voici un exemple de code :

class A
{
	function __construct()
	{
		echo __METHOD__."\n";
	}

	function __destruct()
	{
		echo __METHOD__."\n";
	}
}

class B extends A
{
	function __construct()
	{
		parent::__construct();
		echo __METHOD__."\n";
	}

	function __destruct()
	{
		echo __METHOD__."\n";
		parent::__destruct();
	}
}

$b = new B();

Ceci produira :

A::__construct
B::__construct
B::__destruct
A::__destruct

Le destructeur est appelé lors de la destruction explicite de l'objet ou lorsque la fin du script est atteinte.

Télécharger le code de l'exemple

Constantes

PHP5 définit des constantes de classe grâce au mot-clé const.

class A
{
	const CONST_VAR1 = 'Var1';
	const CONST_VAR2 = 'Var2';
}

echo A::CONST_VAR1;

Télécharger le code de l'exemple

Exceptions

Les exceptions permettent d'arrêter le fonctionnement normal d'un traitement afin d'en signaler les erreurs. Cependant, le fonctionnement des exceptions n'est pas idyllique comparé aux autres langages :

Voici un exemple :

try {
	$error = "Toujours lancer cette erreur";
	throw new Exception($error);

	echo "Jamais exécuté\n";
}
catch (Exception $e) {
	echo "Capture de l'exception : ".$e->getMessage()."\n";
}

echo "Reprise du fonctionnement normal\n";

Il peut y avoir plusieurs blocs catch. Si l'exception n'est pas récupérée, elle remonte jusqu'à l'arrêt complet du script.

Télécharger le code de l'exemple

Objets retournés

En PHP4, lorsqu'une fonction retourne un objet, il est impossible de directement l'exploiter et d'appeler ses méthodes. Ceci est résolu en PHP5 et fonctionne correctement.

Voici un exemple :

class Dog
{
	public $nick;

	function __construct($nick)
	{
		$this->nick = $nick;
	}
}

class Master
{
	private $dog;

	function __construct()
	{
		$this->dog = new Dog('Raoul le pitbull');
	}

	function getDog()
	{
		return $this->dog;
	}
}

$m = new Master();
echo $m->getDog()->nick;

Télécharger le code de l'exemple

Static

Le mot-clé static permet de déclarer des méthodes ou attibuts accessibles sans avoir besoin d'instancier la classe.

class Test
{
	public static $var = 'Var1';

	public static function execute()
	{
		echo __METHOD__."\n";
	}
}

echo Test::$var."\n";
Test::execute();

Télécharger le code de l'exemple

Instanceof

L'opérateur instanceof est l'équivalent de la fonction is_a qui permet de savoir si un objet est d'une certaine classe ou d'une de ses classes fille.

Voici un exemple :

class A
{
	public $var1;
}

class B extends A
{
	public $var2;
}

class C
{
	public $var3;
}

$b = new B();
echo ($b instanceof A) ? "true\n" : "false\n";
echo ($b instanceof B) ? "true\n" : "false\n";
echo ($b instanceof C) ? "true\n" : "false\n";

Ceci produira :

true
true
false

Télécharger le code de l'exemple

Passage par référence

En PHP4, tous les objets et variables sont passés en paramètre par copie. En PHP5, les objets passent par référence.

Voici un exemple

class Dog
{
	public $nick;
	function __construct($nick)
	{
		$this->nick = $nick;
	}
}

function f1($dog)
{
	$dog->nick = 'Hubert le cocker';
}

function f2($str)
{
	$str = 'Hubert le cocker';
}

function f3(&$str = 'Raoul le pitbull')
{
	echo $str."\n";
	$str = 'Hubert le cocker';
}

// Passage d'un objet par référence
$dog = new Dog('Raoul le pitbull');
echo $dog->nick."\n";
f1($dog);
echo $dog->nick."\n";
echo "--------------------\n";

// Passage d'une variable par copie
$str = 'Raoul le pitbull';
f2($str);
echo $str."\n";
echo "--------------------\n";

// Passage d'une variable par référence avec valeur par défaut
// Impossible en PHP4 !
$str = 'toto';
f3($str);
echo $str."\n";
f3();

Ceci produira :

Raoul le pitbull
Hubert le cocker
--------------------
Raoul le pitbull
--------------------
toto
Hubert le cocker
Raoul le pitbull

Dans la première partie, on constate que les objets sont bien passés par référence, nouveauté de PHP5.

Dans la seconde partie, on constate que tout comme en PHP4, les variables (chaines, entiers, etc...) sont passées par copie.

La troisième et dernière partie montre une autre nouveauté de PHP5. Les passages par référence acceptent enfin d'avoir des valeurs par défaut, ce qui est très pratique car on ne peut avoir deux méthodes de même nom avec des paramètres différents.

Télécharger le code de l'exemple

__toString

PHP5 définit une nouvelle méthode __toString qui est appelée lors de l'affichage d'un objet.

Voici un exemple :

class A
{
	function __toString()
	{
		return 'A, la classe';
	}
}

class B
{
}

$a = new A();
echo $a;
echo "\n";
echo $a."\n";
echo $a,"\n";
echo "---------------------\n";
$b = new B();
echo $b;
echo "\n";
echo $b."\n";
echo $b,"\n";

Ceci produira :

A, la classe
Object id #1
A, la classe
---------------------
Object id #2
Object id #2
Object id #2

On constate que la méthode __toString n'est pas toujours appelée lorsqu'elle est définie. Lorsque l'objet est concaténé avec une chaîne de caractère, la méthode n'est pas appelée.

Télécharger le code de l'exemple