Wagemage
Wagemage

Reputation: 300

Hooking method execution in PHP

Given a base class where I have some logic that must run before and after a certain method, that takes wildly different parameters in its differing derived classes. As an example:

abstract class Base{    
    public function pre(){ print "Runing Base::pre()\n"; }
    public function pos(){ print "Runing Base::post()\n"; }
    abstract public function doIt();
}

class Cheating extends Base
{
    public function doIt(){
        $this->pre();
        print "Doing it the cheating way\n";
        $this->pos();
    }
}

But what I'd actually like to do is along the lines of:

class Alpha extends Base
{
    public function doIt($x, $y){
        print "Doing it in Alpha with x=$x, y=$y";
    }
}

class Beta extends Base
{
    public function doIt($z){
        print "Doing it in Alpha with z=$z";
    }
}

And have some way to always run the pre and pos methods, without having to change the doIt method itself.

The obvious way, should doIt be homogenous across all derivations of Base would be something like:

abstract class Base
{
    public function pre(){ print "Runing Base::pre()\n"; }
    public function pos(){ print "Runing Base::post()\n"; }

    public function process($a,$b){
        $this->pre();
        $this->doIt($a,$b);
        $this->pos();
    }

    abstract public function doIt();
}

class Wishful extends Base
{
    public function doIt($a, $b){
        print "Doing it the Wishful way with a=$a, b=$b\n";
    }
}

The problem there is that since we have different number and type of parameters on each implementation of doIt, it does not actually solve the problem.

This sounds like a case for "hooks" - how does one go about implementing those ? Or any other decent way of solving the problem... I believe there should be a simpler way that I'm just missing - probably thinking in circles one the wrong things.

Thanks!

Upvotes: 4

Views: 2727

Answers (3)

Flavius
Flavius

Reputation: 13816

You should look at aspect-oriented programming. The lithium framework's filter system uses such thing. Zend Framework 2 also plans to use AOP.

If you want to intercept a function call at the engine level, you could use intercept from the PECL.

Google also reveals a nice framework you could LEARN a lot from. Look at its code.

Also, here is a relevant SO question: https://stackoverflow.com/questions/4738282/are-there-any-working-aspect-oriented-php-libraries

Upvotes: 2

Karoly Horvath
Karoly Horvath

Reputation: 96258

Calling with variable arguments can be done with: http://php.net/manual/en/function.call-user-func-array.php. Pass $this as object.

Fetching the arguments is a bit trickier, but can be done with __call: http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods

Upvotes: 0

zzzzBov
zzzzBov

Reputation: 179046

It sounds like you want something like:

function process()
{
  $this->pre();
  $result = call_user_func_array( array( $this, 'doIt' ), func_get_args() );
  $this->post();
  return $result;
}

Upvotes: 0

Related Questions