Comment mettre en œuvre un décorateur en PHP?

supposons qu'il y ait une classe appelée " Class_A ", elle a une fonction membre appelée " func ".

je veux que le " func "fasse un peu de travail supplémentaire en emballant Class_A dans une classe de décorateur.

$worker = new Decorator(new Original());

quelqu'un Peut-il donner un exemple? Je n'ai jamais utilisé OO avec PHP.

est-ce que la version suivante est correcte?

class Decorator
{
    protected $jobs2do;

    public function __construct($string) {
        $this->jobs2do[] = $this->do;
    }

    public function do() {
        // ...
    }
}

Le code ci-dessus a l'intention de mettre un travail supplémentaire à un tableau.

29
demandé sur ROMANIA_engineer 2009-06-04 07:24:49

5 réponses

je suggérerais que vous créiez aussi une interface unifiée (ou même une classe de base abstraite) pour les décorateurs et les objets que vous voulez décorer.

pour continuer l'exemple ci-dessus à condition que vous puissiez avoir quelque chose comme:

interface IDecoratedText
{
    public function __toString();
}

puis bien sûr modifier à la fois Text et LeetText pour implémenter l'interface.

class Text implements IDecoratedText
{
...//same implementation as above
}

class LeetText implements IDecoratedText
{    
    protected $text;

    public function __construct(IDecoratedText $text) {
        $this->text = $text;
    }

    public function __toString() {
        return str_replace(array('e', 'i', 'l', 't', 'o'), array(3, 1, 1, 7, 0), $this->text->toString());
    }

}

Pourquoi utiliser une interface?

parce qu'alors vous pouvez ajouter autant de décorateurs que vous le souhaitez et être assuré que chaque décorateur (ou objet à décorer) aura toutes les fonctionnalités requises.

40
répondu catchdave 2009-06-04 04:51:54

c'est assez facile, surtout dans un langage dactylographié dynamiquement comme PHP:

class Text {

    protected $string;

    /**
     * @param string $string
     */
    public function __construct($string) {
        $this->string = $string;
    }

    public function __toString() {
        return $this->string;
    }
}

class LeetText {

    protected $text;

    /**
     * @param Text $text A Text object.
     */
    public function __construct($text) {
        $this->text = $text;
    }

    public function __toString() {
        return strtr($this->text->__toString(), 'eilto', '31170');
    }
}

$text = new LeetText(new Text('Hello world'));
echo $text; // H3110 w0r1d

vous pouvez jeter un oeil à l'article wikipedia , aussi.

34
répondu soulmerge 2012-11-20 12:44:55

aucune de ces réponses ne met en œuvre Decorator correctement et avec élégance. la réponse de mrmonkington est proche, mais vous n'avez pas besoin d'utiliser la réflexion pour décréter le modèle Decorator en PHP. Dans un autre fil, @Gordon montre comment utiliser un décorateur pour l'enregistrement de L'activité de savon . Voici comment il fait:

class SoapClientLogger
{
    protected $soapClient;

    // this is standard. Use your constuctor to set up a reference to the decorated object.
    public function __construct(SoapClient $client)
    {
        $this->soapClient = $client;
    }

    ... overridden and / or new methods here ...

    // route all other method calls directly to soapClient
    public function __call($method, $args)
    {
        // you could also add method_exists check here
        return call_user_func_array(array($this->soapClient, $method), $args);
    }
}

et il est une légère modification où vous pouvez passer la fonctionnalité désirée au constructeur:

class Decorator {

    private $o;

    public function __construct($object, $function_name, $function) {
        $this->o = $object;
        $this->$function_name = $function;
    }
    public function __call($method, $args)
    {
        if (!method_exists($this->o, $method)) {
            throw new Exception("Undefined method $method attempt in the Url class here.");
        }
        return call_user_func_array(array($this->o, $method), $args);
    }   
}
20
répondu Darth Egregious 2017-05-23 12:17:44

j'ai voulu utiliser la décoration pour encourager les collègues à utiliser la mise en cache plus, et inspiré par la jolie syntaxe Python expérimentée avec la réflexion PHP pour truquer cette fonctionnalité de langage (et je dois souligner 'fake'). C'est une approche utile. Voici un exemple:

class MrClass { 
  /**
   * decoratorname-paramname: 50
   * decoratorname-paramname2: 30
   */
   public function a_method( $args ) {
     // do some stuff
   }
}


class DecoratorClass {
  public function __construct( $obj ) {
     $this->obj = $obj;
     $this->refl = new ReflectionClass( $obj );
  }
  public function __call( $name, $args ) {
    $method = $this->refl->getMethod( $name );
    // get method's doccomment
    $com = trim( $method->getDocComment() );
    // extract decorator params from $com
    $ret = call_user_func_array( array( $this->obj, $name), $args );
    // perhaps modify $ret based on things found in $com
    return $ret;
}

meilleurs exemples avec des exemples de cache ici: https://github.com/mrmonkington/EggCup /

6
répondu mrmonkington 2011-08-17 18:07:14

une caractéristique clé et unique du décorateur est qu'une classe abstraite en étend une autre. Le participant Décorateur est à la fois un enveloppeur pour et étend le participant composant.

<?php
abstract class Decorator extends IComponent
{
    //public function getDescription() { }
}
?>

je crois que c'est le seul modèle où cela se produit dans le catalogue Gang of Four. Le décorateur rend facile d'ajouter des propriétés à un objet sans changer l'objet. Pour un exemple simple, précis et clair voir:

http://www.php5dp.com/php-decorator-design-pattern-accessorizing-your-classes/#more-32

-2
répondu Bill 2014-07-31 01:06:14