Applicazione delle interfacce in OOP in PHP

Quindi, abbiamo già stabilito che le interfacce sono un buon modo per controllare che tutti i metodi necessari della classe siano implementati.

Consideriamo un altro esempio, più pratico. Supponiamo di avere una classe che memorizzerà un array di oggetti-figura:

FiguresCollection.php<?php
  class FiguresCollection
  {
    private $figures = []; // array per le figure
  }
?>

Implementiamo nel nostro classe il metodo addFigure per aggiungere oggetti alla collezione:

FiguresCollection.php<?php
  class FiguresCollection
  {
    private $figures = [];
    
    // L'oggetto con la figura viene passato come parametro:
    public function addFigure($figure)
    {
      $this->figures[] = $figure;
    }
  }
?>

È ovvio che contiamo sul fatto che al parametro del metodo addFigure venga passato un oggetto con una figura. Tuttavia non c'è nessun controllo su questo!

Usiamo un'indicazione di tipo e indichiamo esplicitamente il tipo degli oggetti come Figure:

FiguresCollection.php<?php
  class FiguresCollection
  {
    private $figures = [];
    
    public function addFigure(Figure $figure)
    {
      $this->figures[] = $figure;
    }
  }
?>

Analizziamo cosa abbiamo fatto.

Se Figure fosse una classe realmente esistente, allora potremmo passare al parametro del metodo oggetti di questa classe, e anche dei suoi discendenti.

Tuttavia, nel nostro caso Figure è un'interfaccia. In questo caso, l'indicazione significa che al parametro del metodo possono essere passati solo oggetti di classi che implementano la nostra interfaccia.

Proviamo a creare un oggetto della nostra classe e ad aggiungervi delle figure:

index.php<?php
  $figuresCollection = new FiguresCollection;
  
  // Aggiungiamo un paio di quadrati:
  $figuresCollection->add(new Quadrate(2));
  $figuresCollection->add(new Quadrate(3));
  
  // Aggiungiamo un paio di rettangoli:
  $figuresCollection->add(new Rectangle(2, 3));
  $figuresCollection->add(new Rectangle(3, 4));
?>

Il tentativo di aggiungere un oggetto di qualsiasi altra classe porterà a un errore:

index.php<?php
  $figuresCollection = new FiguresCollection;
  
  class Test {}; // qualche altra classe
  $figuresCollection->add(new Test); // darà un errore
?>

Cosa ci dà nella pratica questo controllo: poiché tutte le figure aggiunte alla collezione implementano l'interfaccia Figure, possiamo essere sicuri che ognuna di esse avrà il metodo getSquare e il metodo getPerimeter.

In futuro, forse, oltre al quadrato e al rettangolo apparirà, ad esempio, anche un triangolo. In questo caso anche il triangolo avrà i metodi getSquare e getPerimeter.

Nella pratica questo ci dà quanto segue: possiamo nella classe FiguresCollection creare, ad esempio, il metodo getTotalSquare, che trova l'area totale delle figure della collezione. In questo metodo scorreremo in ciclo l'array delle figure e per ogni figura chiameremo il metodo getSquare.

Poiché ogni figura implementa l'interfaccia Figure, possiamo essere al 100% sicuri che ogni figura avrà questo metodo getSquare.

Quindi, ecco l'implementazione del metodo:

php<?php
  class FiguresCollection
  {
    private $figures = [];
    
    public function addFigure(Figure $figure)
    {
      $this->figures[] = $figure;
    }
    
    // Troviamo l'area totale:
    public function getTotalSquare()
    {
      $sum = 0;
      
      foreach ($this->figures as $figure) {
        $sum += $figure->getSquare(); // usiamo il metodo getSquare
      }
      
      return $sum;
    }
  }
?>
Задание 1

Senza sbirciare nel mio codice, implementate la stessa classe FiguresCollection.

Задание 2

Aggiungete alla classe FiguresCollection il metodo getTotalPerimeter per trovare il perimetro totale di tutte le figure.