IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours de PHP 5

Image non disponible


précédentsommairesuivant

IV. Programmation Orientée Objet (POO)

IV-A. Modèle objet

IV-A-1. Bref historique

La programmation orientée objet (POO) a fait son apparition dans la version 3 de PHP. C’était alors simplement un moyen d’autoriser la syntaxe OO (par opposition au procédural), mais pas réellement un moyen de programmer efficacement avec des objets.

PHP4 a continué dans la lancée, proposant de nouveaux mots clefs, mais toujours sans proposer une syntaxe proche de langages ayant une plus grande maturité comme C++ ou Java. C’est ce qui a facilité le passage des applications et des hébergements de PHP3 à PHP4, et c’est ce qui retarde la mise en place massive de PHP5 à travers le Web.

PHP5, en revanche, introduit de véritables concepts OO : le constructeur est plus clairement identifié, le destructeur fait son apparition, les objets sont tous pris en charge comme des références, de nouveaux mots clefs font leur apparition (public, protected et private) ainsi que des interfaces et des classes abstraites…

IV-A-2. Terminologie

Une classe est une représentation abstraite d’un objet. C’est la somme des propriétés de l’objet et des traitements dont il est capable. Une Chaise, un Livre, un Humain, une Rivière sont autant d’exemples possibles de classes. Une classe peut généralement être rendue concrète au moyen d’une instance de classe, que l’on appelle objet : on parle d’instancier la classe. Un objet est donc un exemple concret de la définition abstraite qu’est la classe.

On parle d’héritage lorsque l’on définit une hiérarchie de classes. On peut par exemple définir la classe Chien, mais elle nous semble trop abstraite : si j’instancie Chien par un objet $médor, je ne sais pas de quelle race est mon chien. Je pourrais avoir une propriété « race » dans la classe Chien, mais la solution de l’héritage me donne plus de souplesse : elle me permet de redéfinir des propriétés et des méthodes de la classe Chien, tout en héritant de celles que je ne modifie pas.

IV-A-3. Les mots réservés

Ces mots permettent de déclarer des classes en PHP :

  • class : Déclaration de classe ;
  • const : Déclaration de constante de classe ;
  • function : Déclaration d’une méthode ;
  • public/protected/private : Accès (par défaut « public » si aucun accès n’est explicitement défini) ;
  • new : Création d’objet ;
  • self : Résolution de portée (la classe elle-même) ;
  • parent : Résolution de portée (la classe « parent ») ;
  • static : Résolution de portée (appel statique) disponible depuis PHP 5.3 et 6.0 ;
  • extends : Héritage de classe ;
  • implements : Implémentation d’une interface (dont il faut redéclarer toutes les méthodes).

Les mots clefs « self » et « parent » sont utiles pour accéder à une propriété ou méthode (statique ou non) de la classe elle-même ou de son parent.

Le mot clef « static » a la même utilité, mais il résout la portée au moment de l’exécution du script (cf. plus loin).

Les méthodes magiques sont des méthodes qui, si elles sont déclarées dans une classe, ont une fonction déjà prévue par le langage.

Méthodes magiques

  • __construct() : Constructeur de la classe ;
  • __destruct() : Destructeur de la classe ;
  • __set() : Déclenchée lors de l’accès en écriture à une propriété de l’objet ;
  • __get() : Déclenchée lors de l’accès en lecture à une propriété de l’objet ;
  • __call() : Déclenchée lors de l’appel d’une méthode inexistante de la classe (appel non statique) ;
  • __callstatic() : Déclenchée lors de l’appel d’une méthode inexistante de la classe (appel statique) : disponible depuis PHP 5.3 et 6.0 ;
  • __isset() : Déclenchée si on applique isset() à une propriété de l’objet ;
  • __unset() : Déclenchée si on applique unset() à une propriété de l’objet ;
  • __sleep() : Exécutée si la fonction serialize() est appliquée à l’objet ;
  • __wakeup() : Exécutée si la fonction unserialize() est appliquée à l’objet ;
  • __toString() : Appelée lorsque l’on essaie d’afficher directement l’objet : echo $object; ;
  • __set_state() : Méthode statique lancée lorsque l’on applique la fonction var_export() à l’objet ;
  • __clone() : Appelés lorsque l’on essaie de cloner l’objet ;
  • __autoload() : Cette fonction n’est pas une méthode, elle est déclarée dans le scope global et permet d’automatiser les « include/require » de classes PHP.

