la programmation objet (en PHP)
Accueil Remonter Informatique Science Societe Pay Bac 2008 tunisie

 

Tappez vos mots clés ici
Accueil
Remonter

La programmation objet (concepts fondamentaux)


En programmation, un modèle est une abstraction de la réalité.
Par conséquent, un modèle est une vue subjective de la réalité, mais toutefois, cette vue est toujours pertinente.

En effet, un modèle définit une frontière entre la réalité et la perspective de l'observateur. Il ne s'agit donc pas de la réalité, mais d'une vue très subjective de la réalité.
Par conséquent, un modèle doit permettre de faciliter la compréhension d'un système étudie, mais aussi, de simuler ce système.

Aujourd'hui, en programmation, il existe deux principaux modèle de représentation du monde : le modèle fonctionnel (que vous connaissez déjà) et le modèle objet (que nous allons donc étudier).
Jusqu'à aujourd'hui, vous connaissiez la programmation en PHP avec une approche fonctionnelle.

Afin de mieux comprendre les différences entre ces deux approches, nous allons donc détailler les deux approches, et voir ainsi leurs avantages et leurs inconvénients.

Avec une approche fonctionnelle, vos programmes étaient composés d'une série de fonctions, qui ensemble, assuraient certains services.
Il s'agit d'une approche logique, cohérente et intuitive de la programmation.

Cette approche a un avantage certain que l'on appelle la factorisation des comportements.
En effet, une découpe fonctionnelle intelligente consiste à factoriser certains comportements d'une application, ce qui veut dire que pour créer une fonction d'une application, rien ne vous empêche d'utiliser un autre ensemble de fonctions (qui sont donc déjà écrites).

Mais (il y a toujours un mais ^^), l'approche fonctionnelle a aussi ses défauts, comme par exemple une maintenance complexe en cas d'évolution de votre application.
La factorisation des comportements n'a pas que des avantages. En effet, si on y réfléchit deux minutes, maintenant, nos fonctions sont devenues interdépendantes.

Et ceci implique qu'une simple mise à jour de l'application à un point donné peut impacter en cascade sur d'autres fonctions de notre application.
Naturellement, nous pouvons toujours essayer d'écrire des fonctions les plus génériques possibles mais cela rend le développement de l'application beaucoup plus complexe.

De plus, en cas d'évolution de l'application, même si la structure générale de l'application reste valide, la multiplication des points de maintenance (dus au chaînage des fonctions à cause de la factorisation des comportements) rend l'adaptation extrêmement difficile.
Et dans ce cas, l'application sera alors retouchée dans sa globalité.

Prenons un exemple concret : on a en notre possession une application permettant de gérer une bibliothèque, et suite à la demande du client, notre application doit maintenant être capable de gérer une médiathèque, c'est-à-dire que l'on pourra emprunter, non seulement des livres, mais aussi, des CD-ROM, des DVD, etc...

Pour faire évoluer notre application, nous devrons faire évoluer les structures de données qui sont manipulées par les fonctions, puis nous devrons adapter les traitements, qui à l'origine, ne manipulaient qu'un seul type de document : les livres.

Nous devrons donc faire évoluer toutes les portions de code qui utilisent la base documentaire, et ce, afin de gérer les données et les actions propres aux différents type de documents.

Exemple : notre application, alors qu'elle ne gérait que des livres, pouvait mettre une sorte de carton jaune à un emprunteur lorsqu'il ne rendait pas son livre dans les temps.

Or, maintenant que notre bibliothèque est devenue une médiathèque, et si l'on désire que le délai avant le fameux carton jaune dépende du document emprunté (le carton jaune arrivera plus ou moins tard, suivant le document emprunté : un livre, un CD-ROM, un DVD, etc...), et bien il va falloir prévoir une règle de calcul pour chaque type de document.

Au final, c'est pratiquement la totalité de l'application qu'il va falloir adapter pour gérer les nouveaux types de documents et les traitements correspondants.

Les modifications que nous avons apportées à notre application de médiathèque, nous permettent de penser qu'une approche objet sera beaucoup plus avantageuse quant à la réutilisation du code déjà écrit.

Mais qu'est ce qu'un objet ?

Un objet est une entité comportant des frontières précises et qui possède une identité (un nom).

