As only Dogs can play \"fetch\", is this example a good or a bad idea? I suspect it\'s a really bad idea due to the usage of instanceof, but I\'m not entirely sure why.
Almost the same as you Krishnadas, Brad. This article helped me alot in understanding how to handle polymorphism in PHP
http://code.tutsplus.com/tutorials/understanding-and-applying-polymorphism-in-php--net-14362
interface shape_drawer{
public function draw(Shape $obj);
}
class circle implements shape_drawer{
public function draw(Shape $obj){
echo "Drawing Circle, Area: {$obj->area} <br>";
}
}
class square implements shape_drawer{
public function draw(Shape $obj){
echo "Drawing Square, Area: {$obj->area} <br>";
}
}
class triangle implements shape_drawer{
public function draw(Shape $obj){
echo "Drawing Triangle, Area: {$obj->area} <br>";
}
}
class shape_factory{
public static function getShape(){
$shape = $_REQUEST['shape'];
if(class_exists($shape)) {
return new $shape();
}
throw new Exception('Unsupported format');
}
}
class Shape{
public function __construct($area){
$this->area = $area;
}
public function draw(shape_drawer $obj) {
return $obj->draw($this);
}
}
$shape = new Shape(50);
try {
$drawer = shape_factory::getShape();
}
catch (Exception $e) {
$drawer = new circle();
}
echo $shape->draw($drawer);
Another example for Polymorphism in PHP
<?php
interface Shape {
public function getArea();
}
class Square implements Shape {
private $width;
private $height;
public function __construct($width, $height) {
$this->width = $width;
$this->height = $height;
}
public function getArea(){
return $this->width * $this->height;
}
}
class Circle implements Shape {
private $radius;
public function __construct($radius) {
$this->radius = $radius;
}
public function getArea(){
return 3.14 * $this->radius * $this->radius;
}
}
function calculateArea(Shape $shape) {
return $shape->getArea();
}
$square = new Square(5, 5);
$circle = new Circle(7);
echo calculateArea($square), "<br/>";
echo calculateArea($circle);
?>
In this context it's useful to talk about interfaces.
interface Talkative {
public function speak();
}
class Dog extends Animal implements Talkative {
public function speak() {
return "Woof, woof!";
}
}
Any animal or human (or alien) that implements the Talkative interface can be used in a context where talkative beings are needed:
protected function makeItSpeak(Talkative $being) {
echo $being->speak();
}
This is a properly used polymorphic method. You don't care what you're dealing with as long as it can speak()
.
If Dog
s can also play fetch, that's great for them. If you want to generalize that, think about it in terms of an interface as well. Maybe one day you'll get a highly trained cat which can play fetch as well.
class Cog extends Cat implements Playfulness {
public function playFetch() { ... }
}
The important point here being that when you call playFetch()
on something, it's because you want to play fetch with that animal. You don't call playFetch
because, well... you can, but because you want to play fetch in this very moment. If you don't want to play fetch, then you don't call it. If you need to play fetch in a certain situation, then you need something that can play fetch. You ensure this through interface declarations.
You can achieve the same thing using class inheritance, it's just less flexible. In some situations where rigid hierarchies exist though it's perfectly useful:
abstract class Animal { }
abstract class Pet extends Animal { }
class Dog extends Pet {
public function playFetch() { ... }
}
class GermanShepherd extends Dog {
public function beAwesome() { ... }
}
Then, in some specific context, you may not require any object that can do something (interface), but you are specifically looking for a GermanShepherd
, because only it can be awesome:
protected function awesomeness(GermanShepherd $dog) {
$dog->beAwesome();
}
Maybe down the road you'll make a new breed of GermanShepherd
s that are also awesome, but extend
the GermanShepherd
class. They'll still work with the awesomeness
function, just like with interfaces.
What you certainly should not do is to loop through a bunch of random things, check what they are and make them do their own thing. That's just not very sensible in any context.