Enfin, la variable $this utilisée à l’intérieur d’une classe, vaut toujours une référence vers l’objet lui-même. Pour plus d’informations sur les références, cf. plus loin à la section « Références et clonage ».

IV-A-4. Syntaxe

Je ne prétends pas refaire un cours complet sur la POO, car il y a d’excellents cours sur le Net et dans de nombreux livres. Je vais toutefois survoler le sujet afin de rappeler les aspects en rapport avec PHP.

La POO représente la programmation par objets. Un objet est la concrétisation d’une classe, une classe étant un ensemble générique (par opposition à concret) de propriétés et de fonctionnalités. On parle d’instancier une classe pour en faire un objet.

Une classe s’écrit au moyen du mot « class » suivi du nom de la classe et d’accolades (pas de point virgule). Les conventions d’écriture de code recommandent d’écrire ce mot comme un nom propre, à savoir avec une seule majuscule. Certaines recommandations (PEAR, Zend Framework etc.) préconisent d’utiliser l’underscore pour identifier l’héritage :

 
Sélectionnez
<?php
class Animal{}
class Animal_Chien extends Animal{}
class Animal_Chien_Caniche extends Animal_Chien{}
class Animal_Chien_Labrador extends Animal_Chien{}

La création d’une instance de classe se fait au moyen du mot clef « new ». L’accès aux propriétés et méthodes de l’objet se fait par la flèche « -> », et l’accès statique par l’opérateur de résolution de portée « :: ». Le point n’est pas utilisé dans la POO de PHP.

IV-A-5. Droits d’accès

Les classes ont des propriétés et méthodes privées, c’est-à-dire internes et qui ne concernent pas l’extérieur. Ces propriétés sont déclarées en tant que « private ».

La propriété n’est pas accessible hors de la classe :
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
<?php
class Caniche
{
    private $nbPattes;

    public function __construct()
    {
        $this->nbPattes = 4;
    }
}

$froufrou = new Caniche();
echo $froufrou->nbPattes; //illégal depuis l’extérieur de la classe
 
Sélectionnez
Fatal error: Cannot access private property Caniche::$nbPattes
    in C:\Web\online\http\tests\error.php on line 8
Il faut déclarer une méthode accesseur :
Sélectionnez
<?php
class Caniche
{
    private $nbPattes;

    public function __construct()
    {
        $this->nbPattes = 4;
    }

    public function nbPattes() //voici ce que l’on appelle un "getter"
    {
        return $this->nbPattes; //OK depuis l’intérieur de la classe
    }
}

$froufrou = new Caniche();
echo $froufrou->nbPattes(); //affiche "4"

Les propriétés ou méthodes « protected » concernent les objets de la même classe ainsi que ses dérivées, mais pas ceux des classes étrangères.

 
Sélectionnez
<?php
class Chien
{
    protected $presenceQueue;

    public function __construct()
    {
        $this->presenceQueue = TRUE;
    }
}

class Chien_Labrador extends Chien
{
    public function aUneQueue()
    {
        if($this->presenceQueue) //OK depuis une classe fille
        {
            return 'oui';
        }
        else
        {
            return 'non';
        }
    }
}

$médor = new Chien_Labrador();
echo $médor->aUneQueue(); //affiche "oui"

Les propriétés ou méthodes « public » sont visibles et manipulables par tous les objets, même s’ils sont d’autres classes.

 
Sélectionnez
<?php
class Caniche
{
    public $âge = 2;

    public function __construct()
    {
        $this->âge = 2;
    }
}

$froufrou = new Caniche();
echo $froufrou->âge; //affiche "2"

IV-A-6. Résolution de portée

Les mots clefs « parent » et « self » combinés à l’opérateur « :: » résolvent respectivement la classe dont ils héritent et leur propre classe :

 
Sélectionnez
<?php
class Chien
{
    protected function aboyer()
    {
        return 'Je suis un chien';
    }
}

class Chien_Labrador extends Chien
{
    protected function aboyer()
    {
        return 'Je suis un labrador';
    }

