Warum hat PHP Schnittstellen?

35

Ich habe festgestellt, dass ab PHP5 der Sprache Schnittstellen hinzugefügt wurden. Da PHP jedoch so lose geschrieben ist, scheinen die meisten Vorteile der Verwendung von Schnittstellen verloren zu gehen. Warum ist das in der Sprache enthalten?

GSto
quelle
5
Ich denke die richtige Frage ist, warum nicht?
Alberto Fernández
5
weil sie keinen Nutzen zu bieten scheinen, warum sie also einbeziehen?
GSto
4
@HorusKol und bevor sie implementiert wurden, wurden sie nicht verwendet, sodass Sie sehen können, wie sie nur in einer früheren Version nicht verwendet und nutzlos waren. Sie müssen auch die Behauptung aufstellen und unterstützen, dass ihre Verwendung irgendwie eine Verbesserung darstellt, um zu sagen, dass sie nützlich sind.
Rein Henrichs
6
@ HorusKol Überhaupt nicht spekulativ. Es ist einfach, das Wertversprechen des Hammers zu demonstrieren. Diese Frage fordert jemanden auf, das Wertversprechen von PHP-Schnittstellen zu demonstrieren und nicht nur zu erklären, dass sie in argumentativer Weise wertvoll sind.
Rein Henrichs
3
Und denken Sie daran, dass es bei Interfaces nicht nur um das Tippen geht. Eine Schnittstelle ist ein Vertrag besagt , dass eine implementierende Klasse muss die Methoden umfassen sie auslegt. Nützlich für Dinge wie Plugin-Engines.
Michael

Antworten:

30

Der Hauptvorteil von Interfaces in PHP ist, dass Klassen mehrere Interfaces implementieren können. Auf diese Weise können Sie Klassen gruppieren, die einige Funktionen gemeinsam nutzen, jedoch nicht unbedingt eine übergeordnete Klasse. Einige Beispiele könnten das Zwischenspeichern, Ausgeben oder Zugreifen auf Eigenschaften der Klasse auf eine bestimmte Weise umfassen.

In Ihrem Code können Sie überprüfen, ob eine Klasse eine bestimmte Schnittstelle implementiert, anstatt den Klassennamen zu überprüfen. Dann funktioniert Ihr Code immer noch, wenn neue Klassen hinzugefügt werden.

PHP bietet einige vordefinierte Schnittstellen, die in verschiedenen Situationen nützlich sein können: http://php.net/manual/en/reserved.interfaces.php .

BEARBEITEN - Ein Beispiel hinzufügen

Wenn Sie über eine Schnittstelle mit dem Namen MyInterface verfügen und mit mehreren Objekten verschiedener Klassen arbeiten, die möglicherweise einige Funktionen gemeinsam nutzen oder nicht, können Sie mit den Schnittstellen Folgendes tun:

// Assume $objects is an array of instances of various classes
foreach($objects as $obj) {
 if($obj instanceof MyInterface) {
     $obj->a();
     $obj->b();
     $obj->c();
   }
}
pjskeptisch
quelle
23
Mit anderen Worten: "Sie können alle Vorteile von dynamisch geschriebenen Sprachen völlig ignorieren"
Kamil Tomšík
11
@Kamil, ich denke eher, dass Sie die Vorteile des statischen Tippens nutzen können, ohne die Nachteile zu erleiden, wenn Sie sie nicht möchten.
Karl Bielefeldt
9
sind Sie im Ernst? Instanz von? wenn-dann-wenn-dann-wenn-dann-die-zeit, kommt es dir nicht bekannt vor? Ah ja, prozedurale Programmierung.
Kamil Tomšík
23
@Kamil Tomšík Noch eine Beleidigung der Sprache von PHP und nicht der Leute, die es inkompetent benutzen. PHP verfügt über alle Werkzeuge für eine vollständige objektorientierte Programmierung. Ob Sie diese verwenden oder nicht, hängt vom Programmierer ab. Darüber hinaus ist an der prozeduralen Programmierung an und für sich nichts auszusetzen.
Lotus Notes
18
@Kamil - wie seltsam, wenn man deinen Kommentar liest, kann man zu dem Schluss kommen, dass es in OOP keine Wenn-S gibt und dass auf magische Weise Dinge funktionieren. Wow.
Michael JV
23

