Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm finding it difficult to frame this question so ... I want to execute code both before and after a method runs in PHP. There are, as far as I know, two ways to implement this:

Method One: pre and post methods

class Model
{
  function find($id)
  {
    $this->_precode();
    // ... do stuff
    $this->post_code();
  }
}

Add the calls to _precode() and _postcode() to each method where I need this functionality.

Method Two: __call and method naming

class Model extends PrePost
{
  function prepost_find($id)
  {
    // ... do stuff ...
  }
}

class PrePost 
{
  function __call($method,$param) 
  {
    $method = "prepost_$method";
    // .. precode here ..
    $result = $this->$method($param);
    // .. postcode here ..
  }
}

This relies on naming a method in a specific way in the inheriting class. Is there a preferred way of doing this? The call method can be made to only handle its specific cases and even defer to a child class's call if there is one.

I'm not looking for opinions; I'm looking to find out if there are valid reasons to choose one way over another.

share|improve this question
add comment

1 Answer

up vote 6 down vote accepted

There are actually a lot more ways than you think.

Magic call method

This is code smell to me. It's not hard to follow, and, as shown, opens up some possible coding problems for external callers of the class. If I call $model->something(), and it doesn't exist, it'll try to run prepost__something() incorrectly. Magic is generally hard to follow and can give you some unexpected conditions.

Explicitly calling methods

Explicit is always better, but not when it interrupts the main flow of your method. Also - how often are you doing this? In 1 class? 10? 100? If it's something that's repeating a lot, then you should look at another method entirely.

The big question is what sort of functionality is hiding in those pre/post functions... is it related? Is it something like logging, debugging, etc. that isn't related at all, but needs to be executed there?

Event Driven

If they are unrelated, the best route is an event-based system. This is very common in most popular (well written, anyway) applications/frameworks.

class Model
{
  function find($id)
  {
    $this->dispatcher->dispatch("model.find.pre", $event = new PreFindEvent($id));

    // do whatever with $event->getId()

    $this->dispatcher->dispatch("model.find.post", new PostFindEvent($id, $result));
    return $result;
  }
}

This requires you to pass an event dispatcher component into your class (dependency injection), and manually wire all your triggered classes into the event dispatcher. However, you can trigger behaviour in very concise classes that modify the before/after functionality that you're going for. This can be very verbose, but it's testable, and allows you to write very modular code. Check out Symfony's EventDispatcher component for more examples, though many other vendors offer similar functionality.

If that's too verbose for you, and you want something a little more radical, there is also

Aspect Oriented Programming

If you want to implement cross-cutting functionality (ex, logging) across several methods, then this is a very handy option. However, the PHP support is not that great (experimental extension is required, or framework integration).

It allows you to dynamically trigger code at various points of your application WITHOUT having to explicitly add the hook points in your code. Something like this,

aop_add_before('some_function', 'run_this');

Arguably, this makes code execution very hard to follow, but it allows you to do some very cool things without all of the added complexity of event-based programming. If you use something like a dependency injection container, adding AOP may be possible to it as well, though very dependent on which tools you use.

Conclusion

Those are the options. I'd recommend event-based as that seems to be the community standard in PHP. (Symfony, Zend, etc.) AOP is better supported in other languages (natively), and it's a little hacky in PHP at the moment.

Either way, you're heading more and more into dependency injection, and that may be a whole new can of worms to open first.

Hope this helps. There is no right answer - it's always dependent on your current tools, and problem domain.

share|improve this answer
    
the magic call method really only has the "harder to follow" problem; you can determine if the method exists before trying to call it, and throw an exception if it doesn't exist. I like the syntax of the AOP extention, I may have to play with it a bit, and I appreciate your answer. –  Will Nov 13 '12 at 21:57
2  
Magic yields WTFs to anybody else reading your code who didn't catch it. Easy to deal with once you know/remember it's there, but having a clear API is always preferred - IMO anyway. Cheers –  Adrian Schneider Nov 13 '12 at 21:59
    
AOP was the first thing I thought of here too. Definitely what one would do to solve this type of problem in a language that supported it. –  glenatron Dec 28 '12 at 9:56
    
AOP to the rescue! Go! AOP. Pure PHP library for 5.4. –  Alexander Feb 13 '13 at 10:44
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.