    public function identifierParent()
    {
        return parent::aboyer();
    }

    public function identifierSelf()
    {
        return self::aboyer();
    }
}

$médor = new Chien_Labrador();
echo $médor->identifierParent().'<br/>';
echo $médor->identifierSelf().'<br/>';
 
Sélectionnez
Je suis un chien
Je suis un labrador

Les variables et méthodes « static » sont communes à l’ensemble des objets d’une même classe au moyen de l’opérateur « :: ». On parle alors de propriétés ou de méthodes « de classe » puisqu’elles n’appartiennent pas à un objet en particulier.

 
Sélectionnez
<?php
class Caniche
{
    public static $caniches = 0;
    public function __construct()
    {
        ++self::$caniches;
    }
}

$froufrou = new Caniche();
$froufrette = new Caniche();

echo Caniche::$caniches; //affiche "2"

L’accès « public/protected/private » s’applique de la même manière que pour les accès non statiques :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<?php
class Caniche
{
    protected static $caniches = 0;
    public function __construct()
    {
        ++self::$caniches;
    }
}

$froufrou = new Caniche();
$froufrette = new Caniche();

echo Caniche::$caniches;
 
Sélectionnez
Fatal error: Cannot access protected property Caniche::$caniches
    in C:\Web\online\http\tests\error.php on line 14

IV-A-7. Interfaces

Une interface est un ensemble de méthodes que les classes doivent définir si elles veulent l’implémenter.

Ne pas implémenter toutes les méthodes de l’interface cause une erreur fatale :
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<?php
interface Joueur
{
    // une classe qui veut implémenter l’interface Joueur
    // doit définir la méthode jouer()
    public function jouer();
}

class Labrador implements Joueur{} //illégal, car pas de définition de jouer()

$médor = new Labrador();
$médor->jouer();
 
Sélectionnez
Fatal error: Class Labrador contains 1 abstract method
    and must therefore be declared abstract or implement the remaining methods
    (Joueur::jouer) in C:\Web\online\http\tests\error.php on line 7
Il faut donc surcharger les méthodes décrites dans l’interface :
Sélectionnez
<?php
interface Joueur
{
    // une classe qui veut implémenter l’interface Joueur
    // doit définir la méthode jouer()
    public function jouer();
}

class Labrador implements Joueur
{
    public function jouer()
    {
        echo 'Ouah!';
    }
}

$médor = new Labrador();
$médor->jouer();

De nombreuses interfaces intéressantes sont définies dans la Standard PHP Library (SPL).

Obtenir la liste des interfaces déclarées :
Sélectionnez
<pre>
<?php
print_r(get_declared_interfaces());

IV-A-8. Références et clonage

Depuis PHP 5, les objets sont tous des références. Ainsi, copier un objet vers un autre au moyen de l’opérateur « = » ne duplique pas l’objet, au contraire il crée une deuxième référence vers le même objet.

Lorsque l’on crée un objet avec l’opérateur new, PHP créé l’objet en mémoire et référence son emplacement en mémoire dans la variable :

 
Sélectionnez
$object = new stdClass();

La variable $object contient maintenant une référence vers un objet de la classe stdClass, mais elle ne contient pas l’objet lui-même. Pour détruire cet objet en mémoire, il faut détruire toutes les références vers cette instance de la classe.

 
Sélectionnez
$object = new stdClass();
unset($object);
//toutes les références sont détruites, l’objet n’existe donc plus en mémoire
 
Sélectionnez
$object_1 = new stdClass();
$object_2 = $object_1;
unset($object_1); //il reste une référence, l’objet persiste donc en mémoire
unset($object_2); //l’objet n’est plus référencé par aucune variable, il est donc détruit

Pour nous en convaincre, essayons le script suivant :

 
Sélectionnez
<?php
class Test
{
    public function __destruct()
    {
        echo 'Objet détruit<br/>';
    }
}

$obj_1 = new Test();
$obj_2 = $obj_1;
$obj_3 = $obj_2;

echo 'Marqueur n° 1<br/>';
unset($obj_1);

echo 'Marqueur n° 2<br/>';
unset($obj_2);

echo 'Marqueur n° 3<br/>';
 
