PHP – Abstract Classes and Interfaces

15 04 2010

For those of you who may be looking for my Compression Part IV — it is coming soon. In the meantime, I thought it would be fun to take a quick look at PHP’s abstract classes and interfaces. I had a phone screen today and the subject of polymorphism came up. I think the case can be made that PHP has polymorphism to the extent that you can create different objects which all have the same method although each object may implement the method differently.

While googling the topic of polymorphism, not something I tend to think about in my daily programming life, I came across an interesting example on wikipedia that shows an abstract class only partially implementing an interface. How can that be? If a class implements an interface it surely is duty bound to honor its contract and fully implement the interface, n’est pas? Well, there is a loophole. An abstract class owing to its nature can avoid fully implementing an interface. Let’s see how this works by first looking at the output of the following code which uses a regular class:


<?php
interface IPlantMagic
{
function sing();
}
class GardenBase implements IPlantMagic
{
public function drink() {
echo "slurp, slurp";
}
}
class Daisy extends GardenBase
{
public function sing()
{
return "Daisy, Daisy, give me your answer, do, ....";
}
}
class Rose extends GardenBase
{
public function sing()
{
return "I want some red rozes for a blue lady ...";
}
}
class PineTree extends GardenBase
{
public function sing()
{
return "We're off to see the wiard, the wonderful wizard of oz ...";
}
}
$myGarden = array(
new Daisy(),
new Rose(),
new PineTree()
);
// water the garden and hear its music
foreach ($myGarden as $member) {
echo $member->drink() . ' -- ' .$member->sing();
}

When you run this code you should see an error message to this effect:

Fatal error: Class GardenBase contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (IPlantMagic::sing)

So this error message indicates that you have an interesting option. You could make GardenBase an abstract class and then the abstract class is off the hook as regards implementing the interface. Let’s do just that:


<?php
interface IPlantMagic
{
function sing();
}
abstract class GardenBase implements IPlantMagic
{
public function drink() {
echo "slurp, slurp";
}
}
class Daisy extends GardenBase
{
public function sing()
{
return "Daisy, Daisy, give me your answer, do, ....";
}
}
class Rose extends GardenBase
{
public function sing()
{
return "I want some red rozes for a blue lady ...";
}
}
class PineTree extends GardenBase
{
public function sing()
{
return "We're off to see the wizard, the wonderful wizard of oz ...";
}
}
$myGarden = array(
new Daisy(),
new Rose(),
new PineTree()
);
// water the garden and hear its music
foreach ($myGarden as $member) {
echo $member->drink() . ' -- ' .$member->sing();
}

What we learn from this second example, is that we have implicitly made sing() an abstract method of the abstract class GardenBase by failing to adhere to implementing its interface of IPlantMagic. This works because the implementation does occur in all the subclasses of the abstract class. Now is this a good thing to do?

Other developers shouldn’t have to spend time figuring out your code. Either put in a comment to document that sing() is an abstract method in the abstract class GardenBase or else display in that class sing() with an empty implementation. Or, you could forget even using the interface and simply make sing() an abstract method as follows:


<?php
abstract class GardenBase
{
public function drink() {
echo "slurp, slurp";
}
abstract public function sing();
}
class Daisy extends GardenBase
{
public function sing()
{
return "Daisy, Daisy, give me your answer, do, ....";
}
}
class Rose extends GardenBase
{
public function sing()
{
return "I want some red rozes for a blue lady ...";
}
}
class PineTree extends GardenBase
{
public function sing()
{
return "We're off to see the wizard, the wonderful wizard of oz ...";
}
}
$myGarden = array(
new Daisy(),
new Rose(),
new PineTree()
);
// water the garden and hear its music
foreach ($myGarden as $member) {
echo $member->drink() . ' -- ' .$member->sing();
}

This work is licensed under a Creative Commons License
.

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: