Allgemeiner Polymorphismus mit PHP-Beispielen

Lesezeit: 6 Minuten

Benutzer-Avatar
Dan

Da nur Hunde “Apportieren” spielen können, ist dieses Beispiel eine gute oder schlechte Idee? Ich vermute, dass es aufgrund der Verwendung von instanceof eine wirklich schlechte Idee ist, aber ich bin mir nicht ganz sicher, warum.

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();
}

Ein anderes Beispiel. Da ich ständig Datenobjekte erstelle, die eine ID haben, dachte ich, ich könnte sie genauso gut alle von einer Basisklasse aus erweitern, um Codeduplizierung zu vermeiden. Auch das war schlecht, oder? Denn ein Stuhl hat keinen Namen und ein Hund keine Räder. Aber sie sind beide Datenobjekte, also ist es sehr verwirrend.

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;
    }
}

Im Wesentlichen was ich denken Ich frage ist: “sollten alle Unterklassen die gleiche Schnittstelle haben oder können sie unterschiedliche haben?”

  • Ich bin mir ziemlich sicher, dass dies hier schon einmal gefragt wurde, aber die kurze Antwort lautet, dass es in Ordnung ist, wenn Unterklassen eine andere Schnittstelle haben.

    – NullUserException

    17. Dezember 2011 um 4:51 Uhr


  • Ich bin mir ziemlich sicher, dass das erste Beispiel aufgrund der Verwendung von instanceof für bedingte Logik nicht richtig ist. Besteht nicht der ganze Sinn des Polymorphismus darin, dies nicht zu tun?

    – Dan

    17. Dezember 2011 um 4:55 Uhr

  • Warum sollten Sie alle Tiere dazu bringen, etwas zu tun (sprechen), außer einer Art (Hund)? Klingt so, als ob die fehlerhafte Logik in der Schleife liegt, nicht die Klassendefinitionen.

    – NullUserException

    17. Dezember 2011 um 4:58 Uhr


  • Alle sprechen, auch der Hund. Aber nur der Hund kann Apportieren spielen. So oder so denke ich, dass ich hier etwas Hilfreiches gefunden haben könnte: stackoverflow.com/questions/6119087/…

    – Dan

    17. Dezember 2011 um 5:03 Uhr

  • Wenn zwei verschiedene Objekte dasselbe auf unterschiedliche Weise tun können, ist das Polymorphismus. Wenn ein Objekt kann zusätzlich etwas anderes tun, na ja, so sei es. Das ist dann einfach kein polymorphes Verhalten, da es ein für das Objekt einzigartiges Verhalten ist. Sie würden dieses spezifische Verhalten dann einfach nicht als polymorph behandeln.

    – verzeihen

    17. Dezember 2011 um 5:04 Uhr

Benutzer-Avatar
verzeihen

In diesem Zusammenhang ist es sinnvoll, darüber zu sprechen Schnittstellen.

interface Talkative {
    public function speak();
}

class Dog extends Animal implements Talkative {
    public function speak() {
        return "Woof, woof!";
    }
}

Jedes Tier oder Mensch (oder Alien), das die Talkative-Schnittstelle implementiert, kann in einem Kontext verwendet werden, in dem gesprächige Wesen benötigt werden:

protected function makeItSpeak(Talkative $being) {
    echo $being->speak();
}

Dies ist ein richtig verwendetes polymorphes Verfahren. Es ist dir egal was Sie beschäftigen sich so lange wie möglich speak().

Wenn Dogs können auch Apportieren spielen, das ist toll für sie. Wenn Sie das verallgemeinern wollen, denken Sie auch an eine Schnittstelle. Vielleicht bekommen Sie eines Tages eine gut ausgebildete Katze, die auch Apportieren spielen kann.

class Cog extends Cat implements Playfulness {
    public function playFetch() { ... }
}