De plus, un ensemble d'attributs caractérisent l'état d'un objet, et l'on dispose d'un ensemble d'opérations (les méthodes) qui permettent d'agir sur le comportement de notre objet.

Un objet est l'instance d'une classe, et une classe, est un type de données abstrait, caractérisé par des propriétés (ses attributs et ses méthodes) communes à des objets et elle permet de créer des objets possédant ces propriétés.

Exemple : prenons le cas de notre bibliothèque.

Créons alors une classe Livre qui va nous permettre de créer des objets "Livre".

On aura alors :

POO

Et une instance de la classe Livre (un objet) :

POO

titre et auteur sont les attributs de notre classe, c'est-à-dire les caractéristiques communes à tous nos objets "Livre".
En clair, tous les livres auront un titre et un auteur.

De plus, notre classe dispose des méthodes emprunter() et rendre() qui s'appliquerons à nos objets "Livre" (on agira alors directement sur notre objet "Livre").

monLivre représente quant à lui, une instance de la classe Livre, il s'agit donc d'un objet qui porte le nom monLivre.

Les autres concepts importants de l'approche objet sont :
- l'encapsulation
- l'héritage (ainsi que le polymorphisme)
- l'agrégation

L'encapsulation consiste à masquer les détails d'implémentation d'un objet, et ce, en définissant une interface. En clair, vous n'avez pas besoin de savoir comment est conçu cet objet à la base pour pouvoir l'utiliser. Une interface est quant à elle, une vue externe d'un objet et elle définit les services accessibles pour modifier le comportement de l'objet.
L'encapsulation facilite l'évolution d'une application car elle stabilise l'évolution des objets.
En effet, nous pouvons très bien modifier l'implémentation des attributs d'un objet sans pour autant modifier son interface. Elle garantit de plus l'intégrité des données vu qu'elle permet d'interdire l'accès direct aux attributs des objets (on doit alors passer par des assesseurs).
Un assesseur étant une méthode d'accès pour connaître ou modifier la valeur d'un attribut d'un objet.

L'héritage est un mécanisme de transmission des propriétés d'une classe (ses attributs et ses méthodes) vers une sous-classe (la sous-classe héritant de la classe principale).
Grâce à l'héritage, une classe peut aussi être spécialisée en d'autres classes, afin d'y ajouter des caractéristiques spécifiques (ajout de méthodes par exemple) ou d'en adapter certaines.
Plusieurs classes peuvent aussi être généralisées en une classe qui les factorise, et ce, afin de regrouper les caractéristiques communes d'un ensemble de classes.
La spécialisation et la généralisation permettent de construire des hiérarchies de classes.
L'avantage principal de l'héritage est qu'il vous permet de d'éviter la duplication de code, et il encourage à la réutilisation de même code.

Exemple d'une hiérarchie de classes :

POO

D'après ce graphique, vous pouvez voir que la classe Livre hérite des propriétés de la classe Document.

Ce qui veut dire que les objets Livre auront un auteur, un éditeur, mais aussi un numéro et un titre.
De plus, comme on peut emprunter() ou rendre() un document, on pourra également emprunter() et rendre() un livre (ceci, parce que la classe Livre hérite de la classe Document).
On pourra également lire() ou photocopier() un livre.
En revanche, un document n'aura pas d'auteur ni d'éditeur, et on ne pourra pas le lire, ni même le photocopier (ces propriétés font partie de la classe Livre, or un document n'est pas un livre : c'est un livre qui est un document, et non l'inverse).

Quand au polymorphisme, celui-ci représente la faculté d'une méthode à pouvoir s'appliquer à des objets de classes différentes. Il augmente donc la généricité de votre code.

Exemple d'un polymorphisme :

POO

Vous pouvez voir ici que chacune des trois classes (Voiture, Train et Avion) héritent des méthodes de la classe Véhicule.
Ces trois classes, auront donc accès à la méthode deplacer() de la classe Véhicule.
Or, dans ces trois "sous classes", nous avons choisit de redéfinir la méthode deplacer() de la classe Véhicule.
Nous adaptons en fait cette méthode suivant l'objet que nous étudions (un avion se déplace dans les airs, un train sur des rails et une voiture sur la route).

L'agrégation constitue une relation entre deux classes, spécifiant que les objets d'une classe sont des composants de l'autre classe.
Une relation d'agrégation permet donc de définir des objets composés d'autres objets.
L'agrégation permet d'assembler des objets de base, afin de construire des objets plus complexes.

