简体   繁体   中英

Call child method from parent class

I have a Class that is used as an extender by several other Classes, and in one instance, a method from the parent Class needs to call back to a method from the child Class. Is there a way of doing this?

I realise PHP contains abstract Classes and functions, but would require each child Class to have the declared abstract function(s), which I do not require in this case.

For example ( these are examples, not real life ) -

Class parent{

    function on_save_changes(){

        some_parent_function();

        if($_POST['condition'] === 'A') :
            // Call 'child_1_action()'
        elseif($_POST['condition'] === 'B') :
            // Call 'child_2_action()'
        endif       

        some_other_parent_function();

    }

    function some_parent_function(){
        // Do something here, required by multiple child Classes
    }

}

Class child_1 Extends parent{

    function __construct(){
        $this->on_save_changes();
    }

    function child_1_action(){
        // Do something here, only every required by this child Class
    }

}

Class child_2 Extends parent{

    function __construct(){
        $this->on_save_changes();
    }

    function child_2_action(){
        // Do something here, only every required by this child Class
    }

}

You can do this by just simply calling the child method, eg:

if($_POST['condition'] === 'A') :
    $this->some_parent_function();
    $this->child_1_action();

However, you should avoid doing this. Putting checks in the parent that call methods only existing in a child class is a very bad design smell. There is always a way to do things in a more structured manner by utilizing well-known design patterns or simply thinking the class hierarchy through better.

A very simple solution you can consider is implementing all of these methods in the parent class as no-ops; each child class can override (and provide implementation for) the method that it's interested in. This is a somewhat mechanical solution so there's no way to know if it's indeed the best approach in your case, but even so it's much better than cold-calling methods that technically are not guaranteed to exist.

Try this:

class ParentClass{

    private $childActionMethod;

    public function on_save_changes(){
        if(method_exists($this, $this->childActionMethod)) {
            call_user_func_array(array($this, $this->childActionMethod), func_get_args());
        }
        else {
            throw new Exception('Child Method has not been set');
        }
    }

    protected function setChildActionMethod($methodName) {
        $this->childActionMethod = $methodName;
    }
}

class ChildClass1 extends ParentClass{

    function __construct(){
        $this->setChildActionMethod('child_1_action');
    }

    function child_1_action(){
        echo('Hello First World<br />');
    }
}

class ChildClass2 extends ParentClass{

    function __construct(){
        $this->setChildActionMethod('child_2_action');
    }

    function child_2_action(){
        echo('Hello Second World<br />');
    }
}

$child1 = new ChildClass1();
$child1->on_save_changes();
// Hello First World

$child2 = new ChildClass2();
$child2->on_save_changes();
// Hello Second World

The parent class has the protected method setChildActionMethod , callable by the children. When the children are instantiated, they tell the parent the name of the method they would like it to call on save.

If the method exists then it is called with any arguments, or it throws an exception (you can change the error handling).

I'm sure theres a name for this pattern, but I am unsure what it is called.

You may use "Template method" pattern, if you need to create some action sequence in parent that child classes should implement on their own but in some predefined manner. But you should avoid referring to future defined arbitrary methods.

In general: any method you use in your parent should be declared either as abstract or have default implementation. Children will override these methods.

abstract class parent{
  function on_save_changes(){
    some_parent_function();
    some_child_action();
    some_other_parent_function(); // added to follow changes of question
  }

  function some_parent_function(){
    // Do something here, required by multiple child Classes
  }

  abstract public function some_child_action();

}

class child_1 Extends parent{
  function some_child__action(){
    if($_POST['condition'] === 'A') : 
      // Do something here, only every required by this child Class
    endif;
   }
}

class child_2 Extends parent{
  function some_child_action(){
    if($_POST['condition'] === 'B') :
      // Do something here, only every required by this child Class
    endif; 
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM