FUDforum
Fast Uncompromising Discussions. FUDforum will get your users talking.

Home » Imported messages » comp.lang.php » Why is polymorphism in PHP not like other languages? Is there a bug in PHP?
Show: Today's Messages :: Polls :: Message Navigator
Return to the default flat view Create a new topic Submit Reply
Why is polymorphism in PHP not like other languages? Is there a bug in PHP? [message #185026] Mon, 24 February 2014 19:49 Go to previous message
kurtk(at)pobox(dot)com is currently offline  kurtk(at)pobox(dot)com
Messages: 10
Registered: May 2012
Karma:
Junior Member
Why can I (quite surprisingly) call a member function that only exists in a derived class through a reference to a base class

I stumbled upon this unexpected behaviour when implementing the Observer pattern in PHP.

The observer is class Quackologist

class Quackologist implements \SplObserver {

public function update(\SplSubject $subject)
{
echo ". $subject->whoami() . " just quacked.\n\n";
}
}

who observes various types of ducks that implement both \SplSubject (using the Observable trait below) and another interface, Quackable.

interface Quackable {

function quack();
}

trait Observable {

private $observers = array();

public function attach ( \SplObserver $observer )
{
$this->observers[spl_object_hash($observer)] = $observer;
}

public function detach( \SplObserver $observer )
{
unset($this->observers[spl_object_hash($observer)]);
}

public function notify()
{
foreach($this->observers as $observer) {

$observer->update($this);
}
}
}

class RedheadDuck implements Quackable, \SplSubject {
use Observable;

public function __construct() {}

public function quack()
{
echo "Quack";
$this->notify();
}
public function whoami() { return "Redhead Duck"; }
}

class RubberDuck implements Quackable, \SplSubject {
use Observable;

public function __construct() {}

public function quack()
{
echo "Squeak";
$this->notify();
}

public function whoami() { return "Rubber Duck"; }
}

The main logic is:

$array_of_duck = array();

$array_of_ducks[] = new RedheadDuck();
$array_of_ducks[] = new RubberDuck();

$quackologist = new Quackologist();

foreach ($array_of_ducks as $duck) {

$duck->attach($quackologist);
}

foreach ($array_of_ducks as $duck) {

$duck->quack();
}

The output is

Quack. Redhead Duck just quacked.
Squeak. Rubber Duck just quacked.

Calling $duck->quack() calls $this->notify(), which calls $observer->update($this). $this is a derived duck class; however, the update method of Quackologist takes \SplSubject, which does not contain the whoamI() method. So I expected a runtime error message similar to what you get with this
simple example.

class Base {}
class Derived extends Base {

public function whoami() { echo "I am Derived\n"; }

}

function test(Base $b)
{
$b->whoami();
}

$b = new Base();
$d = new Derived();

test($b);
test($d);

This expectedly results in the error message **Call to undefined method Base::whoami() in /home/kurt/public_html/spl/observer/test.php**.


If you try to implement similar Observer Pattern code in C++, you will get the expected compile error on the call to whoami() in Quackologist::update(Subject&)

class Subject;

class Observer { // abstract base
public:
virtual void update(Subject&) = 0;
};

class ObservableBase : public Subject { // Adds the virtual method whoami() not in Subject
public:
virtual string whoami() = 0;
};

// mixin: Reusable observer code
class Observable : public ObservableBase {

map<Observer *, Observer *> assoc_array;
public:
void registerObserver(Observer& obs);
void unregisterObserver(Observer& obs);
void notifyObservers();
};

void Observable::notifyObservers()
{
for ( auto current : assoc_array) {
(current.second)->update(*this);
}
}

class Subject { // abstract base
public:
virtual void notifyObservers() = 0;
virtual void registerObserver(Observer& obs) = 0;
virtual void unregisterObserver(Observer& obs) = 0;
};

class Quackologist : public Observer {
public:
void update(Subject& subject)
{
// This line below will not compile, which is expected.
cout << subject.whoami() << "\n" << endl;
}
};

Quackologist::update(Subject&) gives the expected compile error **error: no member named 'whoami' in 'Subject'**.

Why does in the simple Base/Derived PHP example give the expected runtime error but not the first example?
[Message index]
 
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Previous Topic: Completely stumped
Next Topic: Correlating curl resources to some other object.
Goto Forum:
  

-=] Back to Top [=-
[ Syndicate this forum (XML) ] [ RSS ]

Current Time: Thu Nov 28 00:47:22 GMT 2024

Total time taken to generate the page: 0.05423 seconds