Exemple d'une agrégation :

POO

Vous voyez bien que notre objet eau de type molécule est en fait une combinaison de trois objets :
- hydrogene1 qui est un objet de la classe atome (c'est une instance de la classe atome).
- hydrogene2 qui est un objet de la classe atome (c'est une instance de la classe atome).
- oxygene qui est un objet de la classe atome (c'est une instance de la classe atome).

Notre molécule est donc compose de trois atomes : hydrogene1, hydrogene2 et oxygene.


En conclusion, vous devez savoir que le concept objet est un concept stable et éprouvé.
C'est un concept ancien (Simula, le premier langage de programmation à implémenter le concept de type abstrait à l'aide de classe date de 1967), mais il n'a jamais été autant d'actualité.

A cela, deux raisons principales :
- l'approche fonctionnelle n'est pas adaptée au développement d'applications qui évoluent sans cesse et dont la complexité croit continuellement (plusieurs dizaines de milliers de lignes de code).
- l'approche objet a été inventée pour faciliter l'évolution d'applications complexes.

De nos jours, les outils orientés objets sont fiables et performants (les compilateurs C++ par exemple produisent un code robuste et optimisé).

Mais, malgré les apparences, il est beaucoup plus naturel pour nous, êtres humains, de décomposer un problème informatique sous forme d'une hiérarchie de fonctions atomiques et de données, qu'en terme d'objets et d'interaction entre ces objets.
De plus, le vocabulaire précis est souvent un facteur d'échec important dans la mise en oeuvre d'une approche objet.

C'est pour cela qu'il faut penser objet des le départ, au lieu d'essayer de convertir une série de fonction en une classe.


La programmation objet (première approche)


Apres avoir vu les concepts fondamentaux de la programmation objet, attardons nous sur la programmation objet vu du côté de PHP.

Pour cela, je vous propose de réaliser notre premier classe : une classe qui vous servira à envoyer des mails.

Jusqu'à présent, pour envoyer des mails, vous deviez recopier toujours le même code avec des en-têtes à n'en plus finir.
Tout ceci sera fini avec votre classe d'envois de mails : vous écrirez une fois pour toute votre code, et ensuite, vous réutiliserez ce même code à chaque fois que vous aurez l'envie envoyer des mails.

Afin de commencer sur de bonnes bases, je vous conseille de stocker votre classe de mails dans un fichier PHP, comme par exemple sendmail.class.php, puis d'include ce fichier dans vos scripts lorsque vous en aurez besoin.

Attaquons tout de suite le code de notre classe !

Voici les premières lignes de code de notre classe :

<?php
class SendMail {
        var $destinataire;
        var $objet;
        var $texte;
}
?>



Comme vous le voyez, la déclaration d'une classe en PHP démarre par le mot clé class suivi du nom de la classe. Nous ouvrons alors une accolade ouvrante qui délimite le début de la déclaration des méthodes et des attributs de la classe (la déclaration de la classe se terminant avec une accolade fermante).

Ensuite, nous joignons 3 variables à notre classe : $destinataire, $objet et $texte.
Ces 3 variables sont en fait les caractéristiques communes des objets (les attributs) que nous allons pouvoir créer grâce à notre classe.
Noter que l'on déclare ces attributs avec le mot réservé var.

En clair, cela veut dire que tous les objets que nous allons créer avec cette classe (des mails en l'occurrence) auront toujours un destinataire, un objet et un texte.

Vous pouvez déclarer autant d'attributs de classe que vous le souhaitez.

Premier exemple d'utilisation :

<?php
// on inclut le code de notre classe
include ("./sendmail.class.php");

// on déclare notre objet (en fait, dans le langage objet, on dit que l'on crée une instance de la classe SendMail) 
$message = new SendMail ();

// on affecte des valeurs aux attributs de notre objet
$message->destinataire = "toto@toto.com";
$message->objet = "Scoop mondial !";
$message->texte = "Voici mon premier mail utilisant une classe mail :)";
?>



Noter l'utilisation de l'opérateur -> qui permet d'affecter des valeurs aux attributs de notre objet.
Nous verrons par la suite que cet opérateur nous permet également d'appliquer les méthodes de la classe sur notre objet.

Vous vous doutez bien qu'à ce niveau là, aucun mail n'a été envoyé :)
Cependant, vous pouvez vérifier que notre objet possède bien les attributs que nous lui avons fourni en faisant des :

<?php
echo $message->destinataire; // retournera : toto@toto.com
echo $message->objet; // retournera : Scoop mondial !
echo $message->texte; // retournera : mon premier mail utilisant une classe mail :)
?>



Pour envoyer notre mail, nous allons écrire une méthode pour notre classe qui utilisera la fonction mail de PHP ainsi que les attributs de notre objet.

On aura alors (pour notre classe) :

<?php
class SendMail {
        var $destinataire;
        var $objet;
        var $texte;

        function envoyer() {
                mail ($this->destinataire, $this->objet, $this->texte);
        }
}
?>



Détaillons la méthode envoyer().

Notre méthode utilise la fonction de mail de PHP, et elle prend en argument les valeurs des attributs de notre classe.
Cependant, remarquez l'utilisation de $this.
$this indique l'instance courante de notre classe.
Cet objet représente donc notre objet $message que nous utilisons dans notre script.

Vous pouvez écrire autant de méthodes que vous le souhaitez pour votre classe.

Cependant, sachez que vous ne pouvez écrire qu'une seule méthode ayant le même nom que le nom de votre classe (il s'agit en fait du constructeur de la classe qui a un rôle particulier au sein de la classe, nous le détaillerons plus tard).

Envoyons maintenant notre mail grâce à notre méthode envoyer() :

<?php
include ("./sendmail.class.php");

$message = new SendMail ();

$message->destinataire = "toto@toto.com";
$message->objet = "Scoop mondial !";
$message->texte = "Voici mon premier mail utilisant une classe mail :)";

// on applique la méthode envoyer() à notre objet $message grâce à l'opérateur ->
$message->envoyer();
?>



Plutôt pratique non ? :)
En effet, la programmation par objet a cet avantage indéniable, c'est que vous n'étés pas obliger de comprendre comment fonctionne une classe. Du moment que vous savez à quoi servent vos méthodes (leur rôle), vous pouvez les utiliser sans comprendre ce qu'il se passe derrière (le code de la classe en elle-même).

