Vou partir do princípio de que se você chegou até aqui, já tem algum conhecimento em Orientação a Objetos, já esboçou as tuas primeiras classes, e já tem alguma experiência na criação de sistemas.

Interfaces são contratos.

Na minha ótica, o paradigma dos objetos, foi criado para resolver basicamente duas coisas: Padronização e Encapsulamento. Os outros problemas que OO também resolve, já possuiam soluções anteriores. [reutilização, organização…]

As interfaces existem por isso, para ajudar a defender o primeiro pilar.

Estou falando ‘por cima’, para simplificar e me focar no conceito que quero expor.

Imaginemos que nosso sistema faz um CRUD, e possui um módulo de Agenda, razoável, termos um model que seja parecido com isso:

<?php

class Agenda
{
	public function insere_agenda(){
		//implementação
	}
	public function atualiza_agenda(){
		//implementação
	}
	public function excluir_agenda(){
		//implementação
	}
}

Bacana.. Recebemos então uma solicitação que nos pede para criarmos outro ‘módulo’, para galerias de fotos. Novamente, vamos lá e fazemos:

<?php

class Galeria
{
	public function insere_galeria(){
		//implementação
	}
	//...
}

bem parecidos, porém diferentes nas implementações.

Nosso ‘controlador’, que usará os objetos instanciados apartir de Galeria, ou Agenda, sabe que precisa usar:

$galeria = new Galeria();
$galeria->insere_galeria();

ou

$agenda = new Agenda();
$agenda->insere_agenda();

Mas e se um outro programador, for dar continuidade nesse trabalho, é complicado ele ter a paciência de estudar todas as nossas classes, identificar o ‘padrão’ que usamos, e então implementar agora o módulo de ‘Notícias’… esse ‘outro programador’, pode até ser nós mesmos, daqui um tempo.

Evoluimos a cada ‘passagem de tempo’, impossível termos de cabeça todos os códigos, de todos os nossos projetos. Pode ser que não nos lembremos o que fizemos ‘lá atrás’.

Documentar é importante, mas um código bem escrito é ainda mais.

Assim que esse ‘novo programador’, for implementar o módulo de Notícias, ele terá que se perguntar: ‘E agora, oque preciso fazer?’.

Aqui é onde mora o perigo. Ele pode detonar ‘o nosso padrão’(que já estava errado), e fazer algo completamente bizzarro:

<?php
class Noticia
{
	public function cadastra(){}
	public function Muda(){}
	public function manda_pRo_liXo(){}
}

e ai ? a culpa não é só dele.

O nosso sistema por si só, não ‘deixava claro’, como as coisas deveriam ser, ou seja, não implementamos direito um dos pilares do OO.

É aqui que entram as interfaces. A forma de pensar tem que mudar.

Afinal, Galeria::insere_galeria();, Agenda::insere_agenda(), e Noticia::cadastra();, não são ‘semelhantes entre si’ ?

Queremos que os próximos a programarem no nosso sistema, saibam o que devem fazer, e ‘como devem fazer’. Podemos então, obrigar que os próximos depois da gente, sejam mais consistentes.

interface iModel
	{
		public function insert();
		public function update();
		public function delete();
	}

A nomenclatura já está bem melhor também.

Pessoalmente, não vejo sentido no insere_blablabla(); mas coloquei ali, pq vejo muito disso por ai.

Então, daqui para frente, nossas classes precisam apenas implementar essa interface.

Isso mesmo implementar. A interface define apenas a assinatura dos nossos métodos. A implementação fica a cargo de cada classe em específico.

Aqui então, vemos surgir o conceito de ‘poliformismo’. Coisas iguais com comportamentos diferentes, ou coisas diferentes com comportamentos iguais.

Mas como isso é pano para manga, voltemos as nossas interfaces, que não são nada mais do que: ‘coisas’ que vemos, que nos permitem trabalhar com elas. A beleza da programação, está em não precisarmos saber como os métodos foram/serão implementados, porém podemos usá-los, acreditando que eles cumpram o papel para o qual foram designados.

