Qual é o objetivo das interfaces em PHP?

224

As interfaces permitem criar código que define os métodos das classes que o implementam. No entanto, você não pode adicionar nenhum código a esses métodos.

As classes abstratas permitem que você faça a mesma coisa, além de adicionar código ao método.

Agora, se você pode alcançar o mesmo objetivo com as classes abstratas, por que precisamos do conceito de interfaces?

Foi-me dito que isso tem a ver com a teoria de OO, de C ++ a Java, que é o material do PHP baseado em OO. O conceito é útil em Java, mas não em PHP? É apenas uma maneira de evitar que os espaços reservados sejam desarrumados na classe abstrata? Estou esquecendo de algo?

mk.
fonte
4
Você tem que ler este: stackoverflow.com/a/384067/14673
Luc M
tenho certeza de que é um auxílio mental e um auxílio à comunicação. As interfaces agem como excelentes ferramentas de ensino para a sua API, uma vez que agrupam os serviços que ela expõe juntos de uma maneira abstrata que pode ser lida sem o conhecimento da implementação. Isso é caro, mas, como as pessoas que se acostumam com a interface, já podem usar as funções diretamente sem precisar de classes, economizando um ponteiro. sem interfaces definidas por idioma, pode ser complicado planejar com antecedência para muitos programadores, já que as pessoas costumavam "usar linguagens" geralmente preferem projetar com interfaces do que no papel.
Dmitry

Respostas:

142

O objetivo das interfaces é oferecer a flexibilidade de que sua classe seja forçada a implementar várias interfaces, mas ainda não permita herança múltipla. Os problemas com a herança de várias classes são muitos e variados, e a página da Wikipedia nela os resume muito bem.

As interfaces são um compromisso. A maioria dos problemas com herança múltipla não se aplica a classes base abstratas, portanto, a maioria das linguagens modernas hoje em dia desabilita a herança múltipla, mas ainda chama interfaces de classes base abstratas e permite que uma classe "implemente" quantas delas quiser.

Craig H
fonte
39
Também se pode dizer que * Interfaces fornecem o design para uma classe com zero implementação. * As classes abstratas fornecem algum design, com alguma implementação. As classes abstratas são mais úteis onde as classes filho compartilham algumas semelhanças de implementação, mas diferem em determinadas implementações.
Jrgns
@ Craig, Não há nenhum problema inerente à herança múltipla, apenas que os idiomas atuais não são poderosos o suficiente para implementá-los adequadamente. Os "problemas" podem realmente ser resolvidos com bastante facilidade, por exemplo, declarar o caminho explícito da herança para funções herdadas com o mesmo nome pode resolver o dilema do diamante.
Pacerier 7/03/15
15
Não é disso que se trata as interfaces. Não é um compromisso sobre herança múltipla, trata-se de criar um contrato conceitual e abstrato para objetos a serem implementados e outros objetos / métodos para consumir. interfaces são uma ferramenta para polimorfismo, e não para herança direta.
Ghost de Madara
123

O conceito é útil em toda a programação orientada a objetos. Para mim, penso em uma interface como um contrato. Desde que minha turma e sua turma concordem com este contrato de assinatura de método, podemos "fazer interface". Quanto às classes abstratas, aquelas que eu vejo como mais classes básicas que esboçam alguns métodos e preciso preencher os detalhes.

John Downey
fonte
Isso me fez entender um pouco. É como nos espaços para nome - portanto, o código compartilhado é mais fácil de usar e sem conflitos. É mais fácil quando duas pessoas fazem aulas na mesma base, certo?
RedClover
Não precisamos distinguir o conceito geral de uma 'interface' das interfaces concretas em uma linguagem como PHP? Qualquer função, por exemplo, possui uma "interface" que define como você a utiliza e oculta sua implementação. Portanto, esse tipo de interface "contratual" não requer um recurso de idioma especial. Portanto, o recurso de linguagem deve ser para outra coisa (ou algo além),.
UuDdLrLrSs
70

Por que você precisaria de uma interface, se já existem classes abstratas? Para impedir a herança múltipla (pode causar vários problemas conhecidos).

Um desses problemas:

O "problema do diamante" (às vezes chamado de "diamante mortal da morte") é uma ambiguidade que surge quando duas classes B e C herdam de A e a classe D herda de B e C. Se houver um método em A que B e C substituíram e D não o substituiu; então, qual versão do método D herda: a de B ou a de C?

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