Mais vous pouvez aussi réutilisez vos classes dans d'autres scripts (ce qui reste l'avantage principal de cette forme de programmation).

Voyons maintenant le constructeur d'une classe.

En effet, toute classe contient une méthode dite "constructeur" et cette méthode a toujours le même nom que le nom de la classe en question.

Sans le savoir, lorsque vous avez écrit le code :

<?php
$message = new SendMail ();
?>



Et bien vous avez appelé le constructeur par défaut de la classe SendMail.

Cependant, comme vous l'avez remarqué, notre classe SendMail ne comporte pas de méthode SendMail() (le constructeur d'une classe est la méthode de cette classe qui porte le même nom que le nom de la classe), et bien dans ce cas, PHP utilise un constructeur par défaut qui n'affecte en rien sur les propriétés de notre objet.

Toutefois, vous pouvez vous-même écrire un constructeur dans votre classe.

Mais il faut savoir que le code que vous allez mettre dans votre constructeur va se répercuter sur tous les objets qui seront instances de votre classe.

Prenons un exemple simple :

Imaginer que vous ayez une classe Bonhomme.
Un des attributs de cette classe serait $nom, représentant le nom de notre bonhomme.
Si vous instancier votre classe simplement (en faisant donc un new Bonhomme() tout simple) alors que vous n'avez pas spécifié de constructeur, PHP va vous créer un Bonhomme sans nom (l'attribut $nom de notre objet sera vide).
Cependant, vous pouvez très bien écrire vous-même votre propre constructeur pour donner un nom à votre Bonhomme dès sa création.

Revenons alors à notre classe SendMail, et nous allons lui spécifier un constructeur qui va permettre de définir si le mail à envoyé sera au format texte ou html.

On aura alors :

<?php
class SendMail {
        var $destinataire;
        var $objet;
        var $texte;
        
        // on ajoute un attribut $entete à notre classe
        var $entete;
        
        // le constructeur de notre classe qui prend un paramètre
        function SendMail ($type = "texte") {
                if ($type == "texte") {
                        $this->entete = "Content-type: text/plain; charset=iso-8859-1n";
                }
                elseif ($type == "html") {
                        $this->entete = "Content-type: text/html; charset=iso-8859-1n";
                }
        }

