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, e.g.:
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;
}
}
Related
I'm wondering if this is possible in PHP:
trait SomeTrait
{
public function someMethod() { /* ... */ }
}
class Parent
{
use SomeTrait;
}
class Child extends Parent
{
/* Do something to rename someMethod() to someOtherMethod() */
use someMethod as someOtherMethod; // Example
public function someMethod()
{
// Do something different than SomeTrait::someMethod()
}
}
In my actual use-case, the Parent class is a parent to several children (and none of them actually use the someMethod() that comes from the trait applied to the parent class. The Parent class is also part of an external library, so I cannot directly modify the source code.
The Child class in my actual use-case also relies on protected properties from the Parent class, so I'm fairly certain that I need to keep the inheritance.
Is this actually possible, or do I just need to deal with it, and use a different method name on the Child class in question?
What you've got in the question should work fine if you just want to override it. As per the manual:
The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.
If you need to provide an alias in the child class, then you can re-use the trait in the child class, making use of the as operator to define an alias in the current class:
class Child extends Foo
{
// This will re-import the trait into your child class, aliasing
// any specified methods.
use SomeTrait {
someMethod as someOtherMethod;
}
public function someMethod() {
$this->someOtherMethod();
}
}
You can also control the visibility of the new alias, e.g.
use SomeTrait {
someMethod as private someOtherMethod;
}
All that said, I don't really see the benefit of this, when you could just call
parent::someMethod();
after over-riding it. But it might be useful if you've got a particularly complex inheritance tree.
Full example here: https://eval.in/868453
I literally tested this yesterday with the following code :-)
<?php
trait CanWhatever
{
public function doStuff()
{
return 'result!';
}
}
class X
{
use CanWhatever;
public function doStuff()
{
return 'overridden!';
}
}
$x = new X();
echo $x->doStuff();
echo "\n\$x has ";
echo (class_uses($x, 'CanWhatever')) ? 'the trait' : 'no trait';
The output was:
overridden!
$x has the trait
So keeping the name the same just overrides as per normal.
Check it out here https://3v4l.org/Vin2H
I have a code like following ---
class CartItem{
var $v;
function __construct(){
$this->f();
}
function f(){
echo 'In parent';
}
}
class m extends CartItem{
function f(){
echo 'In child';
}
}
new m();
Now when creating instance of m()... it doesn't have any constructor, so it is calling parent classes constructor. Now inside that a function f is called.
What I want is -
if class m() have defined function f()... is should call it instead of parent class's function f().
But anyway it is calling parent classes function, as it was called from parent's constructor, irrespective of child class/ context :(
You want to call in __construct() a method that is not defined in the class. This is a sign that the CartItem class is an abstract concept and you don't intend to instantiate it (because an instance of CartItem probably doesn't contain enough information or behaviour for your project).
An abstract concept is implemented using an abstract class that defines as much as it can and defines abstract methods to be implemented in the concrete classes that extend it. The method f() is such a method that cannot be defined in the abstract concept and has to be defined in each class that extend it:
abstract class CartItem
{
public function __construct()
{
$this->f();
}
abstract protected function f();
}
class m extends CartItem
{
protected function f()
{
// Implement behaviour specific to this class
}
}
This is actually a really interesting question.
so, as I understand it, you're asking (if this isnt right please say):
can you call a function of a class that's extending a parent?
yes, you can... sort of, if the method in the child is static.
Take this example (Ive not used it in the constructor for simplicity of example, but it will work there too):
class ClassA {
public function testMeAsWell() {
return ClassB::testMe();
}
}
class ClassB extends ClassA {
static function testMe() {
return 'do something';
}
}
$child = new ClassB();
echo $child->testMe();
// outputs 'do something'
$parent = new ClassA();
echo $parent->testMeAsWell();
// also outputs 'do something'
the reason this works needs more research, but as a guess I would say that because PHP is compiled, it will know about both classes at run-time and therefore will be able to figure out what we wanted it to do.
So, further on, you want to use variables. Yes you can, but they would have to be static as well.
working example
What is the best of calling a method in child class. My IDE always shows Errors if i try to call the method directly.
class Base
{
public function DoIt()
{
$this->Generate(); //How to check if child implements Generate?
}
}
class Child extends Base
{
protected function Generate()
{
echo "Hi";
}
}
Simply put, you don't do this. It is very bad design: base classes should never assume anything about their descendants other than that they implement the contracts the base itself defines.
The closest acceptable alternative would be to declare abstract protected function Generate() on the parent so that it knows that all derived classes implement it. Of course this is not meant to be a mechanical solution: you should only do it if Generate is meaningful for all descendants of Base.
The issue is that your parent class doesn't define a Generate() method that a child class can override; you have to explicitly define this by creating an abstract method:
// class with at least one abstract method is
abstract class Base
{
public function DoIt()
{
$this->Generate();
}
// child classes MUST implement this method
abstract protected function Generate();
}
You can loosen the requirements by creating an empty implementation in the parent class:
class Base
{
public function DoIt()
{
$this->Generate();
}
// child classes MAY implement this method
protected function Generate() {}
}
Let say I have a PHP Class:
class MyClass {
public function doSomething() {
// do somthing
}
}
and then I extend that class and override the doSomething method
class MyOtherClass extends MyClass {
public function doSomething() {
// do somthing
}
}
Q: Is it bad practice to change, add and or remove method params? e.g:
class MyOtherClass extends MyClass {
public function doSomething($newParam) {
// do somthing
// do something extra with $newParam
}
}
Thanks
In general, yes it is bad design. It breaks the design's adherence to the OOP principle of polymorphism (or at least weakens it)... which means that consumers of the parent interface will not be able to treat instances of your child class exactly as they would be able to treat instances of the parent.
Best thing to do is make a new semantically named method (semantic in this case meaning that it conveys a similar meaning to the original, with some hint as to what the param is for) which either calls the original, or else in your overridden implementation of the original method, call your new one with a sensible default.
class MyOtherClass extends MyClass {
public function doSomething() {
return $this->doSomethingWithOptions(self::$soSomethingDefaultOptions);
}
public function doSomethingWithOptions($optsParam) {
parent::doSomething();
// ...
}
}
The following example does not work because when parent is called in class A, php looks for the parent class of class A but it doesn't exist. I would rather this line to call Test() in class B.
Is this possible?
(I know this seems like a stupid example but it has a practical application)
abstract class A {
function CallParentTest()
{
return call_parent_method('Test');
}
}
abstract class B extends A {
function Test()
{
return 'test passed';
}
}
class C extends B {
function Test()
{
return $this->CallParentTest();
}
}
$object = new C();
echo $object->Test();
Thanks!
EDIT
I changed the parent keyword to the made up method call_parent_method because I think that may have been confusing people. I know there is no way to do this using the keyword.
Just as David Harkness pointed out, I am trying to implement the Template Method pattern but instead of using two different method names, I'm using one. B::Test() will be the default method unless substituted with alternate functionality.
You can use reflection to bypass the natural calling order for overridden methods. In any context simply create a ReflectionMethod for the method you'd like to call and invoke it. You don't need to do this from the class itself, but you will need to call setAccessible(true) if the method isn't public.
class A {
public function bypassOverride() {
echo "Hi from A\n";
$r = new ReflectionMethod('B', 'override');
$r->invoke($this);
}
}
class B extends A {
public function override() {
echo "Hi from B\n";
}
}
class C extends B {
public function override() {
echo "Hi from C\n";
$this->bypassOverride();
}
}
$c = new C;
$c->override();
The output from this is
Hi from C
Hi from A
Hi from B
You could make bypassOverride() more generic and move it to a helper class if you need to do this a lot.
Is this possible?
No.
It makes no sense to use the parent keyword except in child classes. It's only purpose is to be used by child classes to call methods that it as overridden. Think about multi-level parent calls where a child calls its parent's method of the same name and, in turn, that parent calls its parent's method of the same name.
webbiedave is correct regarding parent, but it looks like you're trying to implement the Template Method pattern where the abstract base class calls a method that subclasses are expected to implement. Here's an example that demonstrates a horrible way to handle errors in your applications.
abstract class ExceptionIgnorer {
public function doIt() {
try {
$this->actuallyDoIt();
}
catch (Exception $e) {
// ignore the problem and it might go away...
}
}
public abstract function actuallyDoit();
}
class ErrorThrower extends ExceptionIgnorer {
public function actuallyDoIt() {
throw new RuntimeException("This will be ignored");
}
}
$thrower = new ErrorThrower;
$thrower->doIt(); // no problem
Here doIt() is the template method as it defines the overall algorithm to follow.