如何在 PHP 中实现装饰器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/948443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement a decorator in PHP?
提问by omg
Suppose there is a class called "Class_A", it has a member function called "func".
假设有一个名为“ Class_A”的类,它有一个名为“ func”的成员函数。
I want the "func" to do some extra work by wrapping Class_Ain a decorator class.
我希望“ func”通过包装Class_A在装饰器类中来做一些额外的工作。
$worker = new Decorator(new Original());
Can someone give an example? I've never used OO with PHP.
有人可以举个例子吗?我从未在 PHP 中使用过 OO。
Is the following version right?
下面的版本对吗?
class Decorator
{
protected $jobs2do;
public function __construct($string) {
$this->jobs2do[] = $this->do;
}
public function do() {
// ...
}
}
The above code intends to put some extra work to a array.
上面的代码打算对数组进行一些额外的工作。
回答by catchdave
I would suggest that you also create a unified interface (or even an abstract base class) for the decorators and the objects you want decorated.
我建议您还为装饰器和您想要装饰的对象创建一个统一的接口(甚至是一个抽象基类)。
To continue the above example provided you could have something like:
要继续上面的例子,你可以有类似的东西:
interface IDecoratedText
{
public function __toString();
}
Then of course modify bothTextand LeetTextto implement the interface.
然后,当然,修改都Text并LeetText实现接口。
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 decorators as you like and be assured that each decorator (or object to be decorated) will have all the required functionality.
因为这样您就可以添加任意数量的装饰器,并确保每个装饰器(或要装饰的对象)都具有所有必需的功能。
回答by soulmerge
That is pretty easy, especially in a dynamically typed language like PHP:
这很容易,尤其是在像 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 have a look at the wikipedia article, too.
您可能还想查看维基百科文章。
回答by Darth Egregious
None of these answers implements Decoratorproperly and elegantly. mrmonkington's answer comes close, but you don't need to use reflection to enact the Decoratorpattern in PHP. In another thread, @Gordon shows how to use a decorator for logging SOAP activity. Here's how he does it:
这些答案都没有Decorator正确和优雅地实现。mrmonkington 的答案很接近,但您不需要使用反射来制定DecoratorPHP 中的模式。在另一个线程中,@Gordon 展示了如何使用装饰器记录 SOAP 活动。以下是他的做法:
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 a slight modification where you can pass 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);
}
}
回答by mrmonkington
I wanted to use decoration to encourage colleagues to use caching more, and inspired by the nice Python syntax experimented with PHP reflection to fake this language feature (and I have to stress 'fake'). It was a useful approach. Here's an example:
我想用装饰来鼓励同事更多地使用缓存,并受到很好的 Python 语法的启发,用 PHP 反射试验来伪造这个语言特性(我必须强调“假”)。这是一个有用的方法。下面是一个例子:
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 examples with caching examples here: https://github.com/mrmonkington/EggCup/
带有缓存示例的更好示例:https: //github.com/mrmonkington/EggCup/
回答by Bill
A key and unique feature of the Decorator is that one abstract class extends another. The Decorator participant is both a wrapper for and extends the Component participant.
装饰器的一个关键和独特的特性是一个抽象类扩展了另一个。装饰器参与者既是组件参与者的包装器,又是组件参与者的扩展。
<?php
abstract class Decorator extends IComponent
{
//public function getDescription() { }
}
?>
I believe that this is the only pattern where this happens in the Gang of Four catalog. The Decorator makes it easy to add properties to an object without changing the object. For a simple, accurate and clear example see:
我相信这是四人组目录中唯一发生这种情况的模式。装饰器可以轻松地向对象添加属性,而无需更改对象。有关简单、准确和清晰的示例,请参见:
http://www.php5dp.com/php-decorator-design-pattern-accessorizing-your-classes/#more-32
http://www.php5dp.com/php-decorator-design-pattern-accessorizing-your-classes/#more-32