Por que / quando usar uma interface? Um exemplo ... Todos os carros no mundo têm a mesma interface (métodos) ... AccelerationPedalIsOnTheRight(), BrakePedalISOnTheLeft(). Imagine que cada marca de carro tenha esses "métodos" diferentes de outra marca. BMW teria os freios no lado direito, e Honda teria freios no lado esquerdo da roda. As pessoas precisariam aprender como esses "métodos" funcionam toda vez que comprariam uma marca diferente de carro. É por isso que é uma boa ideia ter a mesma interface em vários "lugares".

O que uma interface faz por você (por que alguém usaria uma)? Uma interface evita que você cometa "erros" (assegura que todas as classes que implementam uma interface específica terão todos os métodos que estão na interface).

// Methods inside this interface must be implemented in all classes 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 differently 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).
    }
}

Dessa forma, o Create()método sempre será usado da mesma maneira. Não importa se estamos usando a MySqlPersonclasse ou a MongoPersonclasse. A maneira como estamos usando um método permanece a mesma (a interface permanece a mesma).

Por exemplo, será usado assim (em qualquer lugar do nosso código):

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

Dessa forma, algo assim não pode acontecer:

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

É muito mais fácil lembrar de uma interface e usar a mesma em todos os lugares, do que várias diferentes.

Dessa forma, o interior do Create()método pode ser diferente para diferentes classes, sem afetar o código "externo", que chama esse método. Tudo o que o código externo precisa saber é que o método Create()possui 1 parâmetro ( $personObject), porque é assim que o código externo usa / chama o método. O código externo não se importa com o que está acontecendo dentro do método; ele só precisa saber como usá-lo / chamá-lo.

Você pode fazer isso sem uma interface também, mas se você usar uma interface, é "mais seguro" (porque impede que você cometa erros). A interface garante que o método Create()tenha a mesma assinatura (mesmos tipos e um mesmo número de parâmetros) em todas as classes que implementam a interface. Dessa forma, você pode ter certeza de que QUALQUER classe que implementa a IPersonServiceinterface terá o método Create()(neste exemplo) e precisará de apenas 1 parâmetro ( $personObject) para ser chamado / usado.

Uma classe que implementa uma interface deve implementar todos os métodos que a interface possui / possui.

Espero não ter me repetido demais.

Jo Smo
fonte
Realmente boa analogia com os pedais do carro!
James
24

A diferença entre usar uma interface e uma classe abstrata tem mais a ver com a organização do código do que com a aplicação pela própria linguagem. Eu os uso muito ao preparar o código para outros desenvolvedores trabalharem, para que eles permaneçam dentro dos padrões de design pretendidos. As interfaces são um tipo de "design por contrato", no qual seu código concorda em responder a um conjunto prescrito de chamadas de API que podem ser provenientes de códigos que você não aceita.

Embora a herança da classe abstrata seja uma relação "é uma", isso nem sempre é o que você deseja, e implementar uma interface é mais uma relação "age como uma". Essa diferença pode ser bastante significativa em certos contextos.

Por exemplo, digamos que você tenha uma conta de classe abstrata da qual muitas outras classes se estendem (tipos de contas e assim por diante). Ele tem um conjunto específico de métodos que são aplicáveis ​​apenas a esse grupo de tipos. No entanto, algumas dessas subclasses de conta implementam Versionable, Listable ou Editable, para que possam ser lançadas em controladores que esperam usar essas APIs. O controlador não se importa com o tipo de objeto.

Por outro lado, também posso criar um objeto que não se estenda da Conta, digamos uma classe abstrata Usuário, e ainda implemente Listável e Editável, mas não Versão, o que não faz sentido aqui.

Dessa forma, estou dizendo que a subclasse FooUser NÃO é uma conta, mas age como um objeto Editável. Da mesma forma, BarAccount se estende da Conta, mas não é uma subclasse de Usuário, mas implementa Editável, Listável e também Versão.

A adição de todas essas APIs para Editável, Listável e Versionável nas próprias classes abstratas não seria apenas desorganizada e feia, mas duplicaria as interfaces comuns em Conta e Usuário ou forçaria meu objeto Usuário a implementar o Versionável, provavelmente apenas para lançar um exceção.

Sam McAfee
fonte
É isso aqui. Rigidamente impor devs usar seus métodos sem estender ou substituí-los
Nick
21

As interfaces são essencialmente um modelo para o que você pode criar. Eles definem quais métodos uma classe deve ter , mas você pode criar métodos extras fora dessas limitações.