PHP ist lose geschrieben, aber es kann stark über Dinge wie Methodenparameter geschrieben werden.

Betrachten Sie das folgende Beispiel:

interface Car { function go(); }

class Porsche { function go() {} }

function drive(Car $car) {}

$porsche = new Porsche();

drive($porsche);

Der obige Code würde Folgendes ausgeben:

Das Argument 1, das an drive () übergeben wird, muss die Schnittstelle Car implementieren, die eine Instanz von Porsche ist

Emanuil Rusev
quelle
1
Klar ist es schade. Sie können jedoch einen nullStandardwert für den Parameter festlegen.
Emanuil Rusev
5
aber wenn ein driveerfordert Car, dann vorbei nullwäre sowieso nicht sehr hilfreich ...
HorusKol
7
Übergeben Sie niemals null. Verwenden Sie ein "Special Case" -Objekt (Google für die Erklärung von Martin Fowler).
Martin Blore
2
@Renesis Wenn Sie den Standardwert auf null setzen, können Sie null an Methoden mit Typhinweisen übergeben. Mit (CAR $ car = null) können Sie diese Methode mit null als Argument aufrufen. Dies wäre jedoch eine ziemlich dumme Übung. Warum um alles in der Welt möchten Sie das können?
Dqhendricks
2
Konkretes Beispiel: function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);Möglicherweise haben Sie eine, $methodNameaber keine $securityMode.
Nicole
7

Mit Schnittstellen können Sie das Open-Closed-Prinzip implementieren, eine lose gekoppelte Codebasis beibehalten und viele der besten OOP-Entwurfsmuster implementieren.

Zum Beispiel, wenn eine Klasse eine andere Klasse als Argument akzeptiert:

class A {

    public function __construct(B $class_b) {
        // use class b
        $class_b->run();
    }
}

Ihre Klasse A und Klasse B haben jetzt eine enge Kopplung, und Klasse A kann keine andere Klasse außer B verwenden. Der Typhinweis stellt sicher, dass Sie den richtigen Argumenttyp haben, hat aber jetzt die Beziehung zwischen A und B gefestigt.

Nehmen wir an, Sie möchten, dass Klasse A alle Arten von Klassen verwenden kann, die jedoch eine run () -Methode haben. Dies ist im Grunde (aber nicht ganz) das COMMAND-Entwurfsmuster. Zum Lösen würden Sie stattdessen hint mithilfe einer Schnittstelle anstelle einer konkreten Klasse eingeben. B würde diese Schnittstelle implementieren und wird als Argument für Klasse A akzeptiert. Auf diese Weise kann Klasse A jede Klasse akzeptieren, die diese Schnittstelle als Argument für ihren Konstruktor verwendet.

Diese Art der Codierung wird in den meisten OOP-Entwurfsmustern verwendet und ermöglicht VIEL einfachere Codeänderungen zu einem späteren Zeitpunkt. Diese sind Teil der Grundlagen der AGILE-Programmierung.

dqhendricks
quelle
1
Oder eine Unterklasse von B
Mez
7

@pjskeptic hat eine gute Antwort und @Kamil Tomšík hat einen guten Kommentar zu dieser Antwort.

Das Tolle an dynamisch getippten Sprachen wie PHP ist, dass Sie versuchen können, Methoden für Objekte zu verwenden, und Sie nicht angeschrien werden, es sei denn, die Methode ist nicht vorhanden.

Das Problem bei dynamisch getippten Sprachen wie PHP ist, dass Sie versuchen können, Methoden für Objekte zu verwenden. Sie werden angeschrien, wenn die Methode nicht vorhanden ist.

Schnittstellen bieten eine bequeme Möglichkeit, Methoden für ein unbekanntes Objekt aufzurufen und sicherzustellen, dass die Methoden vorhanden sind (nicht, dass sie unbedingt korrekt sind oder funktionieren). Es ist kein notwendiger Teil einer Sprache, aber es macht das Codieren bequemer. Es ermöglicht stark typisierten OOP-Entwicklern, stark typisierten PHP-Code zu schreiben, der dann mit lose typisiertem PHP-Code eines anderen PHP-Entwicklers zusammenarbeitet.

eine Funktion wie:

foo( IBar $bar )
{
  $baz = $bar->baz();
  ...
}

ist bequemer als:

foo( $bar )
{
  if ( method_exists( $bar, 'baz' ) )
  {
    $baz = $bar->baz();
  }
  else
  {
    throw new Exception('OMGWTF NO BAZ IN BAR!');
  }
  ...
}

und IMHO einfacher, lesbarer Code ist besserer Code.

zzzzBov
quelle
1
Stattdessen müssen Sie nur nicht nach der Methode suchen und abstürzen und brennen, wenn jemand Ihre Funktion mit den falschen Daten aufruft. Es ist nicht dein Problem, wenn jemand deine Funktion falsch einsetzt.
Raynos
nein genau - Ihr Beispiel ist ein Albtraum für alle, die eine dynamische "Ente" wie Proxy, Adapter, Dekorateur usw. übergeben
möchten
1
@Kamil? Wieso das. Ein Proxy wäre eine Wrapper-Klasse für ein Objekt, das die Schnittstelle nicht implementiert, damit es mit dieser Funktion verwendet werden kann.
tylermac
@tylermac dynamic proxy using __call () - und wenn __call die einzige Methode ist, kann es IBar einfach nicht implementieren, was bedeutet, dass Sie es nicht an foo (IBar $ bar) übergeben können
Kamil Tomšík
5

Sie sind völlig unbrauchbar, wenn Sie ein Duck-Typer sind. Wenn Sie Enten tippen, ist es ziemlich ärgerlich, mit Bibliotheken / Frameworks zu arbeiten, die irgendwelche Typ-Andeutungen verwenden.

Dies gilt auch für alle Arten der dynamischen Metaprogrammierung (magische Methoden).

Kamil Tomšík
quelle
3

PHP ist nicht locker oder stark, sondern dynamisch getippt .

Was Schnittstellen angeht, sollten Sie sich als Erstes fragen: Was sind die meisten Vorteile von Schnittstellen?

In OOP geht es bei Schnittstellen nicht nur um Typen, sondern auch um das Verhalten.

Da PHP auch über eine Tippfunktion verfügt , können Sie Benutzeroberflächen genauso verwenden wie in einer reinen Sprache wie Java.

interface File
{
    public function getLines();
}

CSVFile implements File
{
    public function getLines()
    {}
}

XMLFile implements File 
{
    public function getLines()
    {}
}

JSONFile implements File 
{
    public function getLines()
    {}
}

class FileReader
{
    public function read(File $file)
    {
        foreach($file->getLines() as $line)
        {
            // do something
        }
    }
}

Mit der Implementierung der PHP-Schnittstelle können Sie mit PHPUnit auch Mocks für abstrakte Klassen erstellen - und das ist eine unglaubliche Funktion:

public function testSomething()
{
    $mock = $this->getMockForAbstractClass('File');

    $mock->expects($this->once())
         ->method('getLines')
         ->will($this->returnValue(array()));

    // do your assertions
}

Im Grunde genommen können Sie eine SOLID- kompatible Anwendung in PHP haben, indem Sie die Sprachfunktionen verwenden. Eine davon sind Schnittstellen.

Daniel Ribeiro
quelle
0

Schnittstellen sind für die Abhängigkeitsinjektion viel nützlicher als konkret. Als Beispiel für Barebones:

interface Istore { 
  public function save(); 
}

class Article_DB implements Istore 
{ 
  public function save($data) 
  {
    // do save to format needed.
  } 
}

class Article
{
   private $content;

   public function content($content)
   {
     $this->content = $content;
   }

   public function save(Istore $store)
   {
     $store->save($this->content);
   }
}

$article = new Article();
$article->content('Some content');

$store = new Article_DB();
$article->save($store);

Sagen Sie nun, ob sich Ihre Anforderungen ändern und Sie als PDF speichern möchten. Sie können zu diesem Zweck eine neue Klasse erstellen, anstatt die Klasse Article zu verschmutzen.

class Article_PDF implements Istore 
{ 
  public function save($data) 
  {
    // do save to format needed.
  } 
}


$article = new Article();
$article->content('Some content');

$store = new Article_PDF();
$article->save($store);

Die Article-Klasse hat jetzt einen Vertrag, mit dem Klassen, die zum Speichern verwendet werden, die Istore-Schnittstelle implementieren müssen. Es ist egal, wo und wie gespeichert wird.

Pete
quelle
-1

Sie können "falsche" reale Objekte bereitstellen, die die Schnittstelle implementieren. Sie können dann einen Teil Ihres Codes einem Komponententest unterziehen, ohne echte Server, Dateisysteme, Sockets, Datenbanken usw. zu benötigen.

Martin Blore
quelle
-3

Viele Leute werden mich wahrscheinlich dafür hassen, dass ich auf diese Weise antworte, aber die Lösung Ihrer Tippprobleme kann einfach mit PHP behoben werden. Ja, PHP ist lose geschrieben, daher werden standardmäßig Typen angenommen, was einige Probleme verursachen kann , insbesondere bei Vergleichsoperationen, bei denen die meisten Leute Probleme damit haben. Abgesehen davon kann PHP genauso streng sein wie jede stark typisierte Sprache, wenn Sie das, was Sie verwenden, in den Typ umwandeln, den Sie benötigen, und dann bitweise Vergleichsoperatoren verwenden. Hier ist das einfachste Beispiel, an das ich denken kann:

$ myVar = (int) 0; $ myOtherVar = '0';

Vergleichen ($ myVar == $ myVar) würde gleich (bool) wahr sein

Aber das Vergleichen von ($ myVar === $ myVar) würde gleich (bool) falsch sein, genau wie jeder "getippte" Vergleich

Ich wünschte wirklich nur, Entwickler würden aufhören, sich über diese Dinge zu streiten, wenn Sie ein Problem mit der Funktionsweise von PHP haben, entweder in Java programmieren und leben und leben lassen oder es so verwenden, wie es tun wird, was Sie wollen. Was nützt dir das Zicken überhaupt? Eine Ausrede für den ganzen Tag? Möchtest du besser aussehen als jemand anderes? Nun, es ist großartig, dass Sie sich so hoch mit sich fühlen, dass Sie bereit sind, jemanden schlecht aussehen zu lassen, aber in Wirklichkeit ist es Ihre Präferenz und Ihre Überzeugungen jedem aufzuzwingen, lässt ihn einfach so codieren, dass er sich nicht damit abfinden kann, drei Dinge zu verursachen:

1) Sie werden Ihren Weg codieren, aber nach Ihren Maßstäben "chaotisch" (denken Sie, haben Sie jemals einen Java-Programmierer gesehen, der sein erstes PHP-Programm erstellt oder umgekehrt? Es wird genauso sein, wie Sie ihre Methodik ändern oder vielleicht sogar noch schlimmer.)

2) Sie werden etwas anderes finden, worüber Sie jammern können

3) Die Produktion wird wahrscheinlich länger dauern. Und vielleicht sehen Sie dadurch kurzfristig besser aus, aber das Team als Ganzes sieht schlechter aus (denken Sie daran, dass Sie möglicherweise langsamer codieren als jemand anderes, und das ist nicht unbedingt schlecht, solange das Team die Ergebnisse in einem angemessenen Zeitrahmen erfüllt. Wenn Sie Ihre Gewohnheiten jedoch jemandem aufzwingen, der in der Regel etwas schneller gearbeitet hat, kann dies dazu führen, dass Ihr gesamtes Team langsamer wird und in einem sehr anspruchsvollen Workflow schlechter aussieht.

Ich persönlich bevorzuge es, prozeduralen PHP-Code zu schreiben, obwohl ich vollständige Programme mit OOP in einigen verschiedenen Sprachen schreiben kann und kann. Davon abgesehen habe ich guten OOP-Code und schlechten OOP-Code gesehen, und guten Verfahrenscode und schlechten Verfahrenscode für diese Angelegenheit ... Es hat wirklich nichts mit der Praxis zu tun, aber mit den Gewohnheiten , die Sie verwenden und selbst dann, Viele Dinge sind meine interpretierten Gefühle ... das heißt nicht, dass ich schlecht über diese Entwickler reden oder mit "Mein Weg ist der beste" BS prahlen werde. Es ist genau das Richtige für mich und die Firma, für die ich arbeite, ist hübsch Ich bin mit meiner Arbeit zufrieden und stolz darauf. Es gibt Gründe, warum ein Standard festgelegt werden sollte, aber was Sie in den von Ihnen gewählten Standard aufnehmen, ist SEHR wichtig ... Vielen Dank, dass ich das von der Brust bekommen habe. Ich wünsche ihnen einen wunderbaren Tag.

Jake Pogorelec
quelle
-4
  1. Schnittstellen sind Teil des OOP-Paradigmas. Daher ist es in vielen Fällen sehr nützlich, wenn Sie versuchen, objektorientierte Teile oder Ihr System zu erstellen.
  2. So. Warum nicht? ;-)

Beispiele: Sie müssen Ihre Daten zwischenspeichern. Wie? Es gibt viele verschiedene Caching-Engines. Welches ist das beste? Wen kümmert es, wenn Sie eine abstrakte Ebene haben, die über eine ICacheDriver-Schnittstelle mit einer Reihe von Methoden wie key, get, put, clear usw. verfügt. Implementieren Sie einfach das, was Sie im aktuellen Projekt benötigen, und ändern Sie es, wenn Sie eine andere benötigen. Oder einfache Verwendung von toString. Sie haben eine Reihe von verschiedenen zeigbaren Objekten. Sie implementieren einfach eine Stringable-Schnittstelle (die die toString-Methode beschreibt [es gibt keine solchen Schnittstellen in PHP, aber zum Beispiel]) und interagieren einfach über Ihr gesamtes Objekt mit (string) $ obj. Es gibt alles, was Sie tun müssen, anstatt zu wechseln (true) {case $ obj isntanceof A1: "do 1"; brechen; ...}

Einfach. Es gibt also keine Frage "Warum?". Es gibt "wie man das besser nutzt?". ;-) Viel Glück.

Alex Yaroshevich
quelle
-5

Meine Vermutung.

PHP wird von vielen Einsteiger-Programmierern verwendet , Einsteiger-Programmierer werden im College in Java unterrichtet .

Nach ihrem Programmierkurs 101 wollen sie Java-Funktionen, weil ihnen das Denken so beigebracht wurde. Ein Denken nach Ihren eigenen Vorstellungen (oder das Verstehen von Duck Typing) ist schwer, wenn Sie erst 20 Jahre alt sind.

Zend ist pragmatisch, es ist einfacher, die Funktion hinzuzufügen, als vorzugeben, dass sie die ganze Zeit richtig ist.
Dies kauft auch mehr Benutzer ein, anstatt sie gehen zu lassen, also muss es gut sein.

Eine weitere Instanz dieses Prozesses? Menschen frisch aus .NET und Java Kurse auch wollen Frameworks von Foundation Classes , sie meckern, bis Zend Sprossen aus dem Zend Framework . Dies kauft noch mehr Benutzer. Und weiter und weiter...

(Die einzige Sprache , gegen die das PHP-Team bekanntermaßen im Laufe der Jahre gekämpft hat , ist goto)

ZJR
quelle
In meiner Vision PHP12werden wahrscheinlich alle Syntaxmerkmale der Welt (ich hoffe, es wird keine Abstraktionsschicht-Laufzeit erhalten, hart, da das Perl getötet hat) mit einem Augenzwinkern auf Funktions- und Datentyp-Paradigmen und immer noch nein goto.
ZJR
"es ist schwer, wenn du erst 20 bist" Wie könnte das Alter möglicherweise etwas damit zu tun haben, eines dieser Konzepte zu verstehen?
Evicatos
@Evicatos High Schooler-Programme, aber normalerweise haben sie schlechte Lehrer, schlechte Namenskonventionen und produzieren unhaltbare Blobs. Sie lernen, gleich zu Beginn des Studiums zu programmieren. Es dauert ein paar Jahre, bis sie es schaffen. Dann beginnen sie, von den hart getippten, von der Industrie gesegneten, akademisch anerkannten Sprachen abzuweichen, die ihnen in den ersten Jahren beigebracht wurden, und wenden sich pragmatischeren, von Enten getippten Sprachen zu. Ich glaube, das ist ein Bushido, den viele Programmierer teilen. Andererseits könnte dies nicht Ihre Erfahrung widerspiegeln, Sie könnten ein Autodidakt sein. Wenn ja, zeigen Sie uns den Weg.
ZJR