Sélectionnez
Marqueur n° 1
Marqueur n° 2
Marqueur n° 3
Objet détruit

La phrase « Objet détruit » apparaît uniquement lorsque la fin du script cause la destruction de la 3° et dernière référence (appel automatique du destructeur).

Voyons maintenant avec des clones de l’objet initial :

 
Sélectionnez
<?php
class Test
{
    public function __destruct()
    {
        echo 'Objet détruit<br/>';
    }
}

$obj_1 = new Test();
$obj_2 = clone $obj_1;
$obj_3 = clone $obj_2;

echo 'Marqueur n° 1<br/>';
unset($obj_1);

echo 'Marqueur n° 2<br/>';
unset($obj_2);

echo 'Marqueur n° 3<br/>';
 
Sélectionnez
Marqueur n° 1
Objet détruit
Marqueur n° 2
Objet détruit
Marqueur n° 3
Objet détruit

Ici, il y a bien une seule référence de chaque objet.

IV-A-9. Late Static Bindings (LSB)

Une innovation de PHP 5.3 et 6.0 est ce que l’on appelle les « Late Static Bindings ».

Les LSB sont une nouvelle faculté de PHP : résoudre les appels statiques plus tard dans la chronologie des évènements. C’est une question de fonctionnement interne de PHP. Le plus important pour nous est de savoir que les deux exemples suivants agissent différemment :

Mot clef "self" :
Sélectionnez
<?php
class Chien
{
    protected function aboyer()
    {
        return 'Je suis un chien';
    }

    public function identifier()
    {
        return self::aboyer(); //appel à la classe elle-même
    }
}

class Chien_Labrador extends Chien
{
    protected function aboyer()
    {
        return 'Je suis un labrador';
    }
}

$médor = new Chien();
$félix = new Chien_Labrador();

echo $médor->identifier().'<br/>';
echo $félix->identifier().'<br/>';
 
Sélectionnez
Je suis un chien
Je suis un chien

Ici, la méthode Chien::identifier() est bien transmise par héritage à la classe Chien_Labrador, mais elle n’est pourtant pas appelée. Cela a été perçu comme un problème par de nombreuses personnes, et a donné lieu aux Late Static Bindings. De nombreux articles ont été écrits sur le sujet, si vous souhaitez en savoir davantage.

Les Late Static Bindings permettent d’utiliser un nouveau mot clef « static:: » pour résoudre correctement la portée statique :

Mot clef "static" :
Sélectionnez
<?php
class Chien
{
    protected function aboyer()
    {
        return 'Je suis un chien';
    }

    public function identifier()
    {
        return static::aboyer(); //appel statique
    }
}

class Chien_Labrador extends Chien
{
    protected function aboyer()
    {
        return 'Je suis un labrador';
    }
}

$médor = new Chien();
$félix = new Chien_Labrador();

echo $médor->identifier().'<br/>';
echo $félix->identifier().'<br/>';
 
Sélectionnez
Je suis un chien
Je suis un labrador

Dans cet exemple, « static:: » permet de négocier l’appel de la méthode aboyer() au moment de l’exécution, et ainsi d’utiliser la méthode Chien_Labrador::aboyer()… Au moment de la compilation du script, on ne sait pas encore quelle classe fournira la méthode : c’est à l’exécution que tout devient clair.

Une application particulièrement intéressante des LSB est dans le cadre de projets ORM (bases de données) :

 
Sélectionnez
<?php
class Table
{
    static function getByPk($id)
    {
        return 'SELECT * FROM '.get_called_class().' WHERE id = '.(int)$id;
    }
}

class Album extends Table{}
class Artist extends Table{}

echo Album::getByPk(3);
echo Artist::getByPk(6);
 
Sélectionnez
SELECT * FROM Album WHERE id = 3
SELECT * FROM Artist WHERE id = 6

La fonction get_called_class() s’apparente à la constante magique __CLASS__, à la différence qu’elle retourne la classe appelée par le développeur plutôt que la classe actuelle dans le code.

Les late static bindings ne sont disponibles qu’à partir de PHP 5.3, qui est actuellement en cours de développement. Par conséquent, rien de ce qui a ici trait aux LSB n’est final (jusqu’à la sortie effective de PHP 5.3). Des mots clefs peuvent notamment apparaître, disparaître ou être renommés.

