Skip to content

6. As interfaces

Uma interface é uma estrutura que define protótipos de métodos. Uma classe que implementa uma interface deve definir o código de todos os métodos da interface.

6.1. A árvore de scripts

Image

6.2. Uma primeira interface

Definimos uma interface [IExemple] num script [IExemple.php]. Neste mesmo script, definimos duas classes que implementam a interface [IExemple]:


<?php

// respeito rigoroso dos tipos dos parâmetros das funções
declare(strict_types=1);

// espaço de nomes
namespace Exemples;

// uma interface
interface IExemple {
    // os métodos da interface
    public function ajouter(int $i, int $j): int;
    public function soustraire(int $i, int $j): int;
}

// implementação 1 da interface IExemple
class Classe1 implements IExemple {
    public function ajouter(int $a, int $b): int {
        return $a + $b + 10;
    }

    public function soustraire(int $a, int $b): int {
        return $a - $b + 20;
    }

}

// implementação 2 da interface IExemple
class Classe2 implements IExemple {
    public function ajouter(int $a, int $b) : int{
        return $a + $b + 100;
    }

    public function soustraire(int $a, int $b) : int {
        return $a - $b + 200;
    }

}

Comentários

  • linhas 10-14: a interface IExemple define dois métodos: a função ajouter (linha 12) e a função soustraire (linha 13). A interface não define o código destes métodos. São as classes que implementam a interface que o farão;
  • linha 17: a classe Classe1 implementa a interface IExemple. Por conseguinte, define um código para os métodos ajouter (linha 18) e soustraire (linha 22);
  • linhas 29-38: o mesmo se aplica à classe Classe2;

Utilizamos a interface [IExemple] no seguinte script [interfaces-01.php]:


<?php

require_once "IExemple.php";
use \Exemples\Classe1;
use \Exemples\Classe2;
use \Exemples\IExemple;

// função
function calculer(int $a, int $b, IExemple $interface) : void {
  print $interface->ajouter($a, $b)."\n";
  print $interface->soustraire($a, $b)."\n";
}

// ------------------- main
// criação de 2 objetos do tipo Classe1 e Classe2
$c1 = new Classe1();
$c2 = new Classe2();
// chamada da função «calcular»
calculer(4, 3, $c1);
calculer(14, 13, $c2);

Comentários

  • linhas 3-6: inclusão e definição das classes e interfaces utilizadas pelo script;
  • linha 3: em vez da instrução «include», utilizámos aqui a instrução «require_once». A instrução «include» inclui um ficheiro no script atual, mesmo que este já tenha sido incluído, enquanto a instrução «require_once» só o inclui uma vez. Por isso, no que diz respeito à inclusão de código, é preferível utilizar a instrução «require_once»;
  • linhas 9-12: define-se uma função;
  • linha 9: declaramos aqui o tipo dos três parâmetros. Se, durante a execução, o parâmetro efetivo não for do tipo esperado, é lançado um erro. O terceiro parâmetro é do tipo [IExemple]. Isto significa que o parâmetro efetivo deve ser uma instância de uma classe que implemente a interface [IExemple]; portanto, no nosso exemplo, uma instância das classes [Classe1] ou [Classe2];
  • linhas 10-11: utilizamos os métodos [ajouter, soustraire] da interface [IExemple];
  • linha 19: o terceiro parâmetro efetivo é do tipo [Classe1], compatível com o tipo [IExemple] do terceiro parâmetro formal da função;
  • linha 20: o mesmo se aplica à classe [Classe2];

Resultados

1
2
3
4
17
21
127
201

6.3. Derivação de uma interface

Da mesma forma que uma classe filha pode herdar de uma classe pai, uma interface filha pode herdar de uma interface pai.

Consideremos a interface [IExemple2] definida no ficheiro [IExemple2.php]:


<?php

// respeito rigoroso pelos tipos dos parâmetros das funções
declare(strict_types=1);
// espaço de nomes
namespace Exemples;

// inclusão da definição da interface IExemple
require_once __DIR__."/IExemple.php";

// uma interface que deriva de IExemple
interface IExemple2 extends IExemple {
    // o método da interface
    public function multiplier(int $i, int $j): int;
}

