I have the following code; what should be added to the decorator class to pass the check of method_exists()? In real task I can't change the function that calls method_exists().
Also any idea how to cheat 'get_class_methods()' and '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();
Any ideas ? (I'm thinking of generating a wrapper class by eval())
This answer is extremely simple:
Make the decorator class extend the real class
<?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();
This is a much better design, and it works!
To better solve the underlying problem of inspecting a proprietary encoded program, I also suggest the use of XDebug's execution_trace.
First, __construct never return.
Second, to be a good/real decorator pattern, decorator class must decorate real object or another real extended object, so you should not instantiate the object within the construct method. A decorator pattern example will help you understand:
$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!
Third, you can create a method inside the real class who check if method exists:
public function method_exists($method){
return method_exists($this,$method);
}
and create it on decorator too (dont forget to check into the real object):
public function method_exists($method){
return method_exists($this,$method) || $this->real->method_exists($method);
}
Now think with me, if all your decorators extends from a unique Coffee decorator, you don't need to define this method into each decorator, so in my coffe example:
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With