        function envoyer() {
                mail ($this->destinataire, $this->objet, $this->texte, $this->entete);
        }
}
?>



Vous remarquerez alors que grâce à notre constructeur, nous allons pouvoir rapidement créer des mails au format texte ou bien au format html.

Exemple :

<?php
include ("./sendmail.class.php");

// $message sera un mail au format texte
$message = new SendMail ();

// $message2 sera un mail au format texte
$message2 = new SendMail ("texte");

// $message3 sera un mail au format html
$message3 = new SendMail ("html");
?>



En résumé, le constructeur de la classe sert souvent à initialiser certains attributs des objets crées à partir de la classe.

Attention, une classe ne peut contenir qu'un seul constructeur.

Ce cours vous a donc présenté quelques rudiments de la programmation par objet en PHP, cependant, vous avez du remarquez que contrairement au premier cours (les concepts fondamentaux), de nombreux concepts n'ont pas étés traités ici.

Ces concepts seront traités dans un futur cours afin de ne pas trop vous embrouillez les idées : trop de notions nouvelles d'un coup peut nuire à la compréhension de cette forme de programmation déjà bien complexe.


Les variables dynamiques


Cela ne vous est jamais arrivé de vous demander si il était possible de créer des variables dynamiques ?
C'est à dire des variables ayant un nom changeant au cours du script ?

Et bien c'est tout à fait possible de faire ceci en PHP.

En effet, grâce aux variables dynamiques vous allez pouvoir utiliser des noms de variables qui sont eux mêmes (les noms), variables, ce qui veut dire que vous allez utiliser des noms de variables qui sont affectés et utilisés dynamiquement dans votre script.

D'après ce que l'on vient dire, une variable dynamique serait alors une variable qui aurait comme nom la valeur d'une variable, par exemple $var.
En effet, si nous définissons la variable $hello, avec en valeur la chaîne de caractères Coucou, on aurait la chose suivante :

<?php
$var = 'hello';
$hello = 'Coucou';
echo ${$var};
?>



Qui affichera :

Coucou



C'est à dire la valeur de la variable $hello.

En utilisant le code :

<?php
$var ='hello';
$hello = 'Coucou';
echo $hello;
?>



Nous aurions eu exactement le même résultat.

Vous remarquez alors au passage le fonctionnement d'une variable dynamique :
- on initialise une variable ayant une certaine valeur
- on veut utiliser une autre variable ayant comme nom la valeur de notre variable précédente : pour cela, nous déclarons notre variable avec un $, puis avec l'intitulé de notre variable précédent entre deux crochets, ce qui donne : ${$var}

Malgré, cette brève description des variables dynamiques, j ai comme l'impression que vous n'êtes pas du tout convaincu.
Mais à quoi bon peuvent elles bien servir ces variables dynamiques ?

Tout simplement à faire du dynamique :)

Imaginons que l'on ai dans notre script PHP deux variables de type tableau (ou array) et que l'on désire accéder à l'un de ces tableaux.

