mirror of
https://github.com/macintoshplus/doc-fr.git
synced 2026-03-29 04:12:21 +02:00
git-svn-id: https://svn.php.net/repository/phpdoc/fr/trunk@278265 c90b9560-bf6c-de11-be94-00142212c4b1
1149 lines
32 KiB
XML
1149 lines
32 KiB
XML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<!-- $Revision: 1.74 $ -->
|
|
<!-- EN-Revision: 1.72 Maintainer: yannick Status: ready -->
|
|
<!-- Reviewed: yes -->
|
|
|
|
<chapter xml:id="language.oop" xmlns="http://docbook.org/ns/docbook">
|
|
<title>Les classes et les objets (PHP 4)</title>
|
|
|
|
<sect1 xml:id="keyword.class">
|
|
<title>Les classes : <literal>class</literal></title>
|
|
<para>
|
|
Une classe est une collection de variables et de fonctions qui
|
|
fonctionnent avec ces variables. Les variables sont définies par
|
|
l'élément <literal>var</literal> et les fonctions par
|
|
<literal>function</literal>. Une classe est définie
|
|
en utilisant la syntaxe suivante :
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Panier {
|
|
// Eléments de notre panier
|
|
var $items;
|
|
|
|
// Ajout de $num articles de type $artnr au panier
|
|
|
|
function add_item($artnr, $num) {
|
|
$this->items[$artnr] += $num;
|
|
}
|
|
|
|
// Suppression de $num articles du type $artnr du panier
|
|
|
|
function remove_item($artnr, $num) {
|
|
if ($this->items[$artnr] > $num) {
|
|
$this->items[$artnr] -= $num;
|
|
return true;
|
|
} elseif ($this->items[$artnr] == $num) {
|
|
unset($this->items[$artnr]);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
|
|
<para>
|
|
L'exemple ci-dessus définit la classe Panier qui est composée
|
|
d'un tableau associatif contenant les articles du panier et de deux
|
|
fonctions, une pour ajouter et une pour enlever des éléments
|
|
au panier.
|
|
</para>
|
|
|
|
<warning>
|
|
<simpara>
|
|
Vous <emphasis>NE POUVEZ PAS</emphasis> couper la définition d'une
|
|
classe en plusieurs fichiers. De la même façon, vous <emphasis>NE POUVEZ
|
|
PAS</emphasis> couper la définition d'une classe en de multiples blocs, à
|
|
moins que la coupure ne soit à l'intérieur de la déclaration d'une
|
|
méthode. Ce qui suit ne fonctionnera pas :
|
|
</simpara>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class test {
|
|
?>
|
|
<?php
|
|
function test() {
|
|
print 'OK';
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<simpara>
|
|
Néanmoins, ce qui suit est autorisé :
|
|
</simpara>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class test {
|
|
function test() {
|
|
?>
|
|
<?php
|
|
print 'OK';
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
</warning>
|
|
<simpara>
|
|
Les notes suivantes ne sont valables que pour PHP 4.
|
|
</simpara>
|
|
|
|
<caution>
|
|
<simpara>
|
|
Le nom <literal>stdClass</literal> est utilisé en interne par
|
|
Zend et ne doit pas être utilisé. Vous ne pouvez pas nommer
|
|
une classe <literal>stdClass</literal> en PHP.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<caution>
|
|
<simpara>
|
|
Les noms de fonctions <literal>__sleep</literal> et
|
|
<literal>__wakeup</literal> sont magiques en PHP. Vous ne pouvez
|
|
pas utiliser ces noms de fonctions dans vos classes, à moins
|
|
que vous ne souhaitiez utiliser la magie qui y est associée.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<caution>
|
|
<simpara>
|
|
PHP se réserve l'usage de tous les noms de fonctions
|
|
commençant par <literal>__</literal>, pour sa propre magie.
|
|
Il est vivement recommandé de ne pas utiliser des noms de fonctions
|
|
commençant par <literal>__</literal>, à moins que vous ne
|
|
souhaitiez utiliser la magie qui y est associée.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<simpara>
|
|
En PHP 4, seuls les initialiseurs constants pour les variables
|
|
<literal>var</literal> sont autorisés. Utilisez les
|
|
constructeurs pour les initialisations variables, ou utilisant
|
|
des expressions.
|
|
</simpara>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/* Aucune de ces syntaxes ne fonctionnera en PHP 4 */
|
|
class Panier {
|
|
var $date_du_jour = date("d/m/Y");
|
|
var $name = $firstname;
|
|
var $owner = 'Fred ' . 'Jones';
|
|
var $items = array("DVD", "Télé","Magnétoscope");
|
|
}
|
|
/* Voici comment cela doit se faire désormais. */
|
|
class Panier {
|
|
var $date_du_jour;
|
|
var $name;
|
|
var $owner;
|
|
var $items;
|
|
function Panier() {
|
|
$this->date_du_jour = date("d/m/Y");
|
|
$this->name = $GLOBALS['firstname'];
|
|
/* etc. */
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
Les classes forment un type de variable. Pour créer une variable
|
|
du type désiré, vous devez utiliser l'opérateur <literal>new</literal>.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$cart = new Panier;
|
|
$cart->add_item("10", 1);
|
|
|
|
$another_cart = new Panier;
|
|
$another_cart->add_item("0815", 3);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
L'instruction ci-dessus crée l'objet <varname>$cart</varname> de la classe
|
|
<classname>Panier</classname>.
|
|
La fonction <literal>add_idem()</literal> est appelée afin d'ajouter
|
|
l'article numéro 10 dans le panier. Trois articles numéro 0815 sont
|
|
ajoutés au panier <varname>$another_cart</varname>.
|
|
</para>
|
|
|
|
<para>
|
|
<varname>$cart</varname> et <varname>$another_cart</varname> disposent des
|
|
fonctions <literal>add_item()</literal>, <literal>remove_item()</literal>
|
|
et de la variable <varname>items</varname>. Ce sont des fonctions
|
|
et variables distinctes. Vous pouvez vous représenter les
|
|
objets comme des dossiers sur votre disque dur. Vous pouvez
|
|
avoir deux fichiers <filename>lisez-moi.txt</filename> sur votre disque dur,
|
|
tant qu'ils ne sont pas dans le même répertoire. De même que vous
|
|
devez alors taper le chemin complet jusqu'au fichier, vous devez
|
|
spécifier le nom complet de la méthode avant de l'employer :
|
|
en termes PHP, le dossier racine est l'espace de nom global, et le
|
|
séparateur de dossier est <literal>-></literal>. Par exemple,
|
|
les noms <varname>$cart->items</varname> et
|
|
<varname>$another_cart->items</varname> représentent deux
|
|
variables distinctes. Notez que le nom de la variable est alors
|
|
<varname>$cart->items,</varname> et non pas
|
|
<varname>$cart->$items</varname> : il n'y a qu'un seul
|
|
signe <literal>$</literal> dans un nom de variable.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// correct, le signe $ est unique
|
|
$cart->items = array("10" => 1);
|
|
|
|
// incorrect, car $cart->$items devient $cart->""
|
|
$cart->$items = array("10" => 1);
|
|
|
|
// correct, mais risque de ne pas se comporter comme prévu
|
|
// $cart->$myvar devient $cart->items
|
|
$myvar = 'items';
|
|
$cart->$myvar = array("10" => 1);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
À l'intérieur d'une définition de classe, vous ne savez pas le
|
|
nom de la variable à partir duquel l'objet sera accessible dans
|
|
le script. On ne peut prévoir que l'objet créé sera
|
|
affecté à la variable <varname>$cart</varname>,
|
|
<varname>$another_cart</varname> ou quelque chose d'autres. Donc, vous ne
|
|
pouvez pas utiliser la syntaxe <varname>$cart->items.</varname> Mais pour
|
|
pouvoir accéder aux méthodes et membres d'un objet, vous pouvez utiliser
|
|
la variable spéciale <varname>$this,</varname> qui peut s'interpréter comme
|
|
"moi-même", ou bien "l'objet courant". Par exemple,
|
|
<literal>'$this->items[$artnr] += $num;'</literal>
|
|
peut se lire comme 'ajouter <varname>$num</varname> au compteur
|
|
<varname>$artnr</varname> de mon propre tableau de compteur' ou bien
|
|
'ajouter <varname>$num</varname> au compteur <varname>$artnr</varname> du
|
|
tableau de compteurs de l'objet courant'.
|
|
</para>
|
|
|
|
<note>
|
|
<para>
|
|
La pseudo-variable <varname>$this</varname> n'est pas toujours définie si
|
|
la méthode dans laquelle elle est présente est appelée statiquement.
|
|
Cependant, ceci n'est pas une règle stricte : <varname>$this</varname>
|
|
est définie si une méthode est appelée statiquement depuis un autre objet.
|
|
Dans ce cas, sa valeur vaut l'objet appelé. Ce comportement est illustré
|
|
dans l'exemple ci-dessous :
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class A
|
|
{
|
|
function foo()
|
|
{
|
|
if (isset($this)) {
|
|
echo '$this est défini (';
|
|
echo get_class($this);
|
|
echo ")\n";
|
|
} else {
|
|
echo "\$this n'est pas défini.\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
class B
|
|
{
|
|
function bar()
|
|
{
|
|
A::foo();
|
|
}
|
|
}
|
|
|
|
$a = new A();
|
|
$a->foo();
|
|
A::foo();
|
|
$b = new B();
|
|
$b->bar();
|
|
B::bar();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
$this est défini (a)
|
|
$this n'est pas défini.
|
|
$this est défini (b)
|
|
$this n'est pas défini.
|
|
]]>
|
|
</screen>
|
|
</informalexample>
|
|
</para>
|
|
</note>
|
|
|
|
<note>
|
|
<para>
|
|
Il y a des fonctions très pratiques pour gérer les classes et objets.
|
|
Vous pouvez étudier le chapitre sur les
|
|
<link linkend="ref.classobj">fonctions de classes et objets</link>.
|
|
</para>
|
|
</note>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="keyword.extends">
|
|
<title><literal>extends</literal> : héritage</title>
|
|
|
|
<para>
|
|
Souvent, vous aurez besoin d'une classe avec des méthodes et
|
|
fonctions similaires à une autre classe. En fait, il est bon
|
|
de définir des classes génériques, qui pourront
|
|
être réutilisées et adaptées à tous
|
|
vos projets. Pour faciliter cela, une classe peut être une extension
|
|
d'une autre classe. La classe dérivée hérite alors de
|
|
toutes les méthodes et variables de la classe de base (cet
|
|
héritage a de bien que personne ne meurt pour en profiter), mais peut
|
|
définir ses propres fonctions et variables, qui s'ajouteront. Une
|
|
classe ne peut hériter que d'une seule autre classe, et l'héritage
|
|
multiple n'est pas supporté. Les héritages se font avec le mot
|
|
clé '<literal>extends</literal>'.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Panier_nomme extends Panier {
|
|
var $owner;
|
|
|
|
function set_owner ($name) {
|
|
$this->owner = $name;
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
L'exemple ci-dessus définit la classe <classname>Panier_nomme</classname>
|
|
qui possède les mêmes variables que la classe Panier et
|
|
la variable <varname>$owner</varname> en plus, ainsi que la fonction
|
|
<literal>set_owner()</literal>.
|
|
Vous créez un panier nominatif de la même
|
|
manière que précédemment, et vous pouvez alors
|
|
affecter un nom au panier ou en connaître le nom. Vous pouvez de
|
|
toutes les façons utiliser les mêmes fonctions que sur un
|
|
panier classique.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$ncart = new Panier_nomme; // Création d'un panier nominatif
|
|
$ncart->set_owner ("kris"); // Affectation du nom du panier
|
|
print $ncart->owner; // Affichage du nom du panier
|
|
$ncart->add_item ("10", 1); // (héritage des fonctions de la classe père)
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
Ceci est également appelé une relation "parent-enfant". Vous créez une
|
|
classe parent, et utilisez <literal>extends</literal> pour créer une
|
|
nouvelle classe <emphasis>basée</emphasis> sur la classe parent : la
|
|
classe enfant. Vous pouvez toujours utiliser cette nouvelle classe enfant
|
|
et en créer une nouvelle basée sur cette classe enfant.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Les classes doivent être définies avant d'être utilisées ! Si vous voulez
|
|
que la classe <literal>Named_Cart</literal> étende la classe
|
|
<literal>Cart</literal>, vous devez d'abord définir la classe
|
|
<literal>Cart</literal>. Si vous voulez créer une autre classe appelée
|
|
<literal>Yellow_named_cart</literal>, basée sur la classe
|
|
<literal>Named_Cart</literal>, vous devez d'abord définir la classe
|
|
<literal>Named_Cart</literal>. Pour faire court : l'ordre dans lequel
|
|
les classes sont définies est important.
|
|
</para>
|
|
</note>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.oop.constructor">
|
|
<title>Constructeur</title>
|
|
|
|
<para>
|
|
Le constructeur est la fonction qui est appelée
|
|
automatiquement par la classe lorsque vous créez
|
|
une nouvelle instance d'une classe à l'aide de l'opérateur
|
|
<literal>new</literal>. La fonction constructeur a
|
|
le même nom que la classe.
|
|
Une fonction devient le constructeur si elle porte le
|
|
même nom que la classe. Si une classe n'a pas de constructeur,
|
|
le constructeur de la classe de base sera appelé, s'il existe.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Auto_Panier extends Panier {
|
|
function Auto_Panier () {
|
|
$this->add_item ("10", 1);
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
L'exemple ci-dessus définit la classe <classname>Auto_Panier</classname>
|
|
qui hérite de la classe Panier et définit le constructeur
|
|
de la classe. Ce dernier initialise le panier avec 1 article de
|
|
type numéro 10 dès que l'instruction <literal>new</literal> est
|
|
appelée. La fonction constructeur peut prendre ou non
|
|
des paramètres optionnels, ce qui la rend beaucoup plus
|
|
pratique. Pour pouvoir utiliser cette classe sans paramètre,
|
|
tous les paramètres du constructeurs devraient être optionnels,
|
|
en fournissant une valeur par défaut, comme ci-dessous.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Constructor_Cart extends Cart {
|
|
function Constructor_Cart($item = "10", $num = 1) {
|
|
$this->add_item ($item, $num);
|
|
}
|
|
}
|
|
|
|
// Création du Panier
|
|
$default_cart = new Constructor_Cart;
|
|
|
|
// Création d'un vrai Panier
|
|
$different_cart = new Constructor_Cart("20", 17);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
Vous pouvez également utiliser l'opérateur <literal>@</literal> pour
|
|
<emphasis>empêcher</emphasis> les erreurs survenant dans le constructeur
|
|
de s'afficher, e.g. <literal>@new</literal>.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class A
|
|
{
|
|
function A()
|
|
{
|
|
echo "Je suis le constructeur de A.<br />\n";
|
|
}
|
|
|
|
function B()
|
|
{
|
|
echo "Je suis une fonction standard appelée B dans la classe A.<br />\n";
|
|
echo "Je ne suis pas le constructeur de A.<br />\n";
|
|
}
|
|
}
|
|
|
|
class B extends A
|
|
{
|
|
}
|
|
|
|
// Cette syntaxe va appeler B() comme constructeur.
|
|
$b = new B;
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
La fonction B() de la classe A va soudainement devenir le
|
|
constructeur de la classe B, bien qu'il n'ait pas été
|
|
prévu pour. PHP 4 ne se soucie guère si la fonction est
|
|
définie dans la classe B ou si elle a été héritée.
|
|
</para>
|
|
|
|
<caution>
|
|
<simpara>
|
|
PHP n'appelle pas automatiquement le constructeur de
|
|
la classe supérieure depuis le constructeur de la classe
|
|
dérivée. Il est de votre responsabilité de propager
|
|
l'appel des constructeurs.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<para>
|
|
Les destructeurs sont des fonctions qui sont appelées lorsqu'un
|
|
objet est détruit, soit avec la fonction <function>unset</function>
|
|
soit par simple sortie d'une fonction (cas des variables locales).
|
|
Il n'y a pas de destructeurs en PHP. Vous devez utiliser la
|
|
fonction <function>register_shutdown_function</function>
|
|
à la place pour simuler la plupart des effets des destructeurs.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="keyword.paamayim-nekudotayim"><!-- :-) -->
|
|
<title>Opérateur de contexte de classe (<literal>::</literal>)</title>
|
|
|
|
<caution>
|
|
<simpara>
|
|
La documentation suivante n'est valable que pour PHP 4 et plus récent.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<para>
|
|
Parfois, il est pratique de faire référence aux fonctions
|
|
et variables d'une classe de base, ou bien d'utiliser
|
|
des méthodes de classes qui n'ont pas encore d'objets
|
|
créés. L'opérateur <literal>::</literal> est là pour ces
|
|
situations.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class A {
|
|
function example() {
|
|
echo "Je suis la fonction originale A::example().<br />\n";
|
|
}
|
|
}
|
|
|
|
class B extends A {
|
|
function example() {
|
|
echo "Je suis la fonction redéfinie B::example().<br />\n";
|
|
A::example();
|
|
}
|
|
}
|
|
|
|
// Il n'y a pas d'objets de classe A.
|
|
// L'affichage est :
|
|
// Je suis la fonction originale A::example().<br />
|
|
A::example();
|
|
|
|
// Création d'un objet de la classe B.
|
|
$b = new B;
|
|
|
|
// L'affichage est :
|
|
// Je suis la fonction redéfinie B::example().<br />
|
|
// Je suis la fonction originale A::example().<br />
|
|
$b->example();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
Les exemples ci-dessus appellent la fonction <literal>example()</literal> dans la
|
|
classe A, mais il n'y a pas encore d'objet de classe A, alors il
|
|
n'est pas possible d'écrire <literal>$a->example()</literal>. À la place, on appelle
|
|
la fonction <literal>example()</literal> comme une fonction de classe, c'est-à-dire
|
|
avec le nom de la classe elle-même, et sans objet.
|
|
</para>
|
|
|
|
<para>
|
|
Il y a des fonctions de classe, mais pas de variables de classe.
|
|
En fait, il n'y a aucun objet au moment de l'appel de la fonction.
|
|
Donc, une fonction de classe ne peut accéder à aucune variable
|
|
(mais elle peut accéder aux variables locales et globales).
|
|
Il faut proscrire l'utilisation de <varname>$this</varname>.
|
|
</para>
|
|
|
|
<para>
|
|
Dans l'exemple ci-dessus, la classe B redéfinit la fonction <literal>example()</literal>.
|
|
La définition originale dans la classe A est remplacée par celle de
|
|
B, et n'est plus accessible depuis B, à moins que vous n'appeliez
|
|
spécifiquement la fonction <literal>example()</literal> de la classe A avec
|
|
l'opérateur ::. Écrivez <literal>A::example()</literal> pour cela (en fait,
|
|
il faudrait écrire <literal>parent::example()</literal>, comme expliqué dans
|
|
la section suivante).
|
|
</para>
|
|
|
|
<para>
|
|
Dans ce contexte, il y a un objet courant, qui peut avoir d'autres
|
|
variables objets. De ce fait, lorsqu'il est utilisé depuis une méthode
|
|
d'un objet, vous pouvez utiliser <varname>$this.</varname>
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 xml:id="keyword.parent">
|
|
<title><literal>parent</literal></title>
|
|
|
|
<para>
|
|
Il arrive que vous ayez à écrire du code qui faire référence
|
|
aux variables et fonctions des classes de base. C'est particulièrement
|
|
vrai si votre classe dérivée est une spécialisation de votre classe
|
|
de base.
|
|
</para>
|
|
|
|
<para>
|
|
Au lieu d'utiliser le nom littéral de votre classe de base dans
|
|
votre code, vous pouvez utiliser le mot réservé
|
|
<literal>parent</literal>, qui représente votre classe de
|
|
base (celle indiqué par <literal>extends</literal>, dans la déclaration
|
|
de votre classe). En faisant cela, vous évitez d'appeler le
|
|
nom de votre classe de base directement dans votre code.
|
|
Si votre héritage change, vous n'aurez plus qu'à modifier
|
|
le nom de la classe dans la déclaration <literal>extends</literal>
|
|
de votre classe.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class A {
|
|
function example() {
|
|
echo "Je suis A::example() et je fournis une fonctionnalité de base.<br />\n";
|
|
}
|
|
}
|
|
|
|
class B extends A {
|
|
function example() {
|
|
echo "Je suis B::example() et je fournis une fonctionnalité supplémentaire.<br />\n";
|
|
parent::example();
|
|
}
|
|
}
|
|
|
|
$b = new B;
|
|
|
|
// Cette syntaxe va appeler B::example(), qui, à sont tour, va appeler A::example().
|
|
$b->example();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.oop.serialization">
|
|
<title>Sauvegarde d'objets - cas des sessions</title>
|
|
|
|
<para>
|
|
<function>serialize</function> retourne une chaîne représentant
|
|
une valeur qui peut être stockée dans les sessions de PHP, ou une
|
|
base de données. <function>unserialize</function> peut relire cette
|
|
chaîne pour recréer la valeur originale. <function>serialize</function>
|
|
va sauver toutes les variables d'un objet. Le nom de la classe sera
|
|
sauvé mais par les méthodes de cet objet.
|
|
</para>
|
|
|
|
<para>
|
|
Pour permettre à <function>unserialize</function> de lire un objet,
|
|
la classe de cet objet doit être définie. C'est-à-dire, si vous avez
|
|
un objet <varname>$a</varname> de la classe A dans une page
|
|
<filename>php1.php</filename>, et que vous le
|
|
linéarisez avec <function>serialize</function>, vous obtiendrez une
|
|
chaîne qui fait référence à la classe A, et contient toutes les valeurs
|
|
de <varname>$a.</varname> Pour pouvoir le relire avec la fonction
|
|
<function>unserialize</function>
|
|
dans une page <filename>page2.php</filename>, il faut que la définition de la
|
|
classe A soit présente dans cette deuxième page. Cela peut se faire
|
|
de manière pratique en sauvant la définition de la classe A dans un
|
|
fichier séparé, et en l'incluant dans les deux pages <filename>page1.php</filename> et
|
|
<filename>page2.php</filename>.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// classa.inc:
|
|
|
|
class A {
|
|
var $one = 1;
|
|
|
|
function show_one() {
|
|
echo $this->one;
|
|
}
|
|
}
|
|
|
|
// page1.php:
|
|
|
|
include("classa.inc");
|
|
|
|
$a = new A;
|
|
$s = serialize($a);
|
|
// enregistrez $s où la page2.php pourra la trouver.
|
|
$fp = fopen("store", "w");
|
|
fwrite($fp, $s);
|
|
fclose($fp);
|
|
|
|
// page2.php:
|
|
|
|
// Ceci est nécessaire pour que unserialize() fonctionne correctement
|
|
include("classa.inc");
|
|
|
|
$s = implode("", @file("store"));
|
|
$a = unserialize($s);
|
|
|
|
// maintenant, utilisez la méthode show_one de l'objet $a.
|
|
$a->show_one();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
Si vous utilisez les sessions et la fonction <function>session_register</function>
|
|
pour sauver des objets, ces objets seront linéarisés automatiquement
|
|
avec la fonction <function>serialize</function> à la fin de chaque
|
|
script, et relus avec <function>unserialize</function> au début du prochain
|
|
script. Cela signifie que ces objets peuvent apparaître dans n'importe quelle
|
|
page qui utilise vos sessions.
|
|
</para>
|
|
|
|
<para>
|
|
Il est vivement recommandé d'inclure la définition de classe dans
|
|
toutes vos pages, même si vous n'utilisez pas ces classes dans
|
|
toutes vos pages. Si vous l'oubliez et qu'un tel objet est
|
|
présent, il perdra sa classe, et deviendra un objet de classe
|
|
<classname>__PHP_Incomplete_Class_Name</classname> sans aucune fonction et, donc, plutôt
|
|
inutile.
|
|
</para>
|
|
|
|
<para>
|
|
Si, dans l'exemple ci-dessus, <varname>$a</varname> devient un objet de
|
|
session avec l'utilisation de <literal>session_register("a")</literal>, vous
|
|
devez penser à inclure le fichier <literal>classa.inc</literal> dans toutes
|
|
vos pages, et pas seulement <filename>page1.php</filename> et <filename>page2.php</filename>.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.oop.magic-functions">
|
|
<title>Les fonctions magiques <literal>__sleep</literal> et <literal>__wakeup</literal></title>
|
|
<para>
|
|
<function>serialize</function> s'assure que votre classe a une méthode
|
|
avec le nom magique <literal>__sleep</literal>. Si c'est le cas, cette
|
|
fonction est appelée avant toute linéarisation. Elle peut alors nettoyer
|
|
l'objet et on s'attend à ce qu'elle retourne un tableau avec la liste des
|
|
noms de variables qui doivent être sauvées.
|
|
Si la méthode ne retourne rien, alors &null; est linéarisé et une alerte de type
|
|
E_NOTICE sera émise.
|
|
</para>
|
|
|
|
<para>
|
|
Le but avoué de <literal>__sleep</literal> est de valider les données en attente
|
|
ou d'effectuer des opérations de nettoyage. Cette fonction
|
|
est aussi pratique si vous avez de très grands objets qui n'ont pas
|
|
besoin d'être sauvés entièrement.
|
|
</para>
|
|
|
|
<para>
|
|
À l'inverse, <function>unserialize</function> s'assure de la présence
|
|
de la fonction magique <literal>__wakeup</literal>. Si elle existe, cette
|
|
fonction reconstruit toutes les ressources d'un objet.
|
|
</para>
|
|
|
|
<para>
|
|
Le but de cette fonction <literal>__wakeup</literal> est de rétablir
|
|
toutes les connexions aux bases de données, et de recréer les
|
|
variables qui n'ont pas été sauvées.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.oop.newref">
|
|
<title>Références dans un constructeur</title>
|
|
<para>
|
|
Créer des références dans un constructeur peut conduire à des résultats
|
|
étranges. Ce tutoriel vous guide pour éviter ces problèmes.
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Foo {
|
|
function Foo($name) {
|
|
// crée une référence dans le tableau global $globalref
|
|
global $globalref;
|
|
$globalref[] = &$this;
|
|
// donne le nom de la variable
|
|
$this->setName($name);
|
|
// et l'affiche
|
|
$this->echoName();
|
|
}
|
|
|
|
function echoName() {
|
|
echo "<br />", $this->name;
|
|
}
|
|
|
|
function setName($name) {
|
|
$this->name = $name;
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
|
|
<para>
|
|
Vérifions maintenant qu'il y a une différence entre
|
|
<varname>$bar1</varname> qui a été créé avec
|
|
<literal>=</literal> et <varname>$bar2</varname> qui a été
|
|
créé avec l'opérateur de référence
|
|
<literal>=&</literal> :
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$bar1 = new Foo('crée dans le constructeur');
|
|
$bar1->echoName();
|
|
$globalref[0]->echoName();
|
|
|
|
/* affiche :
|
|
crée dans le constructeur
|
|
crée dans le constructeur
|
|
crée dans le constructeur */
|
|
|
|
$bar2 =&new foo('crée dans le constructeur');
|
|
$bar2->echoName();
|
|
$globalref[1]->echoName();
|
|
|
|
/* affiche :
|
|
crée dans le constructeur
|
|
crée dans le constructeur
|
|
crée dans le constructeur */
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
Apparemment, il n'y a pas de différence, mais en fait, il y en a une
|
|
significative : <varname>$bar1</varname> et <varname>$globalref[0]</varname>
|
|
ne sont pas référencées, ces deux variables sont différentes.
|
|
Cela est dû au fait que l'opérateur <literal>new</literal>
|
|
ne retourne par de référence, mais retourne une copie.
|
|
<note>
|
|
<simpara>
|
|
Il n'y a aucune perte de performances (puisque PHP 4 utilise un compteur
|
|
de références) à retourner des copies au lieu de
|
|
références. Au contraire, il est souvent mieux de travailler
|
|
sur les copies plutôt que sur les références,
|
|
car créer une référence prend un peu plus de temps
|
|
que de créer une copie qui ne prend virtuellement pas de temps
|
|
(à moins de créer un tableau géant ou un objet monstrueux,
|
|
auquel cas il est préférable de passer par des
|
|
références).
|
|
</simpara>
|
|
</note>
|
|
Pour prouver ceci, regardez le code suivant :
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// maintenant, nous allons changer de nom. Qu'attendez-vous ?
|
|
// Vous pouvez vous attendre à ce que les deux variables $bar
|
|
// et $globalref[0] changent de nom...
|
|
$bar1->setName('modifié');
|
|
|
|
// comme prédit, ce n'est pas le cas
|
|
$bar1->echoName();
|
|
$globalref[0]->echoName();
|
|
|
|
/* affiche :
|
|
modifié
|
|
crée dans le constructeur
|
|
*/
|
|
|
|
// quelle est la différence entre $bar2 et $globalref[1]
|
|
$bar2->setName('modifié');
|
|
|
|
// Heureusement, elles sont non seulement égales, mais
|
|
// elles représentent la même variable.
|
|
// donc $bar2->Name et $globalref[1]->Name sont les mêmes
|
|
$bar2->echoName();
|
|
$globalref[1]->echoName();
|
|
|
|
/* affiche :
|
|
modifié
|
|
modifié */
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
Un dernier exemple pour bien comprendre.
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class A {
|
|
function A($i) {
|
|
$this->value = $i;
|
|
// Essayez de comprendre on n'a pas besoin de
|
|
// référence ici
|
|
$this->b = new B($this);
|
|
}
|
|
|
|
function createRef() {
|
|
$this->c = new B($this);
|
|
}
|
|
|
|
function echoValue() {
|
|
echo "<br />","class ",get_class($this),': ',$this->value;
|
|
}
|
|
}
|
|
|
|
|
|
class B {
|
|
function B(&$a) {
|
|
$this->a = &$a;
|
|
}
|
|
|
|
function echoValue() {
|
|
echo "<br />","class ",get_class($this),': ',$this->a->value;
|
|
}
|
|
}
|
|
// Essayez de comprendre pourquoi une copie simple va
|
|
// conduire à un résultat indésirable à
|
|
// la ligne marquée d'une étoile
|
|
$a =&new a(10);
|
|
$a->createRef();
|
|
|
|
$a->echoValue();
|
|
$a->b->echoValue();
|
|
$a->c->echoValue();
|
|
|
|
$a->value = 11;
|
|
|
|
$a->echoValue();
|
|
$a->b->echoValue(); // *
|
|
$a->c->echoValue();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
class A: 10
|
|
class B: 10
|
|
class B: 10
|
|
class A: 11
|
|
class B: 11
|
|
class B: 11
|
|
]]>
|
|
</screen>
|
|
</informalexample>
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.oop.object-comparison">
|
|
<title>Comparer des objets</title>
|
|
<para>
|
|
En PHP 4, les objets sont comparés de manière très simple,
|
|
à savoir : deux instances sont égales si elles ont les mêmes
|
|
attributs et valeurs, et qu'elles sont de la même classe. Des règles
|
|
similaires s'appliquent lors de la comparaison avec l'opérateur
|
|
<literal>===</literal>.
|
|
</para>
|
|
<para>
|
|
Si vous exécutez le code suivant :
|
|
<example>
|
|
<title>Exemple de comparaison d'objets en PHP 4</title>
|
|
<programlisting role='php'>
|
|
<![CDATA[
|
|
<?php
|
|
function bool2str($bool) {
|
|
if ($bool === false) {
|
|
return 'FALSE';
|
|
} else {
|
|
return 'TRUE';
|
|
}
|
|
}
|
|
|
|
function compareObjects(&$o1, &$o2) {
|
|
echo 'o1 == o2 : '.bool2str($o1 == $o2)."\n";
|
|
echo 'o1 != o2 : '.bool2str($o1 != $o2)."\n";
|
|
echo 'o1 === o2 : '.bool2str($o1 === $o2)."\n";
|
|
echo 'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
|
|
}
|
|
|
|
class Flag {
|
|
var $flag;
|
|
|
|
function Flag($flag=true) {
|
|
$this->flag = $flag;
|
|
}
|
|
}
|
|
|
|
class SwitchableFlag extends Flag {
|
|
|
|
function turnOn() {
|
|
$this->flag = true;
|
|
}
|
|
|
|
function turnOff() {
|
|
$this->flag = false;
|
|
}
|
|
}
|
|
|
|
$o = new Flag();
|
|
$p = new Flag(false);
|
|
$q = new Flag();
|
|
|
|
$r = new SwitchableFlag();
|
|
|
|
echo "Compare des instances créées avec les mêmes paramètres\n";
|
|
compareObjects($o, $q);
|
|
|
|
echo "\nCompare des instances créées avec différents paramètres\n";
|
|
compareObjects($o, $p);
|
|
|
|
echo "\nCompare une instance d'un parent avec celle d'une sous-classe\n";
|
|
compareObjects($o, $r);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Compare des instances créées avec les mêmes paramètres
|
|
o1 == o2 : TRUE
|
|
o1 != o2 : FALSE
|
|
o1 === o2 : TRUE
|
|
o1 !== o2 : FALSE
|
|
|
|
Compare des instances créées avec différents paramètres
|
|
o1 == o2 : FALSE
|
|
o1 != o2 : TRUE
|
|
o1 === o2 : FALSE
|
|
o1 !== o2 : TRUE
|
|
|
|
Compare une instance d'un parent avec celle d'une sous-classe
|
|
o1 == o2 : FALSE
|
|
o1 != o2 : TRUE
|
|
o1 === o2 : FALSE
|
|
o1 !== o2 : TRUE
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
Ce qui est le résultat que nous attendions, au vu des règles édictées.
|
|
Seules deux instances avec les mêmes valeurs d'attributs, et issues de la même
|
|
classe, sont considérées comme égales.
|
|
</para>
|
|
<para>
|
|
Même lorsque nous avons une composition d'objet, la même règle de comparaison
|
|
s'applique. Dans l'exemple ci-dessous, nous allons créer une classe
|
|
conteneur, qui stocke un tableau associatif <classname>Flag</classname>.
|
|
<example>
|
|
<title>Comparaison d'objets composés en PHP 4</title>
|
|
<programlisting role='php'>
|
|
<![CDATA[
|
|
<?php
|
|
class FlagSet {
|
|
var $set;
|
|
|
|
function FlagSet($flagArr = array()) {
|
|
$this->set = $flagArr;
|
|
}
|
|
|
|
function addFlag($name, $flag) {
|
|
$this->set[$name] = $flag;
|
|
}
|
|
|
|
function removeFlag($name) {
|
|
if (array_key_exists($name, $this->set)) {
|
|
unset($this->set[$name]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
$u = new FlagSet();
|
|
$u->addFlag('flag1', $o);
|
|
$u->addFlag('flag2', $p);
|
|
$v = new FlagSet(array('flag1'=>$q, 'flag2'=>$p));
|
|
$w = new FlagSet(array('flag1'=>$q));
|
|
|
|
echo "\nObjects composés u(o,p) et v(q,p)\n";
|
|
compareObjects($u, $v);
|
|
|
|
echo "\nu(o,p) et w(q)\n";
|
|
compareObjects($u, $w);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Objects composés u(o,p) et v(q,p)
|
|
o1 == o2 : TRUE
|
|
o1 != o2 : FALSE
|
|
o1 === o2 : TRUE
|
|
o1 !== o2 : FALSE
|
|
|
|
u(o,p) et w(q)
|
|
o1 == o2 : FALSE
|
|
o1 != o2 : TRUE
|
|
o1 === o2 : FALSE
|
|
o1 !== o2 : TRUE
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
</sect1>
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"../../manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|