3

I'm not really sure if what I am looking for has a name, so it has been a bit difficult for me to search for, so I apologise if what I am asking has already been answered here before.

The situation is that I have an abstract class which has, of course, many other classes which extend it.

The abstract method in the abstract class is called run() and all of the extending classes define this method.

My problem is that I want to call some common code after the run() method has been called, but I want to know if there is a better way to do this.

I could of course just paste my common code into each and every extending class's run() method, but if I do that then it would be a lot of work for me to make simple changes from that point onward.

I could also put my common code into a method in the parent class and then call if from the extending class's run() method with $this.

But my question is, is there a better way to do this, or do I have to either use the $this keyword or paste in the code into each class's?

Here is a small example of what I want to do with my current idea:

abstract class Parent_Class {
    public abstract function run();

    protected function common_code() {
        // Common code here
    }
}

class Child_Class {
    public function run() {
        // Code here
        // I want some common code to run after the run method has been called

        $this->common_code(); // Is this the best way to do it?
    }
}

Or is it possible to somehow tell the class that when the run() method has been called to automatically run the common_code() method?

3 Answers 3

2

A far simpler way to do this would to simply have a third method which calls run() and then calls common_code(). Subclasses can then override run() all they want.

abstract class Parent_Class {
    public abstract function run();

    protected function common_code() {
        // Common code here
    }

    protected function start() {
        $this->run();
        $this->common_code();
    }

}

class Child_Class {
    public function run() {
        // Code here
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

That's a very good point - I can't believe I didn't think of it... I'll leave this question open a bit longer to see if anyone else has different suggestions but after reading your answer it seems so obvious now.
2

Based on Bradley Forster answer, you can define the method as protected, so when it's called from outside the class, you can intercept the event with php magic __call metod because

__call() is triggered when invoking inaccessible methods in an object context.

and then you can execute that method from the __call function

class A {

  public function __call($method, $args){

     if(!method_exists($this, $method))
       throw new Exception("Call to undefined method ".__CLASS__."::$method()");

     echo "doing something BEFORE function 'run' execution\n";

     $retval = call_user_func_array(array($this, $method), $args);

     echo "doing something AFTER function 'run' execution\n";

     return $retval;
  }

  protected function run() {
      echo "function 'run' executed\n" ;
  }
}

$a = new A;
$a->run();

Comments

1

The answer given by Amber is nice and simple. But requires you to put your data in run() but call start(). Here is an alternative that allows you to have your code $a->run() in all your scripts, and $a->run() with your common code, but encapsulated in a namespace.

File hooks.php

<?php
// File: hooks.php
namespace hook;

class processHooks {
    public function __construct() { /* Fatal Error without constructor */ }

    protected function processHooks($_c, $method, $args) {
        /* Swap the next two callbacks to run your custom code after */
        call_user_func_array("\hook\\{$_c}::{$method}", $args);
        return call_user_func_array(array($_c,$method), $args);
    }
}

class A {
    public function foo() {
        echo 'Doing code stuff BEFORE calling child function....<br>';
    }
}

File regular_file.php

<?php
// File: regular_file.php
include "hooks.php";

class A extends \hook\processHooks {

    /* All that is required is this function
     * and the function with common code to be protected
     */
    public function __call($method, $args) {
        self::processHooks(__CLASS__, $method, $args);
    }

    protected function foo() {
        echo 'Method is called....<br>';
    }
}

$a = new A();
$a->foo();

This works beacause method foo of class A in regular_file.php is protected, so it's not callable outside the class, so calling it triggers PHP magic method __call

__call() is triggered when invoking inaccessible methods in an object context.

1 Comment

This is a simplified version of a system I designed using all static functions.It can be easily changed back if that's how you want to use it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.