// implementação da interface IExemple2
class Classe3 extends Classe2 implements IExemple2 {
   
    public function multiplier(int $a, int $b): int {
        return $a * $b;
    }

}

Comentários

  • linha 6: a interface [IExemple2] estará no mesmo espaço de nomes que a interface [Iexemple];
  • linha 9: inclui-se o ficheiro de definição da interface [Iexemple];
  • linhas 12-15: definem a interface [IExemple2], que estende (herda) a interface [Iexemple] e lhe adiciona um novo método (linha 14);
  • linhas 18-24: a classe [Classe3] estende a classe [Classe2]. Como esta implementa a interface [IExemple], o mesmo se aplica à classe [Classe3]. Com efeito, a [Classe3] herda todos os métodos públicos e protegidos da classe [Classe2], incluindo, portanto, os métodos «adicionar» e «subtrair». Além disso, indica-se que a classe [Classe3] implementa a interface [IExemple2]. Nessa qualidade, deve também implementar o método «multiplicar», o que a classe [Classe2] não faz. É isso que as linhas 20-22 fazem;

A interface [IExemple2] é utilizada pelo seguinte script [interfaces-02]:


<?php

// respeito rigoroso pelos tipos dos parâmetros das funções
declare(strict_types=1);

// inclusão e qualificações das classes e interfaces necessárias ao script
require_once __DIR__."/Iexemple2.php";
use \Exemples\IExemple2;
use \Exemples\Classe3;

// função
function calculer(int $a, int $b, IExemple2 $interface) {
    print $interface->ajouter($a, $b) . "\n";
    print $interface->soustraire($a, $b) . "\n";
    print $interface->multiplier($a, $b) . "\n";
}

// ------------------- main
// criação de 1 objeto do tipo Classe3 que implementa IExemple2
$c3 = new Classe3();
// chamada à função «calcular»
calculer(4, 3, $c3);

Comentários

  • linha 12: o terceiro parâmetro da função [calculer] é do tipo [IExemple2];
  • linhas 13-15: utilizam-se os três métodos da interface [IExemple2];
  • linha 22: chama-se a função [calculer] com, como terceiro parâmetro, um objeto do tipo [IExemple2] (linha 20);

Resultados

1
2
3
107
201
12

6.4. Passagem de uma interface como parâmetro de uma função

Vimos no parágrafo anterior que, quando o tipo esperado para um parâmetro de função é uma classe, o parâmetro efetivo pode ser um objeto do tipo esperado ou derivado. O mesmo se aplica às interfaces, como mostra o seguinte script [interfaces-03.php]:


<?php

// respeito rigoroso pelos tipos dos parâmetros das funções
declare(strict_types=1);

// inclusão e qualificações das classes e interfaces necessárias ao script
require_once __DIR__."/IExemple.php";
use \Exemples\IExemple;
require_once __DIR__."/IExemple2.php";
use \Exemples\Classe3;

// função
function calculer(int $a, int $b, IExemple $interface) {
  print $interface->ajouter($a, $b) . "\n";
  print $interface->soustraire($a, $b) . "\n";
}

// ------------------- main
// criação de 1 objeto do tipo Classe3 que implementa IExemple2 e, portanto, IExemple
$c3 = new Classe3();
// chamada à função «calcular»
calculer(4, 3, $c3);

Comentários

  • na linha 13, a função [calculer] espera, como terceiro parâmetro, um tipo [IExemple]. Isto significa que o tipo do parâmetro efetivo poderá ser do tipo [IExemple] ou derivado;
  • linha 20: instanciamos um objeto $c3 do tipo [Classe3], classe que implementa a interface [IExemple2], que por sua vez estende a interface [IExemple]. Portanto, em última análise, $c3 implementa a interface [IExemple];
  • linha 22: chama-se a função [calculer] com, como terceiro parâmetro, um objeto $c3 do tipo [Classe3]. Através da herança de classes e das implementações, verificámos que o objeto $c3 implementava o tipo [IExemple]. Por isso, podemos utilizá-lo como terceiro parâmetro;

Resultados

107
201