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

  1. #1
    Rédacteur

    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    602
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 602
    Points : 2 790
    Points
    2 790
    Par défaut POO PHP5 : Design Pattern observateur aidé de la Standard PHP Library (SPL)
    Le design pattern observateur est un classique du GOF, il participe au découplage et à la réduction des dépendances.
    En général, 2 interfaces sont utilisées, on peut aussi manipuler des classes abstraites. Nous allons ici montrer un exemple complet de son utilisation et nous allons nous aider de la puissante librairie objet interne de PHP5 : la SPL.
    POO PHP5 : Design Pattern observateur aidé de la Standard PHP Library (SPL)


  2. #2
    Membre à l'essai
    Inscrit en
    septembre 2005
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : septembre 2005
    Messages : 8
    Points : 11
    Points
    11
    Par défaut Petite coquille
    Très bon article, avec un exemple concret

    Je pense qu'il y a une coquille dans la fabrique par réflexion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     
    public function factory($listener, array $args = array())
        {
            $reflect = new ReflectionClass($class); //devrait être $listener
            return $reflect->newInstanceArgs($args);
        }
    La variable $class n'est pas définie, ca devrait être $listener, nan ?

  3. #3
    Membre du Club
    Profil pro
    None
    Inscrit en
    mars 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : None

    Informations forums :
    Inscription : mars 2008
    Messages : 57
    Points : 69
    Points
    69
    Par défaut Avis
    Bonjour.
    Dans un premier temps, grand merci à Julien Pauli pour ses nombreux tutoriaux.
    Ceci étant dit, une relecture avant publication ne serait pas inutile. Ce n'est pas la première fois que les codes sont inutilisables et qu'il est fait référence en 3 mots à une notion qui nécessiterait bien 10 phrases (si on lit un tuto sur un design pattern, les chances sont grandes qu'on ne maitrise pas les autres sur le bout des doigts)
    Quelques erreurs:
    Chaque fois qu'apparait la méthode notifyObservers, ce devrait être notify.
    Dans le même registre, pour une raison incompréhensible, les instances de ErrorHandler utilisent la méthode add() (non définie) quand elles devraient utiliser attach().
    Enfin, pour être franc, à partir du II-D, je ne comprends plus rien (oui, je sais, je ne suis pas doué, mais c'est aussi pour ça que je lis des tutos, pour progresser)

  4. #4
    Membre confirmé Avatar de Grabeuh
    Homme Profil pro
    Développeur Web
    Inscrit en
    février 2009
    Messages
    114
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2009
    Messages : 114
    Points : 639
    Points
    639
    Par défaut tant qu'on y est...
    Excellent tutoriel, je lis toujours avec un grand plaisir les publications de Julien Pauli, car c'est une véritable mine d'or pour le développeur avide de code clair, propre et maintenable.

    petite suggestion
    Plutôt que de faire une méthode getError() qui retourne une chaine, ne peut-on pas pousser encore plus loin l'utilisation de l'API standard PHP au moyen de la méthode magique __toString() qui remplirait exactement le même rôle ?

  5. #5
    Membre habitué
    Avatar de savageman86
    Profil pro
    Inscrit en
    octobre 2006
    Messages
    105
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : octobre 2006
    Messages : 105
    Points : 197
    Points
    197
    Par défaut
    Bon, je vais surtout parler de gestionnaire d'erreur car j'ai bien un pattern Observer, mais sans la SPL. Voici un gestionnaire d'erreur sympa à utiliser également, le plus sympa étant de pouvoir filtrer les types d'erreurs directement dans le gestionnaire !

    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
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    <?php
     
    class MultipleErrorHandler {
     
    	// List every observer for each $errno
    	protected static $observers   = array();
    	// Reference each callback function
    	protected static $callbacks   = array();
    	// List all the catchable errors
    	protected static $catchable_errors = array();
     
    	// Attach an callback function as error handler
    	// The index return is needed to Detach the callback handler
    	public static function Attach($callback, $errno = E_ALL) {
    		static $count = 1;
    		self::$callbacks[$count] = $callback;
    		foreach(self::get_catchable_errors() as $catchable) {
    			if (($errno & $catchable) == $catchable) {
    				array_unshift(self::$observers[$catchable], $count);
    			}
    		}
    		return $count++;
    	}
     
    	// Detach a callback function from error handling
    	// Needs the index returned by Attach()
    	public static function Detach($index, $errno = E_ALL) {
    		foreach(self::get_catchable_errors() as $catchable) {
    			if (($errno & $catchable) == $catchable) {
    				$key = array_search($index, self::$observers[$catchable]);
    				if (false !== $key) {
    					unset(self::$observers[$catchable][$key]);
    				}
    			}
    		}
    	}
     
    	// Runs the MultipleErrorHandler
    	public static function Run($old_error_level = E_ALL) {
    		$old_error_handler = set_error_handler(array(__CLASS__, 'Notify'));
    		// If an old handler was attached, keep it in the error handling process
    		if ($old_error_handler !== null && $old_error_level) {
    			self::Attach($old_error_handler, $old_error_level);
    		}
    		return $old_error_handler;
    	}
     
    	// Custom error handler used by the class
    	public static function Notify($errno, $errstr, $errfile, $errline, $errcontext) {
    		$stop_propagation = false;
    		foreach(self::get_catchable_errors() as $catchable) {
    			if (($errno & $catchable) == $errno) {
    				foreach(self::$observers[$errno] as $callback) {
    					$stop_propagation = (true === call_user_func(self::$callbacks[$callback], $errno, $errstr, $errfile, $errline, $errcontext)) || $stop_propagation;
    				}
    			}
    		}
    		return $stop_propagation;
    	}
     
    	// Returns all catchable errors as an array
    	public static function get_catchable_errors() {
    		if (empty(self::$catchable_errors)) {
    			self::$catchable_errors = array(E_WARNING,E_PARSE,E_NOTICE,E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE);
    			foreach(array('E_STRICT','E_RECOVERABLE_ERROR','E_DEPRECATED','E_USER_DEPRECATED') as $constant) {
    				defined($constant) && self::$catchable_errors[] = constant($constant);
    			}
    			foreach(self::$catchable_errors as $type) {
    				self::$observers[$type] = array();
    			}
    		}
    		return self::$catchable_errors;
    	}
    }
     
    function test_handler($errno, $errstr, $errfile, $errline, $errcontext) {
    	echo 'test ok';
    	return false;
    }
     
    function test_handler_2($errno, $errstr, $errfile, $errline, $errcontext) {
    	echo 'test autre';
    	return false;
    }
     
    MultipleErrorHandler::Run(); // Don't reattach the old error handler
    $index = MultipleErrorHandler::Attach('test_handler', E_WARNING);
    $index = MultipleErrorHandler::Attach('test_handler_2', E_WARNING);
    2/0;

  6. #6
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 32
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : février 2010
    Messages : 3 929
    Points : 7 994
    Points
    7 994
    Par défaut
    Bonjour et merci pour cet article.

    J'aurais juste une remarque d'ordre esthétique à apporter à la discussion : tant qu'a avoir un factory qui utilise les classes de reflexion, on pourrait en profiter pour protéger le programmeur de plus haut niveau de ses erreurs en restreignant les classes utilisables aux seuls SplObservers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public static function factory ($class, $args)
    {
        if (!is_array($args)) $args = array($args); // permet l'usage class::factory('FileHandler', 'fichier.txt');
        $reflect = new ReflectionClass($class);
        if ($reflect->implementsInterface('SplObserver'))
            return $reflect->newInstanceArgs($args);
        else
            // Erreur|Exception|null
    }
    De cette manière le code est bien plus sécurisé : le factory n'est capable de créer que ce qui peut être attaché à l'objet en question.

Discussions similaires

  1. Implementation du design pattern Observateur
    Par 0coco0 dans le forum Langage
    Réponses: 1
    Dernier message: 02/12/2009, 10h23
  2. Réponses: 1
    Dernier message: 04/07/2008, 15h53
  3. [POO] pattern observateur
    Par poukill dans le forum C++
    Réponses: 3
    Dernier message: 16/12/2007, 23h51
  4. UML -> code PHP5 : design pattern ???
    Par D_Kupp dans le forum UML
    Réponses: 2
    Dernier message: 11/10/2007, 13h42

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