IV-A-10. Exceptions

Il existe déjà de nombreux articles sur ce sujet, je ne vais donc pas m’étendre. Exemple : Exceptions et PHP5Tutoriel POO en PHP, par Guillaume Affringue

Les exceptions sont un moyen de gérer les situations marginales, mais dont nous savons qu’elles peuvent survenir. Un exemple est l’indisponibilité du serveur pendant la connexion à une base de données : ce n’est pas une situation normale, néanmoins elle est facilement prévisible et identifiable. Un modèle Orienté Objet permet de repérer ces situations et de les gérer de manière personnalisée.

Lancement et identification d’une exception :
Sélectionnez
try 
{
    throw new Exception('incident');
}
catch(Exception $e)
{
    echo $e->getMessage(); //affiche "incident"
}

Lorsqu’une exception est lancée depuis un bloc « try », le bloc « catch » permet de l’attraper et de traiter l’incident. Dans l’exemple ci-dessus, nous avons lancé nous-mêmes volontairement une exception.

PHP permet d’utiliser plusieurs blocs « catch » à la suite, mais ne dispose pas (encore ?) d’instruction « finally » comme dans d’autres langages.

IV-A-11. Fonctions et constantes utiles

Fonctions :

  • class_parents() : Retourne un tableau de la classe parent et de tous ses parents ;
  • class_implements() : Retourne un tableau de toutes les interfaces implémentées par la classe et par tous ses parents ;
  • get_class() : Retourne la classe de l’objet passé en paramètre ;
  • get_called_class() : À utiliser dans une classe, retourne la classe appelée explicitement dans le code PHP et non au sein de la classe ;
  • class_exists() : Vérifie qu’une classe a été définie ;
  • get_declared_classes() : Liste des classes définies ;
  • get_class_methods() : Liste des méthodes d’une classe ;
  • get_class_vars() : Liste des propriétés d’une classe.

Constantes magiques :

  • __CLASS__ : Donne le nom de la classe en cours ;
  • __METHOD__ : Donne le nom de la méthode en cours.

get_class($this) et __CLASS__ ont le même effet.

IV-B. Espaces de noms

IV-B-1. Introduction

Les espaces de noms, aka namespaces, sont un moyen de résoudre les collisions de noms de constantes, fonctions et classes.

Par exemple si j’ai besoin d’une classe pour filtrer mes variables, je peux avoir envie de créer une classe nommée « Filter ». Or, ce nom est sans doute déjà utilisé par PHP ou par l’une des bibliothèques incluses dans mes scripts. La solution classique est de préfixer le nom de la classe de manière à le rendre unique : « DVP_Filter ».

Ou dans un contexte MVC, j’ai souvent des modèles et des contrôleurs pour le même concept. Selon le framework utilisé, la nomenclature change, mais le nom de classe est généralement préfixé lui aussi.

PHP 5.3 introduit le concept des namespaces dans PHP. Cela nous permet de définir des noms de classes, fonctions, etc. au sein d’un espace de noms, par exemple le namespace « DVP » peut contenir la classe « Filter » alors que l’espace de noms global contient également une classe « Filter ». Nous pouvons ainsi avoir autant de classes « Filter » que nous pouvons imaginer de noms de namespaces.

Les espaces de noms ne sont disponibles qu’à partir de PHP 5.3, qui est actuellement en cours de développement. Par conséquent, rien de ce qui a ici trait aux espaces de noms n’est final (jusqu’à la sortie effective de PHP 5.3). Des mots clefs peuvent notamment apparaître, disparaître ou être renommés.

IV-B-2. Syntaxe

Déclaration :
Sélectionnez
<?php
namespace <Nom>;
...
Utilisation :
Sélectionnez
<?php
use <Nom> as <Alias>;
$object = new Models::Member(); //avec le nom complet
$object = new M::Member(); //avec l’alias

Les espaces de noms composés peuvent être importés tels quels ou avec un alias :

 
Sélectionnez
<?php
namespace Cours::Models;
...
 
Sélectionnez
<?php
use Cours::Models;
use Cours::Models as M;
...

En revanche, les noms qui ne sont pas composés doivent être importés avec un alias :

 
Sélectionnez
<?php
namespace Models;
...
 
