tags:

views:

678

answers:

5

There was an interesting question in a practice test that I did not understand the answer to. What is the output of the following code:

<?php
class Foo {
    public $name = 'Andrew';

    public function getName() {
     echo $this->name;
    }
}

class Bar extends Foo {
    public $name = 'John';

    public function getName() {
     Foo::getName();
    }
}

$a = new Bar;
$a->getName();
?>

Initially, I thought this was produce an error because static methods can not reference $this (atleast in PHP5). I tested this myself and it actually outputs John.

I added Foo::getName(); at the end of the script and did get the error I was expecting. So, what changes when you call a static method from within a class that extends the class you're calling from?

Would anyone mind explaining in detail exactly what is going on here?

+1  A: 

If you call the static method bound to the other object, the method is executed in the context of the current object. Which allows access to the $this-object.

Better way to call the superclass-method from inside the subclass would be:

parent::getName();
Ulf
Is there a super:: symbol in PHP? The only one I can think of is parent:: for static classes.
Sebastian Hoitz
super doesn't seem to work, parent does.
notruthless
you are right, i got mixed up
Ulf
+1  A: 

$this to the object in whose context the method was called. So: $this is $a->getName() is $a. $this in $fooInstance->getName() would be $fooInstance. In the case that $this is set (in an object $a's method call) and we call a static method, $this remains assigned to $a.

Seems like quite a lot of confusion could come out of using this feature. :)

siz
A: 

When you call $a->getName() you're referencing a specific object, $a, which is of class Bar and so returns "John".

Foo::getName() isn't valid outside the function because there's no specific object.

I'm not sure it works in PHP, but if you cast the object to the superclass as in (Foo)$a->getName() then you'd get "Andrew" as your result. You'd still be talking about the specific object ($a) but in this case of type Foo. (Note you wouldn't generally want to do this)

notruthless
+2  A: 

Foo::getName() is using an older PHP4 style of scope resolution operator to allow an overridden method to be called.

In PHP5 you would use parent::getName() instead

It's useful if you want to extend, rather than completely override the behaviour of the base class, e.g. this might make it clearer

class Bar extends Foo {
    public $name = 'John';

    public function getName() {
        echo "My name is ";
        parent::getName();
    }
}
Paul Dixon
A: 

Sometimes programmers are better at explaining things in code than in English!

The first thing going on here is the concept of overloading. When you instantiate Bar, it's getName() method overloads the method of the same name in Foo.

Overloading is a powerful and important part of OOD.

However, it is often useful to be able to call the version of a method that exists in the Parent class (Foo).

Here's an example:

class Dog
{
   public function getTag()
   {
      return "I'm a dog.";
   }
}

class Skip extends dog
{
   public function getTag()
   {
      return Dog::getTag() . " My name is Skip.";
      // I'm using Dog:: because it matches your example. However, you should use parent:: instead.
   }
}

$o = new Skip();
echo $o->getTag(); // Echo's: "I'm a dog. My name is Skip."

Clearly this is a very parochial example but it illustrates a point.

Your base class is the most general implementation of a Type. In this case, it's "Dog." You want to put information in this base class that is common to all instances of that Type. This prevents duplication in each of the Derived classes (like "Skip").

Your script is taking advantage of this feature, perhaps inadvertently.

Encoderer