Qual è il punto delle interfacce in PHP?

Le interfacce consentono di creare codice che definisce i methods delle classi che lo implementano. Tuttavia, non è ansible aggiungere alcun codice a questi methods.

Le classi astratte ti consentono di fare la stessa cosa, aggiungendo il codice al metodo.

Ora se riesci a raggiungere lo stesso objective con le classi astratte, perché abbiamo persino bisogno del concetto di interfacce?

Mi è stato detto che ha a che fare con la teoria OO da C ++ a Java, su cui si basa la roba OO di PHP. Il concetto è utile in Java ma non in PHP? E 'solo un modo per evitare di avere segnaposti disseminati nella class astratta? Mi sto perdendo qualcosa?

L'integer punto delle interfacce è quello di darti la flessibilità di avere la tua class costretta a implementare più interfacce, ma non consente ancora l'ereditarietà multipla. I problemi con l'ereditare da più classi sono molti e vari e la pagina di wikipedia su di esso li riassume abbastanza bene.

Le interfacce sono un compromesso. La maggior parte dei problemi con l'ereditarietà multipla non si applica alle classi astratte di base, quindi la maggior parte dei linguaggi moderni in questi giorni disabilita l'ereditarietà multipla, ma chiama le interfacce di base astratte e consente a una class di "implementare" quanti ne vogliono.

Il concetto è utile in tutto nella programmazione orientata agli oggetti. Per me penso a un'interface come a un contratto. Per tanto tempo la mia class e la tua class sono d'accordo su questo metodo di contratto di firma che possiamo "interfacere". Per quanto riguarda le classi astratte quelle che vedo come più di classi base che annullano alcuni methods e ho bisogno di riempire i dettagli.

Perché avresti bisogno di un'interface, se ci sono già classi astratte? Per prevenire l'ereditarietà multipla (può causare più problemi noti).

Uno di questi problemi:

Il "problema dei diamanti" (a volte indicato come il "diamante mortale della morte") è un'ambiguità che sorge quando due classi B e C ereditano da A, e la class D eredita sia da B che da C. Se esiste un metodo in A che B e / o C hanno scavalcato, e D non lo sovrascrive, quindi quale versione del metodo eredita D: quella di B, o quella di C?

Fonte: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

Perché / Quando utilizzare un'interface? Un esempio … Tutte le auto del mondo hanno la stessa interface (methods) … AccelerationPedalIsOnTheRight() , BrakePedalISOnTheLeft() . Immagina che each marchio automobilistico avrebbe questi "methods" diversi da un altro marchio. La BMW avrebbe i freni sul lato destro e la Honda avrebbe freni sul lato sinistro della ruota. Le persone dovrebbero imparare come questi "methods" funzionano each volta che comprano una marca diversa di auto. Ecco perché è una buona idea avere la stessa interface in più "luoghi".

Che cosa fa un'interface per te (perché qualcuno dovrebbe usarne una)? Un'interface ti impedisce di fare "errori" (ti assicura che tutte le classi che implementano un'interface specifica avranno tutti i methods che sono nell'interface).

 // Methods inside this interface, must be implemented in all classs which implement this interface. interface IPersonService { public function Create($personObject); } class MySqlPerson implements IPersonService { public function Create($personObject) { // Create a new person in MySql database. } } class MongoPerson implements IPersonService { public function Create($personObject) { // Mongo database creates a new person differenty then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object). } } 

