Comme seuls les chiens peuvent jouer à "chercher", cet exemple est-il une bonne ou une mauvaise idée? Je soupçonne que c'est une très mauvaise idée en raison de l'utilisation d'instance of, mais je ne sais pas trop pourquoi.
class Animal {
var $name;
function __construct($name) {
$this->name = $name;
}
}
class Dog extends Animal {
function speak() {
return "Woof, woof!";
}
function playFetch() {
return 'getting the stick';
}
}
class Cat extends Animal {
function speak() {
return "Meow...";
}
}
$animals = array(new Dog('Skip'), new Cat('Snowball'));
foreach($animals as $animal) {
print $animal->name . " says: " . $animal->speak() . '<br>';
if ($animal instanceof Dog) echo $animal->playFetch();
}
Un autre exemple. Comme je crée constamment des objets de données qui ont un identifiant, je me suis dit que je pourrais aussi bien les étendre à partir d’une classe de base pour éviter la duplication de code. Encore une fois, c'était mauvais, non? En tant que président, il n’a pas de nom et un chien n’a pas de roues. Mais ils sont les deux objets de données, donc c'est très déroutant.
class Data_Object {
protected $_id;
function setId($id) {
$this->_id = $id;
}
function getId() {
return $this->_id;
}
}
class Dog extends Data_Object {
protected $_name;
function setName($name) {
$this->_name =
}
function getName() {
return $this->_name;
}
}
class Chair extends Data_Object {
protected $_numberOfWheels;
function setNumberOfWheels($number) {
$this->_numberOfWheels = $number;
}
function getNumberOfWheels() {
return $this->_numberOfWheels;
}
}
Ce que je pense je demande, c'est essentiellement: "toutes les sous-classes doivent-elles avoir la même interface ou peuvent-elles en avoir différentes?"
Dans ce contexte, il est utile de parler de interfaces.
interface Talkative {
public function speak();
}
class Dog extends Animal implements Talkative {
public function speak() {
return "Woof, woof!";
}
}
Tout animal ou humain (ou étranger) qui implémente l'interface Talkative peut être utilisé dans un contexte où des êtres bavards sont nécessaires:
protected function makeItSpeak(Talkative $being) {
echo $being->speak();
}
Ceci est une méthode polymorphe correctement utilisée. Cela vous est égal à quoi vous faites face tant qu'il peut speak()
.
Si Dog
s peut également jouer à chercher, c'est très bien pour eux. Si vous voulez généraliser cela, pensez-y aussi en termes d'interface. Peut-être qu'un jour, vous aurez un chat très bien entraîné qui peut aussi aller chercher chercher.
class Cog extends Cat implements Playfulness {
public function playFetch() { ... }
}
Le point important ici est que lorsque vous appelezplayFetch()
sur quelque chose, c'est parce que vous voulez jouer à chercher avec cet animal. Vous n'appelez pas playFetch
parce que, eh bien ... vous pouvez le faire, mais parce que vous voulez jouer à chercher en ce moment même. Si vous ne voulez pas jouer à chercher, vous ne l'appelez pas. Si vous avez besoin de jouer à chercher dans une situation donnée, vous avez besoin de quelque chose qui puisse jouer à chercher. Vous vous en assurez par le biais de déclarations d'interface.
Vous pouvez réaliser la même chose en utilisant l'héritage de classe, c'est simplement moins flexible. Dans certaines situations où des hiérarchies rigides existent bien que cela soit parfaitement utile:
abstract class Animal { }
abstract class Pet extends Animal { }
class Dog extends Pet {
public function playFetch() { ... }
}
class GermanShepherd extends Dog {
public function beAwesome() { ... }
}
Ensuite, dans un contexte spécifique, vous pouvez ne pas avoir besoin de de tout objet capable de faire quelque chose (interface), mais vous cherchez spécifiquement une GermanShepherd
, car elle peut être géniale:
protected function awesomeness(GermanShepherd $dog) {
$dog->beAwesome();
}
Peut-être que plus tard, vous ferez une nouvelle race de GermanShepherd
s qui sont aussi géniaux, mais extend
la classe GermanShepherd
. Ils fonctionneront toujours avec la fonction awesomeness
, tout comme avec les interfaces.
Ce que vous ne devriez certainement pas faire, c’est de parcourir en boucle une série de choses aléatoires, de vérifier ce qu’elles sont et de les laisser faire ce qu’elles font. Ce n'est tout simplement pas très judicieux dans aucun contexte.
Un autre exemple de polymorphisme en 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);
?>
Presque pareil que toi Krishnadas, Brad. Cet article m'a beaucoup aidé à comprendre comment gérer le polymorphisme en 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);
Le polymorphisme décrit un modèle de programmation orientée objet dans lequel les classes ont des fonctionnalités différentes tout en partageant une interface commune
InterfaceUne interface est similaire à une classe, sauf qu'elle ne peut pas contenir de code. Une interface peut définir des noms de méthodes et des arguments, mais pas le contenu des méthodes. Toute classe implémentant une interface doit implémenter toutes les méthodes définies par l'interface. Une classe peut implémenter plusieurs interfaces.
Une interface est déclarée à l'aide du mot clé 'interface':
interface MyInterface {
// methods
}
et est attaché à une classe en utilisant le mot clé 'implements' (plusieurs interfaces peuvent être implémentées en les listant séparées par des virgules):
class MyClass implements MyInterface {
// methods
}
Les méthodes peuvent être définies dans l'interface comme dans une classe, sauf que le corps ne figure pas entre les accolades:
interface MyInterface {
public function doThis();
public function doThat();
public function setName($name);
}
Toutes les méthodes définies ici devront être incluses dans les classes d'implémentation exactement comme décrit. (lisez les commentaires du code ci-dessous)
// VALIDE
class MyClass implements MyInterface {
protected $name;
public function doThis() {
// code that does this
}
public function doThat() {
// code that does that
}
public function setName($name) {
$this->name = $name;
}
}
// INVALID
class MyClass implements MyInterface {
// missing doThis()!
private function doThat() {
// this should be public!
}
public function setName() {
// missing the name argument!
}
}