compile-fan
compile-fan

Reputation: 17615

Is there any polymorphism in PHP?

Suppose both base and son class have a method method_1,

and there's another method method_2 of base.

inside base::method_2,how can I point $this->method_1 to base::method_1 no matter whether $this is a instance of base or son?

Upvotes: 2

Views: 382

Answers (5)

joelhardi
joelhardi

Reputation: 11169

This will do what you want. Props to dbers for the example code (even if his didn't quite work).

<?php

class base {
  public function method1() {
    echo "base::method1\n";
  }
  public function method2() {
    if (get_parent_class($this) === FALSE) {
      echo get_class($this)." has no parent\n";
      $this->method1();
    } else {
      echo get_class($this)." has parent\n";
      call_user_func(array(get_parent_class($this), 'method1'));
    }
  }
}

class son extends base {
  public function method1() {
    echo "son::method1\n";
  }
}

$b = new base();
$b->method2();

$s = new son();
$s->method2();

?>

Outputs:

base has no parent
base::method1
son has parent
base::method1

Upvotes: 1

anon
anon

Reputation:

If you call a method that doesn't exist in your subclass, PHP will traverse the class hierarchy until it finds an ancestor class which implements the function you want. This means that if your son class doesn't implement method_2, PHP will automatically look for the nearest ancestor which does. In your case, it will call method_2 of base as you want.

If you are overriding the method_2 in your son class, and you want to do your own implementation of method_2 and also call the base::method_2 implementation then you can use the parent keyword:

class son extends base {
  public function method_2() {
    parent::method_2();
    //do son::method_2()-specific stuff here
  }
}

You can't chain parent calls together, so if base was a subclass of GrandparentClass you couldn't do something like this:

parent::parent::method_2(); // trying to call grandparent::method_2
                            // but this call will fail

But you can directly refer to ancestor classes by name, so this would work:

GrandparentClass::method_2();

And just to take it a little further, there is also a function called class_parents() which returns an array of every ancestor class your class inherits from. This could help if you wanted to go back, say, two ancestors, but you didn't know its specific name for some reason, you could still call the function using eval().

For example, this code would call GrandparentClass::method_2() without directly referencing the class by name in your code:

$parents = class_parents($this);
eval(end($parents) . "::method_2();");

Hope that helps.

Upvotes: 0

Dawson
Dawson

Reputation: 7597

Yes it does. It's singular (one parent).

son->method_1 can add to or override ALL of base->method_1 functionality.

son->method_1 can simply add an additional function, and utilize the rest of the functionality of it's parent's instance of method_1

So calling $this->method_1 would use base->method_1, and son->method_1 as long as what you want to use from base isn't overridden in son.

Upvotes: 0

dbers
dbers

Reputation: 654

If I understand you correctly, you want something like this:

<?php

class base {
  public function method1() {
    echo "base:method1\n";
  }
  public function method2() {
    if(get_class($this) == 'base') {
      $this->method1();
    }
    else {
      parent::method1();
    }
    echo "base:method2\n";
  }
}



class son extends base {
  public function method1() {
    echo "son:method1\n";
  }
}


$obj = new son();

$obj->method2();

where the call to method2 would always use the base version of the method1.

The best way I could do it is as above, but this code won't work since base has no parent. I'm pretty sure what you're trying to do isn't possible.

This is the error you will get:

PHP Fatal error:  Cannot access parent:: when current class scope has no parent in 

Upvotes: 1

Matthew
Matthew

Reputation: 48284

Make the function private:

<?php
class A
{
  public function __construct()
  {
    $this->foo();
    $this->bar();    
  }

  private function foo() { echo "A::foo()\n"; }
  public function bar() { echo "A::bar()\n"; }
}

class B extends A
{
  public function foo() { echo "B::foo()\n"; }
  public function bar() { echo "B::bar()\n"; }
}

new B();
?>

The output is:

A::foo()
B::bar()

Upvotes: 0

Related Questions