Não sei ao certo o que você quer dizer com não poder adicionar código aos métodos - porque você pode. Você está aplicando a interface a uma classe abstrata ou à classe que a estende?

Um método na interface aplicada à classe abstrata precisará ser implementado nessa classe abstrata. No entanto, aplique essa interface à classe de extensão e o método só precisa ser implementado na classe de extensão. Eu posso estar errado aqui - não uso interfaces com a frequência que poderia / deveria.

Eu sempre pensei nas interfaces como um padrão para desenvolvedores externos ou um conjunto de regras extra para garantir que as coisas estejam corretas.

Ross
fonte
9
No PHP, as interfaces contêm apenas declaração de método e não a implementação real. Classes abstratas, no entanto, permitem "adicionar código" aos métodos a serem herdados pelas classes que o estendem. Eu acredito que essa diferença é a que mk estava se referindo.
Nocash # 24/09
13

Você usará interfaces no PHP:

  1. Para ocultar a implementação - estabeleça um protocolo de acesso a uma classe de objetos e altere a implementação subjacente sem refatorar em todos os lugares em que você usou esses objetos
  2. Para verificar o tipo - como para garantir que um parâmetro tenha um tipo específico $object instanceof MyInterface
  3. Para impor a verificação de parâmetros em tempo de execução
  4. Para implementar vários comportamentos em uma única classe (criar tipos complexos)

    classe Carro implementa EngineInterface, BodyInterface, SteeringInterface {

para que um Carobjeto ca agora start(), stop()(EngineInterface) ou goRight(), goLeft()(interface de direção)

e outras coisas em que não consigo pensar agora

Número 4, é provavelmente o caso de uso mais óbvio que você não pode resolver com classes abstratas.

De Pensando em Java:

Uma interface diz: "É assim que serão todas as classes que implementam essa interface específica". Portanto, qualquer código que use uma interface específica sabe quais métodos podem ser chamados para essa interface, e isso é tudo. Portanto, a interface é usada para estabelecer um "protocolo" entre as classes.

catalin.costache
fonte
10

As interfaces existem não como uma base na qual as classes podem se estender, mas como um mapa das funções necessárias.

A seguir, é apresentado um exemplo do uso de uma interface em que uma classe abstrata não se encaixa:
Digamos que eu tenha um aplicativo de calendário que permita aos usuários importar dados de calendário de fontes externas. Eu escreveria classes para lidar com a importação de cada tipo de fonte de dados (ical, rss, atom, json). Cada uma dessas classes implementaria uma interface comum que garantiria que todos eles tivessem os métodos públicos comuns que meu aplicativo precisa para obter os dados.

<?php

interface ImportableFeed 
{
    public function getEvents();
}

Então, quando um usuário adiciona um novo feed, posso identificar o tipo de feed e usar a classe desenvolvida para esse tipo para importar os dados. Cada classe gravada para importar dados para um feed específico teria código completamente diferente. Caso contrário, poderá haver muito poucas semelhanças entre as classes, exceto pelo fato de serem necessárias para implementar a interface que permite que meu aplicativo as consuma. Se eu usasse uma classe abstrata, poderia facilmente ignorar o fato de não ter substituído o método getEvents () que quebraria meu aplicativo nessa instância, enquanto o uso de uma interface não deixaria meu aplicativo executar se QUALQUER um dos métodos definido na interface não existe na classe que o implementou. Meu aplicativo não precisa se importar com a classe usada para obter dados de um feed,

Para dar um passo adiante, a interface se mostra extremamente útil quando eu voltar ao meu aplicativo de calendário com a intenção de adicionar outro tipo de feed. Usar a interface ImportableFeed significa que posso continuar adicionando mais classes que importam diferentes tipos de feed, simplesmente adicionando novas classes que implementam essa interface. Isso permite que eu adicione toneladas de funcionalidade sem ter que adicionar desnecessariamente em massa ao meu aplicativo principal, já que meu aplicativo principal depende apenas da existência de métodos públicos disponíveis que a interface exige, desde que minhas novas classes de importação de feed implementem a interface ImportableFeed. sei que posso simplesmente colocá-lo no lugar e seguir em frente.

Este é apenas um começo muito simples. Posso então criar outra interface que todas as minhas classes de calendário possam implementar, oferecendo mais funcionalidades específicas ao tipo de feed que a classe manipula. Outro bom exemplo seria um método para verificar o tipo de feed etc.

Isso vai além da questão, mas desde que eu usei o exemplo acima: As interfaces vêm com seu próprio conjunto de problemas, se usadas dessa maneira. Sinto-me precisando garantir a saída retornada dos métodos implementados para corresponder à interface e, para isso, utilizo um IDE que lê blocos PHPDoc e adiciono o tipo de retorno como uma dica de tipo em um bloco PHPDoc da interface que, em seguida, traduzir para a classe concreta que a implementa. Minhas classes que consomem a saída de dados das classes que implementam essa interface, no mínimo, sabem que estão esperando uma matriz retornada neste exemplo:

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

Não há muito espaço para comparar classes e interfaces abstratas. Interfaces são simplesmente mapas que, quando implementados, exigem que a classe tenha um conjunto de interfaces públicas.

Houghtelin
fonte
Boa explicação :) Obrigado!
precisa saber é o seguinte
Apenas para adicionar informações: na classe abstrata, se você declarar o método como abstrato, ele se comportará como uma interface, para que você não possa ignorar o fato de não ter substituído o método getEvents (). O aplicativo falharia da mesma maneira que com a interface.
Rikudou_Sennin
8

