omg*_*omg 31 php oop decorator
假设有一个名为" Class_A
" 的类,它有一个名为" func
" 的成员函数.
我希望" func
"通过包装Class_A
在装饰器类中来做一些额外的工作.
$worker = new Decorator(new Original());
Run Code Online (Sandbox Code Playgroud)
有人能举个例子吗?我从未在PHP上使用过OO.
以下版本是对的吗?
class Decorator
{
protected $jobs2do;
public function __construct($string) {
$this->jobs2do[] = $this->do;
}
public function do() {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码旨在为数组添加一些额外的工作.
cat*_*ave 43
我建议您还为装饰器和要装饰的对象创建统一的接口(甚至是抽象基类).
要继续上面的示例,您可以使用以下内容:
interface IDecoratedText
{
public function __toString();
}
Run Code Online (Sandbox Code Playgroud)
然后当然修改两者 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());
}
}
Run Code Online (Sandbox Code Playgroud)
为什么要使用界面?
因为那时你可以添加任意数量的装饰器,并确保每个装饰器(或要装饰的对象)都具有所有必需的功能.
sou*_*rge 34
这很容易,特别是在像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
Run Code Online (Sandbox Code Playgroud)
您也可以查看维基百科文章.
Dar*_*ous 23
这些答案都没有Decorator
恰当而优雅地实现.mrmonkington的答案很接近,但你不需要使用反射来Decorator
在PHP中实现模式.在另一个主题中,@ 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);
}
}
Run Code Online (Sandbox Code Playgroud)
他稍微修改了一下你可以将所需的功能传递给构造函数:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
我想使用装饰来鼓励同事更多地使用缓存,并且受到使用PHP反射实验的漂亮Python语法的启发,以伪造这种语言功能(我必须强调'假').这是一种有用的方法.这是一个例子:
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;
}
Run Code Online (Sandbox Code Playgroud)
这里有缓存示例的更好示例:https://github.com/mrmonkington/EggCup/