Au lieu de faire des tests fous pour savoir à quel tableau on veut accéder, il nous suffit de créer une variable de type chaîne de caractères contenant le nom de notre tableau (celui que l'on désire parcourir) et d'utiliser une variable dynamique pour accéder à notre tableau.

Exemple :

<?php
$tableau1 = array ('test', 'toto', 'titi');
$tableau2 = array ('humpf', 'grmbl');

$var = 'tableau1';
$nb_elements = count (${$var});
for ($i=0; $i<$nb_elements; $i++) {
    // on accede aux éléments du tableau $tableau1
    echo ${$var}[$i].'<br />';
}
?>



Ce qui affichera donc :

test
toto
titi



L'exemple peut vous paraître un peu bête, mais regardez le de plus près : en effet, si nous décidons du jour au lendemain de changer le nom de notre tableau (afin de parser un autre tableau), nous n'aurons qu'une seule ligne à modifier :

<?php
$var = 'tableau1';
?>



(On aurait en fait écrit le nom d'un nouveau nom de tableau)

Alors qu'en n'utilisant pas les variables dynamiques, nous aurions du modifier cette même ligne, mais aussi la ligne concernant le comptage du nombre d'élément de notre tableau mais aussi la ligne contenue dans notre boucle for (le echo).

Les variables apportent alors leur lot d'avantages :
- la clarté du code
- du code dynamique réutilisable
- des solutions à des problèmes liés à la dynamique d'un script (comme par exemple généré un formulaire contenant un nombre indéfini de champs)

Avant de poursuivre ce cours, sachez également que le nombre de variables dynamiques utilisées est théoriquement sans limites.

Vous pouvez très bien faire, par exemple :

<?php
$var  = 'toto';
$toto = 'test';
$test = 'humpf';

echo ${${$var}};
?>



Ce qui affichera :

Humpf



Voyons maintenant un cas concret sur lequel il est intéressant d'utiliser les variables dynamiques.
Imaginez que vous ayez un formulaire, et dans la page de traitement de ce formulaire, plusieurs actions sont possibles.

Jusqu'à présent, pour faire votre page de traitement, vous deviez enchaîner une série de if elseif else (ou même mieux en utilisant un case) afin de savoir dans quel cas vous vous trouviez, et de plus, vous deviez écrire un bon paquet de ligne de code pour décrire chaque action.

Tout ceci peut-être largement simplifié grâce aux variables dynamiques.
En effet, imaginons que notre formulaire contienne un champ caché contenant une des valeurs suivantes (au choix) :
- insert
- delete
- update
- select

Voici alors le code d'une page de traitement possible de ce formulaire :

<?php
$champ_cache = $_POST['champ_cache'];

function insert() {
        // code
}

function delete() {
        // code
}
function update() {
        // code
}

function select() {
        // code
}

if ($champ_cache == 'insert' || $champ_cache == 'delete' || $champ_cache == 'update' || $champ_cache == 'select') {
        $champ_cache();
}
?>



Dans ce cas précis, on parlera de fonction dynamique.
Car comme vous pouvez le constater, on utilise la valeur d'une variable pour désigner le nom d'une fonction.

Voyons un autre cas d'utilisation, où là, nous allons pouvoir générer dynamiquement un formulaire.

Générer un formulaire dynamiquement veut dire que la personne utilisant le formulaire pourra choisir, elle-même, le nombre de champs de type text contenu dans ce formulaire, et grâce aux variables dynamiques, nous allons pouvoir récupérer la valeur de ces champs sans connaître auparavant le nombre de champs de ce formulaire (vu que ce nombre est décidé par la personne utilisant le formulaire)

Voici le code :

<?php
// si l'utilisateur soumet le formulaire on affiche la valeur de tous les champs du formulaire
if (isset($_POST['submit']) && $_POST['submit'] == "Envoyer"){
        // on affiche le nombre de champs du formulaire
        echo 'Nombre de champs : '.$_POST['nb_champs'].'<br />';

        // on affiche la valeur des champs du formulaire
        for ($i=1; $i<=$_POST['nb_champs']; $i++){
                $dynamique = 'champs_'.$i; 
                $value = $_POST[$dynamique];
                echo 'Valeur du champ '.$i.' : '.$value.'<br />';
        } 


// sinon on affiche le formulaire avec la possibilité d'ajout des champs au formulaire
else{ 
        // on défini le nombre initial de champs
        if (!isset($_POST['nb_champs'])){
                $_POST['nb_champs'] = 1;
        } 
        // si la personne clic sur "un champs en +", on ajoute un champs
        if (isset($_POST['submit']) && $_POST['submit'] == "Un champs en +"){
                $_POST['nb_champs']++;
        } 

        // on affiche le formulaire
        echo '<FORM METHOD="post">';
        // on place un champ caché contenant un entier ayant comme valeur le nombre de champs du formulaire
        echo '<INPUT TYPE="hidden" NAME="nb_champs" VALUE="'.$_POST['nb_champs'].'">';

        // on affiche tous les champs du formulaire
        for ($i=1; $i<=$_POST['nb_champs']; $i++){
                echo '<INPUT TYPE="text" name="champs_'.$i.'"><br />';
        }

        // on place un bouton permettant de rajouter un champs
        echo '<INPUT TYPE="submit" NAME="submit" VALUE="Un champs en +"><br />';
        // on place un bouton permettant de soumettre le formulaire
        echo '<INPUT TYPE="submit" NAME="submit" VALUE="Envoyer">';
        echo '</FORM>'; 

?>

 

Accueil | Contact | Annonce emploi | Annonce commerce | Annuaire gratuit

Hebergement de site web gratuit