Não raramente fazemos isso. Posso dizer que toda vez que você usa uma função nativa da linguagem, vc está acreditando que ela faz oque vc precisa, sem saber exatamente como ela faz.

Nossas classes agora são assim:

class Agenda implements iModel
	{

	}
	class Galeria implements iModel
	{

	}

Todas irão implementar a nossa interface, e por isso, precisam obrigatoriamente fazer isso corretamente, se não, alguns erros serão lançados:

Fatal error: Class Agenda contains 3 abstract methods and must therefore be declared abstract or implement the remaining methods (iModel::insert, iModel::update, iModel::delete) in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\index.php on line 17

Somos obrigados a:

class Agenda implements iModel
	{
		public function insert(){
			//implementação
		}
		public function update(){
			//implementação
		}
		public function delete(){
			//implementação
		}
	}

E o mesmo para todas as classes que implementarem essa interface.

O nosso ‘novo programador’, que vai criar lá, o módulo de Notícias, agora, apenas precisa ler a iModel, e implementar a class Noticia, com base nessa interface.

Se nosso chefe chegar agora, pedir um módulo de ‘Artigos’, então sabemos por onde começar, e temos algo para nos basear. Tá lindo até aqui, mas não para por ai.

É ainda mais poderoso que isso. O php apesar de ser ‘de tipagem fraca’, nos dá um suporte muito importante a typehinting. Nossas models, usarão um banco de dados(ou não), mas não são, ‘o banco’ em si.

Por isso que não faz sentido, que nossas models, herdem coisas de uma class Db.

Se é para usar, vamos usar:

interface iModel
	{
		public function insert( iDb $db );
		public function update( iDb $db );
		public function delete( iDb $db );
	}

Agora, outro erro foi disparado:

Fatal error: Declaration of Agenda::insert() must be compatible with that of iModel::insert() in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\index.php on line 14

Basta adequarmos nossas classes, a essa nova realidade.

public function insert( iDb $db ){}

Okay, mas e oque isso quer dizer?

Que os nossos métodos: esperam receber um objeto ‘iDb’. E quem é esse iDb ?

[conheço pdo, tente por favor extrair o conceito, e não apenas a implementação que estou expondo].

interface iDb
	{
		public function query();
	}
	class MySql implements iDb
	{
		public function query();
	}
	class PostGre implements iDb()
	{
		public function query();
	}

Usamos para o banco MySQL dessa forma:

$db = new MySql();
	$galeria = new Galeria();

	$galeria->insert( $db );

Como também poderiamos usar com a nossa class para o banco de dados Postgre:

$db = new PostGre();

Ou seja, ganhamos uma flexibilidade aqui.

Ambos, tanto postgre, qnto mysql, possuem em comum a interface iDb. Por isso, que os métodos da class Galeria, que esperam receber um objeto iDb, aceita tanto instancias de PostGre, qnto de MySql.

Mas não podemos, fazer:

class Storage
	{
		public function query(){}
	}
	$db = new Storage();
	$galeria = new Galeria();
	$galeria->insert( $db );//mandando um objeto Storage, que não implementa iDb

Será lançado um erro. Afinal, o método iModel::insert() espera receber um iDb, e não foi isso que mandamos para ele.

Nossas classes especificas, assinaram os contratos com as interfaces.

Na prática, temos a garantia de que podemos usar os métodos insert(), update() e delete, com exatamente esses nomes, e passando um objeto iDb, que sabemos que podemos usar o método query();

public function insert( iDb $db )
		{
			$sql = "INSERT INTO ...";
			return $db->query( $sql );
		}

Essa consistência é importante. Não importa se é MySQL, Postgre, SQL Server.. todos implementando iDb, temos a garantia de que o método query() existe, e pode ser usado.

Quando usar Abstract, e quando usar interface, é uma outra discussão.

Coloquei a forma com que vejo, com base em tudo o que já estudei, pesquisei e li. É isso, comentem a vontade, por favor. Me ajudará a saber sobre oque devo escrever.

Dissertar por aqui, é uma rica fonte de aprendizado para mim também. Bons estudos a todos nós.