[ACCEPTED]-How to implement a decorator in PHP?-decorator

Accepted answer
Score: 46

I would suggest that you also create a unified 9 interface (or even an abstract base class) for 8 the decorators and the objects you want 7 decorated.

To continue the above example 6 provided you could have something like:

interface IDecoratedText
{
    public function __toString();
}

Then 5 of course modify both Text and LeetText to implement the 4 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());
    }

}

Why use an interface?

Because then you can add as many 3 decorators as you like and be assured that 2 each decorator (or object to be decorated) will 1 have all the required functionality.

Score: 33

That is pretty easy, especially in a dynamically 2 typed language like 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

You may want to 1 have a look at the wikipedia article, too.

Score: 25

None of these answers implements Decorator properly 6 and elegantly. mrmonkington's answer comes 5 close, but you don't need to use reflection 4 to enact the Decorator pattern in PHP. In another 3 thread, @Gordon shows how to use a decorator for logging SOAP activity. Here's how he does it:

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

And he's 2 a slight modification where you can pass 1 the desired functionality to the constructor:

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);
    }   
}
Score: 6

I wanted to use decoration to encourage 6 colleagues to use caching more, and inspired 5 by the nice Python syntax experimented with 4 PHP reflection to fake this language feature 3 (and I have to stress 'fake'). It was a 2 useful approach. Here's an example:

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

Better 1 examples with caching examples here: https://github.com/gamernetwork/EggCup

More Related questions