Der wichtige Punkt hier ist, dass wenn Sie Anruf playFetch() auf etwas, weil du mit diesem Tier Apportieren spielen willst. Du rufst nicht an playFetch weil, naja… du kannst, aber weil du in diesem Moment Apportieren spielen willst. Wenn Sie nicht Apportieren spielen wollen, dann rufen Sie es nicht an. Wenn Sie in einer bestimmten Situation Apportieren spielen müssen, brauchen Sie etwas, das Apportieren spielen kann. Dies stellen Sie durch Schnittstellendeklarationen sicher.

Sie können dasselbe mit Klassenvererbung erreichen, es ist nur weniger flexibel. In einigen Situationen, in denen starre Hierarchien bestehen, ist es jedoch durchaus nützlich:

abstract class Animal { }

abstract class Pet extends Animal { }

class Dog extends Pet {
    public function playFetch() { ... }
}

class GermanShepherd extends Dog {
    public function beAwesome() { ... }
}

Dann benötigen Sie in einem bestimmten Kontext möglicherweise nicht irgendein Objekt das kann was (interface), aber du suchst gezielt nach einem GermanShepherdweil nur es großartig sein kann:

protected function awesomeness(GermanShepherd $dog) {
    $dog->beAwesome();
}

Vielleicht machen Sie später eine neue Art von GermanShepherds, die sind auch toll, aber extend das GermanShepherd Klasse. Sie werden immer noch mit dem arbeiten awesomeness funktionieren, genau wie bei Schnittstellen.

Was Sie auf keinen Fall tun sollten, ist, einen Haufen zufälliger Dinge durchzugehen, zu überprüfen, was sie sind, und sie ihr eigenes Ding machen zu lassen. Das ist einfach in keinem Zusammenhang sehr sinnvoll.

  • Es ist erfrischend zu sehen, wie ein PHP-Entwickler über Schnittstellen spricht. Ich verwende sie häufig in PHP, aber in den meisten großen Frameworks gibt es keine Liebe und daher eine sehr geringe Übernahme der Ideologie durch den üblichen PHP-Entwickler.

    – Nathan González

    17. Dezember 2011 um 5:52 Uhr

  • @deceze Tolle Antwort. Aber ich frage mich, ob Eigenschaften hier auch erwähnenswert sind. php.net/manual/en/language.oop5.traits.php

    – Muhammad Maqsoodur Rehman

    14. April 2014 um 10:05 Uhr

  • @Muhammad Nicht wirklich, IMO. Traits sind nicht typhintable und daher für die Diskussion etwas irrelevant.

    – verzeihen

    14. April 2014 um 10:16 Uhr

  • Ich weiß, es ist alt, aber wenn mein Hund “atmen”, “laufen”, “springen” kann und meine Katze das auch tut, bedeutet das, dass ich all diese Schnittstellen implementieren muss? Das sind viele Utensilien, nicht wahr?!

    – Steve Chamaillard

    4. November 2015 um 22:06 Uhr

  • @Steve 1) In der Praxis würden Sie wahrscheinlich nicht für jede dieser Methoden eine einzige Schnittstelle erstellen, Sie würden eine Schnittstelle erstellen, die alle drei dieser Methoden zusammen definiert. Es liegt an Ihnen, Ihre Schnittstellen in sinnvolle Teile zu unterteilen, die weder zu detailliert noch zu groß und zusammenhangslos sind. 2) Sie können zusammengesetzte Schnittstellen erstellen, z interface Mammal extends Breathing, Walking, Jumping.

    – verzeihen

    5. November 2015 um 8:03 Uhr

Benutzer-Avatar
Krishnadas PC

Ein weiteres Beispiel für Polymorphismus 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);
?>

Fast genauso wie du, Krishnadas, Brad. Dieser Artikel hat mir sehr geholfen zu verstehen, wie man mit Polymorphismus in PHP umgeht

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);

1135700cookie-checkAllgemeiner Polymorphismus mit PHP-Beispielen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy