PHP bir dekoratör uygulamak nasıl?

4 Cevap php

"Class_A" adlı bir sınıf var varsayalım, o "func" adlı bir üye işlevi vardır.

Ben istiyorum "func" bir dekoratör sınıfta Class_A sararak bazı ekstra işler yapmak için.

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

Birisi bir örnek verebilir misiniz? PHP ile Ö.Ö. hiç kullanmadım.

================================================== =====

Teşekkür ederim çocuklar, benim için iyi bir demo sağladık!

Aşağıdaki sürüm doğru mudur?

class Decorator
{
    protected $jobs2do;

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

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

Yukarıdaki kod, bir dizi bazı ekstra işler koymak niyetinde.

4 Cevap

Bu özellikle PHP gibi dinamik yazdığınız dilde, oldukça kolaydır:

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

Sen de, wikipedia article bakmak isteyebilirsiniz.

Ben de dekoratörler ve dekore istediğiniz nesneler için birleşik bir arayüz (ya da soyut bir temel sınıf) oluşturmanızı öneririm.

Sağlanan Yukarıdaki örneğe devam etmek gibi bir şey olabilir:

interface IDecoratedText
{
    public function __toString();
}

Sonra tabii değiştirmek both Text ve LeetText arabirimini uygulamak için.

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());
    }

}

Why use an interface?

O zaman gibi birçok dekoratörler ekleyebilir ve her bir dekoratör (ya da dekore edilecek nesne) tüm gerekli özelliğe sahip olacak emin çünkü.

Bu cevaplar uygular Decorator düzgün ve zarif Yok. mrmonkington cevabı yakın geliyor, ancak PHP Decorator desen çıkarmak için yansıma kullanmak gerekmez. Başka bir iş parçacığı olarak, @Gordon shows how to use a decorator for logging SOAP activity. İşte o öyle nasıl:

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);
    }
}

Ve o kurucusuna istenen işlevselliği iletebilirsiniz hafif bir değişiklik var:

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);
    }   
}

Ben daha fazla önbelleğe kullanmaya arkadaşları teşvik ve sahte PHP yansıması bu dil özelliği ile tecrübe güzel Python sözdizimi esinlenerek için dekorasyon kullanmak istedim (ve ben 'sahte' stres var). Bu yararlı bir yaklaşım oldu. İşte bir örnek:

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;
}

Burada önbelleğe örneklerle daha iyi örnekler: https://github.com/mrmonkington/EggCup/