Sélectionnez
<?php
use Models as M;
...

Erreur si on ne définit pas d’alias :

 
Sélectionnez
<?php
use Models;
...
 
Sélectionnez
Warning: The use statement with non-compound name 'Models' has
    no effect in C:\Web\online\http\cours-php\namespaces\index.php on line 6

Bien entendu, il est possible d’imbriquer les espaces de noms :

 
Sélectionnez
<?php
namespace Offline::Sites::Application::Models;
 
Sélectionnez
<?php
use Offline::Sites::Application::Models as M;
$object = new M::Member();

Si vous êtes dans un espace de noms (c’est-à-dire dans un script contenant par exemple « namespace Cours; »), vous pouvez vous abstenir d’utiliser le préfixe « Cours:: » devant les symboles de cet espace de noms. En effet, PHP suppose que vous utilisez des symboles du même espace de noms, ou bien un symbole du langage. Si vous voulez utiliser un symbole du scope global (mais pas interne à PHP), préfixez le nom du symbole par « :: ». Si vous utilisez un symbole d’un autre espace de noms, il faut bien entendu préfixer votre symbole de l’espace de noms complet.

Si vous êtes hors d’un espace de noms, il faut systématiquement préfixer soit de l’alias, soit du nom complet.

N’avez-vous jamais rêvé d’utiliser un nom de fonction déjà réservé par le langage ? Les espaces de noms vous permettent d’utiliser les noms déjà réservés pour des constantes, fonctions ou classes internes de PHP.

Il était initialement prévu d’utiliser le mot clef « import » comme en Java, mais cela a finalement été changé pour le mot clef « use ». Voir les archives de php.internals[PHP-DEV] import/use last call pour plus d’informations.

IV-B-3. Exemple d’utilisation

Reprenons un contexte MVC assez simple pour illustrer une utilité possible des namespaces.

Ajouter à "httpd.conf" :
Sélectionnez
<Directory "C:/Web/online/http/cours-php/namespaces">
    AllowOverride None
    php_value include_path ".;C:/Web/offline/sites/cours-php/namespaces"
    SetEnv HTTP_ROOT /cours-php/namespaces/
    RewriteEngine on
    RewriteCond %{REQUEST_URI} !\.(js|css|jpg|png|gif)$
    RewriteRule .* index.php
</Directory>
controllers/member.php
Sélectionnez
<?php
namespace Cours::Controllers;
class Member
{
    public static function whoAmI()
    {
        return 'Je suis un Contrôleur';
    }
}
models/member.php
Sélectionnez
<?php
namespace Cours::Models;
class Member
{
    public static function whoAmI()
    {
        return 'Je suis un Modèle';
    }
}
views/member.php
Sélectionnez
<?php
namespace Cours::Views;
class Member
{
    public static function whoAmI()
    {
        return 'Je suis une Vue';
    }
}
index1.php
Sélectionnez
<?php
require 'models/member.php';
require 'views/member.php';
require 'controllers/member.php';

header('Content-Type: text/html; charset=utf-8');
echo Cours::Models::Member::whoAmI().'<br/>';
echo Cours::Views::Member::whoAmI().'<br/>';
echo Cours::Controllers::Member::whoAmI();
index2.php
Sélectionnez
<?php
require 'models/member.php';
require 'views/member.php';
require 'controllers/member.php';

use Cours::Models;
use Cours::Views;
use Cours::Controllers;

header('Content-Type: text/html; charset=utf-8');
echo Models::Member::whoAmI().'<br/>';
echo Views::Member::whoAmI().'<br/>';
echo Controllers::Member::whoAmI();
index3.php
Sélectionnez
<?php
require 'models/member.php';
require 'views/member.php';
require 'controllers/member.php';

use Cours::Models as M;
use Cours::Views as V;
use Cours::Controllers as C;

header('Content-Type: text/html; charset=utf-8');
echo M::Member::whoAmI().'<br/>';
echo V::Member::whoAmI().'<br/>';
echo C::Member::whoAmI();
 
Sélectionnez
Je suis un Modèle
Je suis une Vue
Je suis un Contrôleur

précédentsommairesuivant

Copyright © 2008 Guillaume Rossolini. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.