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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[POO] Implémenter Intercepting Filters


Sujet :

Langage PHP

  1. #1
    Membre habitué Avatar de alejandro
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2004
    Messages
    167
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2004
    Messages : 167
    Points : 188
    Points
    188
    Par défaut [POO] Implémenter Intercepting Filters
    Bonjour,

    Je possède une version électronique du PHP|Architect's Guide to PHP Design Patterns dont je me suis inspiré pour mettre au point un système de contrôleur frontal :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    if( ! class_exists( 'Front_Controller' ) )
    {
        final class Front_Controller
        {
            private static $o_Instance;
            private $o_FFI;
     
            private function __construct()
            {
                $this->o_FFI = new Front_FilterIterator;
                $this->o_FFI->RegisterFilter( new Front_FilterError )
                            ->RegisterFilter( new Front_FilterException )
                            ->RegisterFilter( new Front_FilterSession )
                            ->RegisterFilter( new Front_FilterOutput );
            }
     
            public static function GetInstance()
            {
                if( ! self::$o_Instance instanceof self )
                    self::$o_Instance = new self;
     
                return self::$o_Instance;
            }
     
            public function Execute()
            {
                foreach( $this->o_FFI->Increment() as $o_Filter )
                {
                    $o_Filter->PreProcess();
                }
     
                Front_Dispatcher::GetInstance()->Execute();
     
                foreach( $this->o_FFI->Decrement() as $o_Filter )
                {
                    $o_Filter->PostProcess();
                }
            }
        }
    }
    Mon contrôleur frontal met en place dans son constructeur une série de filtres que je parcours avec un objet itérator :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    if( ! class_exists( 'Front_FilterIterator' ) )
    {
        final class Front_FilterIterator
        implements Iterator
        {
            private $i_Position, $b_Increment, $a_Filters;
     
            public function __construct()
            {
                $this->a_Filters = array();
                $this->Increment();
                $this->Rewind();
            }
     
            public function & RegisterFilter( Front_FilterInterface $o_Filter )
            {
                $this->a_Filters[] = $o_Filter;
                return $this;
            }
     
            public function & RemoveFilter( Front_FilterInterface $o_Filter )
            {
                foreach( $this as $i_Key => $o_Value )
                {
                    if( get_class( $o_Filter ) == get_class( $o_Value ) )
                        unset( $this->a_Filters[$i_Key] );
                }
                return $this;
            }
     
            public function & Increment()
            {
                $this->b_Increment = true;
                return $this;
            }
     
            public function & Decrement()
            {
                $this->b_Increment = false;
                return $this;
            }
     
            public function rewind()
            {
                $this->i_Position = ( $this->b_Increment )? 0 : count( $this->a_Filters ) - 1;
            }
     
            public function next()
            {
                $this->i_Position += ( $this->b_Increment )? 1 : -1;
            }
     
            public function key()
            {
                return $this->i_Position;
            }
     
            public function current()
            {
                return $this->a_Filters[$this->i_Position];
            }
     
            public function valid()
            {
                return isset( $this->a_Filters[$this->i_Position] );
            }
        }
    }
    Tous les filtres possèdent une interface commune :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if( ! interface_exists( 'Front_FilterInterface' ) )
    {
        interface Front_FilterInterface
        {
            public function PreProcess();
            public function PostProcess();
        }
    }
    Dans mon fichier bootstrap (mon index.php) je démarre mon contrôleur frontal comme suit :

    [code]Front_Controller::GetInstance()->Execute();

    Dans mon contrôleur frontal, j'ai ma fonction "Execute()" qui commence par exécuter la fonction "PreProcess()" sur tous mes filtres. Ensuite elle démarre le traitement de la requête client. Finalement elle exécute la fonction "PostProcess()" sur chacun de mes filtres mais à l'envers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
            public function Execute()
            {
                foreach( $this->o_FFI->Increment() as $o_Filter )
                {
                    $o_Filter->PreProcess();
                }
     
                Front_Context::GetInstance()->Execute();
     
                foreach( $this->o_FFI->Decrement() as $o_Filter )
                {
                    $o_Filter->PostProcess();
                }
            }
    Ce qui a pour effet de me permettre la mise en place de tout un système de filtres me permettant d'effectuer différents contrôles comme par exemple un contrôle du buffer de sorties :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    if( ! class_exists( 'Front_FilterOutput' ) )
    {
        class Front_FilterOutput
        implements Front_FilterInterface
        {
            public function PreProcess()
            {
                ob_start();
            }
     
            public function PostProcess()
            {
                echo ob_get_clean();
            }
        }
    }
    Ce qui peut me permettre d'effectuer des tâches de maintenance comme par exemple la suppression des commentaires HTML (l'exemple est tiré du livre dont je vous ai parlé au début.

    Que pensez-vous de cette méthode d'implémentation du pattern "Intercepting Filters" ? J'ai vu un peu partout sur le net que normalement il s'agissait d'une chaine de process, mais l'auteur du livre utilise cette méthode pour l'implémenter, c'est une sorte de chaine mais à double sens ...

    Votre avis ?

  2. #2
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    La chaine de process a l'avantage de pouvoir être brisée (arrêter les traitements) puisque chaque filtre a la responsabilité d'appeler le filtre suivant (et donc de ne pas l'appeler si necessaire). Ce genre de comportement n'est pas vraiment réalisable dans ton implémentation.

    Un truc qui me déplait dans ton code, c'est le front controller qui s'octroie le droit d'instancier puis d'enregistrer plusieurs filtres alors que l'application n'en a peut être pas besoins du tout (genre pas besoins du filtre de session par exemple). Il me semblerait plus judicieux de laisser l'appli (et non le 'framework') déclarer ce qu'elle souhaite avoir comme filtre.

    Je me permets de critiquer, hein, on est la pour ça
    Pourquoi mets tu des tests 'if (!class_exists(...))' pour chaque classe ? C'est ridicule. ll faut t'arranger pour que tu sois sûr que la classe ne soit chargée qu'une fois et supprimer ces 'if' inutiles.

    En php 5, les objets sont passés par référence par défaut: nul besoins de mettre des '&' pour le retour de tes méthodes qui renvoient $this.

    Juste par curiosité, que fait ton Front_Dispatcher (ou Front_Context) ?

Discussions similaires

  1. Réponses: 13
    Dernier message: 20/10/2008, 16h36
  2. [POO] Implémenter partiellement une interface
    Par A&Z dans le forum Langage
    Réponses: 8
    Dernier message: 14/10/2008, 21h25
  3. [POO] Implémentation en PHP5
    Par cflo91 dans le forum Langage
    Réponses: 3
    Dernier message: 31/03/2008, 16h15
  4. [POO] Conseils pour implémentation d'un catalogue
    Par SPKlls dans le forum Langage
    Réponses: 2
    Dernier message: 24/01/2008, 00h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo