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?
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?
Antworten:
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();
}
}
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
null
Standardwert für den Parameter festlegen.
drive
erfordert Car
, dann vorbei null
wäre sowieso nicht sehr hilfreich ...
function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);
Möglicherweise haben Sie eine, $methodName
aber keine $securityMode
.
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.
@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.
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).
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.
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.
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.
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.
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.
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
)
PHP12
werden 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
.