As interfaces não servem apenas para garantir que os desenvolvedores implementem certos métodos. A idéia é que, como é garantido que essas classes tenham certos métodos, você pode usá-los mesmo que não conheça o tipo real da classe. Exemplo:

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

Em muitos casos, não faz sentido fornecer uma classe base, abstrata ou não, porque as implementações variam muito e não compartilham nada em comum além de alguns métodos.

Linguagens dinamicamente tipadas têm a noção de "digitação de pato", na qual você não precisa de interfaces; você pode assumir que o objeto tem o método que você está chamando. Isso soluciona o problema em linguagens estaticamente tipadas em que seu objeto tem algum método (no meu exemplo, read ()), mas não implementa a interface.

Programador foragido
fonte
6

Na minha opinião, as interfaces devem ser preferidas às classes abstratas não funcionais. Eu não ficaria surpreso se houvesse um impacto no desempenho, pois há apenas um objeto instanciado, em vez de analisar dois, combinando-os (embora, não tenha certeza, não estou familiarizado com o funcionamento interno OOP PHP).

É verdade que as interfaces são menos úteis / significativas do que em comparação com, digamos, Java. Por outro lado, o PHP6 apresentará ainda mais dicas de tipo, incluindo dicas de tipo para valores de retorno. Isso deve adicionar algum valor às interfaces PHP.

tl; dr: interfaces define uma lista de métodos que precisam ser seguidos (pense na API), enquanto uma classe abstrata fornece algumas funcionalidades básicas / comuns, que as subclasses refinam para necessidades específicas.

Henrik Paul
fonte
O PHP 6 nunca será lançado. O PHP 6 foi um projeto que estava em desenvolvimento entre 2005 e 2010, mas foi atrasado e, finalmente, cancelado. O PHP 7 é a próxima versão, principalmente para evitar confusão com o projeto anterior do PHP 6.
Ashu Jha 19/09/16
5

Não me lembro se o PHP é diferente nesse aspecto, mas em Java, você pode implementar várias interfaces, mas não pode herdar várias classes abstratas. Eu diria que o PHP funciona da mesma maneira.

No PHP, você pode aplicar várias interfaces, separando-as com uma vírgula (acho que não considero uma solução limpa).

Quanto a várias classes abstratas, você pode ter vários resumos se estendendo (novamente, não tenho muita certeza disso, mas acho que já vi isso em algum lugar antes). A única coisa que você não pode estender é uma aula final.

Ross
fonte
4

As interfaces não fornecerão ao seu código nenhum aumento de desempenho ou algo parecido, mas podem ajudar bastante a torná-lo sustentável. É verdade que uma classe abstrata (ou mesmo uma classe não abstrata) pode ser usada para estabelecer uma interface para o seu código, mas as interfaces apropriadas (aquelas que você define com a palavra-chave e que contêm apenas assinaturas de método) são muito mais fáceis de usar. classificar e ler.

Dito isto, costumo usar discrição ao decidir se deve ou não usar uma interface em uma classe. Às vezes, eu quero implementações de métodos padrão ou variáveis ​​que serão comuns a todas as subclasses.

Obviamente, a questão da implementação de múltiplas interfaces também é sólida. Se você possui uma classe que implementa várias interfaces, pode usar um objeto dessa classe como tipos diferentes no mesmo aplicativo.

