[ACCEPTED]-How to implement a decorator in PHP?-decorator
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.
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.
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);
}
}
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
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.