In questo modo, il metodo Create() verrà sempre utilizzato allo stesso modo. Non import se stiamo usando la class MySqlPerson o la class MongoPerson . Il modo in cui usiamo un metodo rimane lo stesso (l'interface rimane la stessa).

Ad esempio, verrà usato in questo modo (ovunque nel nostro codice):

 new MySqlPerson()->Create($personObject); new MongoPerson()->Create($personObject); 

In questo modo, qualcosa di simile non può accadere:

 new MySqlPerson()->Create($personObject) new MongoPerson()->Create($personsName, $personsAge); 

È molto più facile ricordare un'interface e utilizzare la stessa ovunque, rispetto a più di una.

In questo modo, l'interno del metodo Create() può essere diverso per classi diverse, senza influenzare il codice "esterno", che chiama questo metodo. Tutto il codice esterno deve sapere che il metodo Create() ha 1 parametro ( $personObject ), perché è così che il codice esterno userà / chiamerà il metodo. Al codice esterno non import cosa succede nel metodo, deve solo sapere come usarlo / chiamarlo.

Puoi farlo anche senza un'interface, ma se usi un'interface, è "più sicura" (perché ti impedisce di fare errori). L'interface ti assicura che il metodo Create() avrà la stessa firma (stesso tipo e stesso numero di parametri) in tutte le classi che implementano l'interface. In questo modo puoi essere sicuro che QUALSIASI class che implementa l'interface IPersonService , avrà il metodo Create() (in questo esempio) e avrà bisogno solo di 1 parametro ( $personObject ) per essere chiamato / usato.

Una class che implementa un'interface, deve implementare tutti i methods, che l'interface ha / ha.

Spero di non essermi ripetuto troppo.

La differenza tra l'utilizzo di un'interface e una class astratta ha più a che fare con l'organizzazione del codice per me, piuttosto che l'applicazione da parte del linguaggio stesso. Li uso molto quando preparo il codice affinché altri sviluppatori lavorino in modo che rimangano nei templates di design previsti. Le interfacce sono una sorta di "design per contratto" in base al quale il tuo codice accetta di rispondere a un set prescritto di chiamate API che potrebbero provenire da un codice a cui non hai accesso.

Mentre l'ereditarietà della class astratta è una relazione "è una", non è sempre ciò che si vuole, e l'implementazione di un'interface è più di una "si comport come una" relazione. Questa differenza può essere piuttosto significativa in determinati contesti.

Ad esempio, supponiamo di avere un account di class astratta da cui si estendono molte altre classi (tipi di account e così via). Ha un particolare insieme di methods che sono applicabili solo a quel tipo di gruppo. Tuttavia, alcune di queste sottoclassi di account implementano Versionable, o Listable o Editable in modo che possano essere lanciate in controller che si aspettano di utilizzare tali API. Il controller non si cura di che tipo di object sia

Al contrario, posso anche creare un object che non si estende da Account, ad esempio una class astratta Utente, e comunque implementare Listabile e Modificabile, ma non Versionable, che qui non ha senso.

In questo modo, sto dicendo che la sottoclass di FooUser NON è un account, ma agisce come un object modificabile. Allo stesso modo, BarAccount si estende dall'account, ma non è una sottoclass Utente, ma implementa modificabile, elencabile e anche versionebile.

L'aggiunta di tutte queste API per Modificabile, Listabile e Versionable nelle stesse classi astratte non solo sarebbe disordinata e brutta, ma duplicherebbe le interfacce comuni in Account e Utente o imporrà il mio object Utente a implementare Versionable, probabilmente solo per lanciare un exception.

Le interfacce sono essenzialmente un progetto per ciò che è ansible creare. Definiscono quali methods deve avere una class, ma puoi creare methods extra al di fuori di tali limiti.

Non sono sicuro di cosa intendi per non essere in grado di aggiungere codice ai methods, perché puoi farlo. Stai applicando l'interface a una class astratta o alla class che la estende?

Un metodo nell'interface applicata alla class astratta dovrà essere implementato in quella class astratta. Tuttavia applica tale interface alla class che si estende e il metodo deve solo implementare nella class di estensione. Potrei sbagliarmi qui – non uso le interfacce tutte le volte che potrei / dovrei.

Ho sempre pensato alle interfacce come a un model per sviluppatori esterni oa un set di regole aggiuntivo per garantire che le cose fossero corrette.

Userai le interfacce in PHP:

  1. Per hide l'implementazione: stabilisce un protocollo di accesso a una class di oggetti e modifica l'implementazione sottostante senza refactoring in tutti i luoghi in cui hai utilizzato gli oggetti
  2. Per controllare il tipo, accertarsi che un parametro abbia $object instanceof MyInterface tipo $object instanceof MyInterface specifica $object instanceof MyInterface
  3. Per applicare il controllo dei parametri in fase di esecuzione
  4. Per implementare più comportmenti in una singola class (costruisci tipi complessi)

class Car implementa EngineInterface, BodyInterface, SteeringInterface { in modo che un object Car ora start() , stop() (EngineInterface) o goRight() , goLeft() (Interfaccia dello sterzo)

e altre cose a cui non riesco a pensare in questo momento

Il numero 4 è probabilmente il caso d'uso più ovvio che non puoi affrontare con classi astratte.

Da Pensare in Java:

Un'interface dice: "Questo è quello che assomigliano a tutte le classi che implementano questa particolare interface." Così, qualsiasi codice che usi una particolare interface sa quali methods possono essere chiamati per quell'interface, e questo è tutto. Quindi l'interface viene utilizzata per stabilire un "protocollo" tra le classi.

Le interfacce non esistono come base su cui le classi possono estendersi ma come una mappa delle funzioni richieste.

Di seguito è riportto un esempio di utilizzo di un'interface in cui una class astratta non è adatta:
Diciamo che ho un'applicazione calendario che consente agli utenti di importre i dati del calendario da fonti esterne. Scriverei classi per gestire l'importzione di each tipo di origine dati (ical, rss, atom, json) Ciascuna di queste classi implementerebbe un'interface comune che assicurerebbe che tutti abbiano i methods pubblici comuni richiesti dalla mia applicazione per get i dati.

 <?php interface ImportbleFeed { public function getEvents(); } 

Quindi, quando un utente aggiunge un nuovo feed, posso identificare il tipo di feed che è e utilizzare la class sviluppata per quel tipo per importre i dati. Ogni class scritta per importre dati per un feed specifico avrebbe codice completamente diverso, altrimenti potrebbero esserci pochissime somiglianze tra le classi al di fuori del fatto che sono richieste per implementare l'interface che consente alla mia applicazione di consumarle. Se wheressi usare una class astratta, potrei facilmente ignorare il fatto che non ho sovrascritto il metodo getEvents () che poi interromperà la mia applicazione in questa istanza, mentre l'utilizzo di un'interface non consentirebbe l'esecuzione della mia app se NEO dei methods definito nell'interface non esiste nella class che lo ha implementato. La mia app non deve preoccuparsi di quale class utilizza per get i dati da un feed, solo che i methods necessari per get tali dati sono presenti.

Per fare un ulteriore passo avanti, l'interface si rivela estremamente utile quando torno alla mia app di calendario con l'intento di aggiungere un altro tipo di feed. L'utilizzo dell'interface ImportbleFeed significa che posso continuare ad aggiungere più classi che importno diversi tipi di feed semplicemente aggiungendo nuove classi che implementano questa interface. Ciò mi consente di aggiungere tonnellate di funzionalità senza wherer aggiungere inutilmente alla mia applicazione principale poiché la mia applicazione principale si basa solo sui methods pubblici disponibili che l'interface richiede, purché le mie nuove classi di importzione dei feed implementino l'interface ImportbleFeed quindi so che posso semplicemente rilasciarlo e continuare a muoverlo.

Questo è solo un inizio molto semplice. Posso quindi creare un'altra interface che sia ansible richiedere a tutte le mie classi del calendario per implementare che offra più funzionalità specifiche per il tipo di feed gestito dalla class. Un altro buon esempio potrebbe essere un metodo per verificare il tipo di feed, ecc.

Questo va al di là della domanda, ma poiché ho usato l'esempio sopra: le interfacce hanno il loro insieme di problemi se usate in questo modo. Mi trovo a wherer garantire l'output che viene restituito dai methods implementati per abbinare l'interface e per get ciò utilizzo un IDE che legge i blocchi PHPDoc e aggiungo il tipo restituito come un suggerimento di tipo in un block PHPDoc dell'interface che verrà poi traduci nella class concreta che la implementa. Le mie classi che consumano i dati in output dalle classi che implementano questa interface sapranno perloless che si aspetta un arrays restituito in questo esempio:

 <?php interface ImportbleFeed { /** * @return arrays */ public function getEvents(); } 

Non c'è molto spazio in cui confrontare classi e interfacce astratte. Le interfacce sono semplicemente mappe che una volta implementate richiedono alla class di avere un insieme di interfacce pubbliche.

Secondo me, le interfacce dovrebbero essere preferite rispetto alle classi astratte non funzionali. Non sarei sorpreso se ci fosse anche un colpo di performance lì, poiché c'è un solo object istanziato, invece di parsing due, combinandoli (anche se, non posso esserne sicuro, non ho familiarità con i meccanismi interni di OOP PHP).

È vero che le interfacce sono less utili / significative rispetto a, diciamo, Java. D'altra parte, PHP6 introdurrà ancora più hint di tipo, incluso il suggerimento sul tipo per i valori di return. Questo dovrebbe aggiungere un certo valore alle interfacce PHP.

tl; dr: interfaces definisce un elenco di methods che devono essere seguiti (think API), mentre una class astratta fornisce alcune funzionalità di base / comuni, che le sottoclassi perfezionano per esigenze specifiche.

Le interfacce non servono solo per garantire che gli sviluppatori implementino determinati methods. L'idea è che siccome queste classi sono garantite con determinati methods, puoi usare questi methods anche se non conosci il tipo effettivo della class. Esempio:

 interface Readable { String read(); } List<Readable> readables; // dunno what these actually are, but we know they have read(); for(Readable reader : readables) System.out.println(reader.read()); 

In molti casi, non ha senso fornire una class base, astratta o less, perché le implementazioni variano in modo selvaggio e non condividono nulla in comune oltre a pochi methods.

Le lingue digitate dynamicmente hanno la nozione di "digitazione" in cui non sono necessarie le interfacce; sei libero di assumere che l'object abbia il metodo con cui lo stai chiamando. Questo aggira il problema in linguaggi tipizzati staticamente where il tuo object ha qualche metodo (nel mio esempio read ()), ma non implementa l'interface.

Non riesco a ricordare se PHP sia diverso da questo punto di vista, ma in Java è ansible implementare più interfacce, ma non è ansible ereditare più classi astratte. Immagino che PHP funzioni allo stesso modo.

In PHP puoi applicare più interfacce separandole con una virgola (penso, non trovo che una solitaria pulita).

Per quanto riguarda più classi astratte potresti avere più abstract che si estendono l'un l'altro (di nuovo, non ne sono completamente sicuro, ma penso di averlo visto da qualche parte prima). L'unica cosa che non puoi estendere è una class finale.

Le interfacce non daranno al tuo codice alcun incremento di performance o qualcosa del genere, ma possono fare molto per renderlo gestibile. È vero che una class astratta (o anche una class non astratta) può essere usata per stabilire un'interface al tuo codice, ma le interfacce appropriate (quelle che definisci con la parola chiave e che contengono solo firme del metodo) sono semplicemente più semplici da ordinare e leggere.

Detto questo, tendo a usare discrezione quando decido di utilizzare o less un'interface su una class. A volte voglio implementazioni di metodo predefinite o variables che saranno comuni a tutte le sottoclassi.

Naturalmente, anche l'implementazione dell'interface multipla è solida. Se si dispone di una class che implementa più interfacce, è ansible utilizzare un object di quella class come tipi diversi nella stessa applicazione.

Il fatto che la tua domanda riguardi PHP, tuttavia, rende le cose un po 'più interessanti. Digitare le interfacce non è ancora incredibilmente necessario in PHP, where puoi praticamente dare da mangiare a qualsiasi metodo, indipendentemente dal suo tipo. È ansible digitare staticamente i parametri del metodo, ma alcuni di questi sono interrotti (Stringa, credo, causi alcuni inconvenienti). Accoppialo con il fatto che non puoi digitare la maggior parte degli altri riferimenti e non c'è molto valore nel tentativo di forzare la digitazione statica in PHP ( a questo punto ). E a causa di ciò, il valore delle interfacce in PHP , a questo punto, è molto inferiore rispetto a quello in lingue più fortemente tipizzate. Hanno il vantaggio della leggibilità, ma poco altro. L'implementazione multipla non è nemless vantaggiosa, perché devi ancora dichiarare i methods e assegnare loro corpi all'interno dell'implementatore.

Di seguito sono riportti i punti per l'interface PHP

  1. Viene utilizzato per definire il numero richiesto di methods in class [se si desidera caricare html, quindi id e nome è richiesto, in questo caso l'interface include setID e setName].
  2. L'interface costringe rigorosamente la class a includere tutti i methods definiti in essa.
  3. È ansible definire solo il metodo nell'interface con l'accessibilità pubblica.
  4. Puoi anche estendere l'interface come class. Puoi estendere l'interface in php usando la parola chiave extends.
  5. Estendi interface multipla.
  6. Non è ansible implementare 2 interfacce se entrambe condividono la function con lo stesso nome. Lancia errore.

Codice di esempio:

 interface test{ public function A($i); public function B($j = 20); } class xyz implements test{ public function A($a){ echo "CLASS A Value is ".$a; } public function B($b){ echo "CLASS B Value is ".$b; } } $x = new xyz(); echo $x->A(11); echo "<br/>"; echo $x->B(10);