我有以下代码;什么应该添加到装饰器类来传递method_exists()
的检查?在实际任务中,我无法更改调用method_exists()
的功能
还有任何想法如何欺骗'get_class_methods()'和'get_class_vars()'?
class real {
function __construct($arg1,$arg2)
{
}
function test()
{
echo "test output\n";
}
}
class decorator
{
protected $real;
function __construct()
{
eval('$this->real=new real('.implode(',',func_get_args()).');');
}
function __call($method,$args)
{
echo "called $method\n";
$ret=call_user_func_array(array($this->real, $method), $args);
return $ret;
}
public function __isset($name)
{
echo "isset $name\n";
}
}
//-----Can't change below
$r=new decorator(1,2);
if (!method_exists($r,'test')) {die ("method 'test' does not exist, Fail :(\n");}
echo $r->test();
有什么想法吗? (我正在考虑通过eval()生成一个包装类
答案 0 :(得分:1)
首先,__ construct永远不会返回。
其次,要成为一个好的/真正的装饰器模式,decorator
类必须装饰real
对象或另一个real
扩展对象,所以你不应该在构造方法中实例化对象。装饰模式示例将帮助您理解:
$coffee = new Coffee();
$coffe_extra_sugar = new Sugar($coffee); // Here you put more sugar
$coffe_extra_extra_sugar = new Sugar($coffe_extra_sugar); // Here you put more sugar!
class NewCoffe extends Coffee{} // Now a new coffee
$ncoffe = new NewCoffe();
$ncoffe_extra_sugar = new Sugar($ncoffe); // Good Decorator!
第三,您可以在real
类中创建一个检查方法是否存在的方法:
public function method_exists($method){
return method_exists($this,$method);
}
并在装饰器上创建它(不要忘记检查真实对象):
public function method_exists($method){
return method_exists($this,$method) || $this->real->method_exists($method);
}
现在想想,如果你所有的装饰者都是从一个独特的咖啡装饰者延伸出来的,你就不需要在每个装饰器中定义这个方法,所以在我的coffe例子中:
class CoffeeDecorator {
protected $real;
public function __construct($decorated_class){
$this->real = $decorated_class;
}
public function method_exists($method){
return method_exists($this,$method) || $this->real->method_exists($method);
}
function __call($method,$args){
echo "called $method\n";
$ret=call_user_func_array(array($this->real, $method), $args);
return $ret;
}
}
// Now create some coffe decorators
class Sugar extends CoffeeDecorator{
// Methods for sugar decorator
}
答案 1 :(得分:1)
这个答案非常简单:
使装饰器类扩展真实类
<?php
class real {
function __construct() {
var_dump( func_get_args());
}
protected function test(){
echo "test output\n";
}
}
class decorator extends real{
function __construct(){
parent::__construct( func_get_args());
}
function __call($method,$args){
echo "called $method\n";
return call_user_func_array( array( 'parent', $method), $args);
}
public function __isset($name) {
echo "isset $name\n";
}
}
//-----Can't change below
$r = new decorator(1,2);
if(!method_exists($r,'test')) {die ("method 'test' does not exist, Fail :(\n");}
echo $r->test();
这是一个更好的设计,it works!
为了更好地解决检查专有编码程序的根本问题,我还建议使用XDebug's execution_trace。
答案 2 :(得分:0)
__construct()
的签名是void __construct ([ mixed $args [, $... ]] )
。
换句话说,__construct()
仅返回对象的实例。
我认为你在factory method pattern和装饰者模式之间感到困惑。
答案 3 :(得分:0)
使用apd编译PHP,
一旦你准备好了,
您可以轻松地将内置函数method_exist覆盖为is_callable
<击> 只需将method_exist更改为is_callable: -
$methodVariable = array($r, 'test');
var_dump(is_callable($methodVariable, true, $callable_name));
echo $callable_name, "\n";
输出: -
bool(true)
decorator::test
什么是is_callable?
验证变量的内容是否可以作为函数调用。这可以检查一个简单变量是否包含有效函数的名称,或者一个数组是否包含正确编码的对象和函数名称。
要添加,method_exist只是检查,
在你的情况下,方法是从不实际声明,
而is_callable检查方法可以调用,
使用__call,返回true。