O fato de sua pergunta ser sobre PHP, no entanto, torna as coisas um pouco mais interessantes. Digitar nas interfaces ainda não é incrivelmente necessário no PHP, onde você pode praticamente alimentar qualquer coisa com qualquer método, independentemente do seu tipo. Você pode digitar estaticamente os parâmetros do método, mas alguns deles estão quebrados (String, acredito, causa alguns soluços). Junte isso ao fato de que você não pode digitar a maioria das outras referências e não há muito valor em tentar forçar a digitação estática no PHP ( neste momento ). E por isso, o valor das interfaces no PHP , neste momentoé muito menor do que em idiomas mais fortemente tipados. Eles têm o benefício da legibilidade, mas pouco mais. A implementação múltipla nem é benéfica, porque você ainda precisa declarar os métodos e fornecer a eles corpos dentro do implementador.

Brian Warshaw
fonte
2

Abaixo estão os pontos para a interface PHP

  1. É usado para definir nenhum dos métodos exigidos na classe [se você deseja carregar o html, o id e o nome são necessários, portanto, neste caso, a interface inclui setID e setName].
  2. A interface força estritamente a classe a incluir todos os métodos definidos nela.
  3. Você só pode definir o método na interface com acessibilidade pública.
  4. Você também pode estender a interface como classe. Você pode estender a interface no php usando extends keyword.
  5. Estenda a interface múltipla.
  6. Você não pode implementar 2 interfaces se ambas compartilharem a função com o mesmo nome. Irá gerar erro.

Código de exemplo:

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);
vivek s vamja
fonte
2

Vimos que classes e interfaces abstratas são semelhantes, pois fornecem métodos abstratos que devem ser implementados nas classes filho. No entanto, eles ainda têm as seguintes diferenças:

1.As interfaces podem incluir métodos e constantes abstratas, mas não podem conter métodos e variáveis ​​concretos.

2.Todos os métodos na interface devem estar no escopo de visibilidade pública .

3. Uma classe pode implementar mais de uma interface, enquanto pode herdar de apenas uma classe abstrata.

                                  interface                      abstract class
the code                     - abstract methods               - abstract methods
                             - constants                      - constants                  
                                                              - concrete methods
                                                              - concrete variables

access modifiers             
                             - public                         - public
                                                              - protected
                                                              - private
                                                                etc.
number of parents          The same class can implement
                           more than 1 interface              The child class can 
                                                              inherit only from 1 abstract class

Espero que isso ajude alguém a entender!

Hiren Gohel
fonte
2

As interfaces são como seus genes.

As aulas abstratas são como seus pais de verdade.

Seus propósitos são hereditários, mas no caso de classes abstratas versus interfaces, o que é herdado é mais específico.

Tapha
fonte
2

Eu não sei sobre outras línguas, qual é o conceito de interface lá. Mas para o PHP, tentarei o meu melhor para explicá-lo. Apenas seja paciente e, por favor, comente se isso ajudou.

Uma interface funciona como um "contrato", especificando o que um conjunto de subclasses faz, mas não como o faz.

A regra

  1. Uma interface não pode ser instanciada.

  2. Você não pode implementar nenhum método em uma interface, ou seja, ele contém apenas .assinatura do método, mas não detalhes (corpo).

  3. As interfaces podem conter métodos e / ou constantes, mas nenhum atributo. As constantes de interface têm as mesmas restrições que as constantes de classe. Os métodos de interface são implicitamente abstratos.

  4. As interfaces não devem declarar construtores ou destruidores, pois esses são detalhes de implementação no nível da classe.

  5. Todos os métodos em uma interface devem ter visibilidade pública.

Agora vamos dar um exemplo. Suponha que tenhamos dois brinquedos: um é um cachorro e o outro é um gato.

Como sabemos, um cão late e miadeiros. Esses dois têm o mesmo método de fala, mas com funcionalidade ou implementação diferente. Suponha que estamos dando ao usuário um controle remoto que possui um botão de falar.

Quando o usuário pressiona o botão falar, o brinquedo precisa falar, não importa se é cachorro ou gato.

Este é um bom caso para usar uma interface, não uma classe abstrata, porque as implementações são diferentes. Por quê? Lembrar

Se você precisar dar suporte às classes filho adicionando algum método não abstrato, use classes abstratas. Caso contrário, as interfaces seriam sua escolha.

Comunidade
fonte