W3docs

insteadof

La parola chiave "insteadof" in PHP specifica quale trait usare al posto di un altro per un dato metodo. In questo articolo esploriamo il suo utilizzo.

La parola chiave PHP insteadof

insteadof è una parola chiave PHP utilizzata all'interno di un blocco use per risolvere un conflitto di metodi tra due o più trait. Quando una classe utilizza più trait che definiscono ciascuno un metodo con lo stesso nome, PHP non può decidere quale sia il vincitore e genera un errore fatale. insteadof indica a PHP quale metodo del trait mantenere e quale scartare.

Questa pagina spiega il conflitto che risolve, la sua sintassi esatta, come si abbina alla parola chiave as per conservare il metodo "perdente" e i problemi noti da tenere a mente.

Il problema che insteadof risolve

Un trait è un blocco riutilizzabile di metodi che viene copiato in una classe in fase di compilazione. Se due trait definiscono un metodo con lo stesso nome e una classe li usa entrambi, PHP non ha modo di sceglierne uno. Il risultato è un errore fatale di collisione:

<?php

trait FileLogger {
  function log() { echo "Writing to a file."; }
}
trait DatabaseLogger {
  function log() { echo "Writing to the database."; }
}

class Service {
  use FileLogger, DatabaseLogger; // No conflict resolution
}

// PHP Fatal error: Trait method DatabaseLogger::log has not been
// applied as Service::log, because of collision with FileLogger::log

La classe non viene nemmeno creata — si tratta di un errore in fase di compilazione, non di esecuzione. insteadof è il modo per indicare a PHP quale metodo applicare.

Sintassi

insteadof viene scritto all'interno del blocco tra parentesi graffe di un'istruzione use:

use TraitWeKeep, TraitWeDrop {
    TraitWeKeep::methodName insteadof TraitWeDrop;
}

Si legge come: "usa il methodName di TraitWeKeep al posto di quello di TraitWeDrop." Il trait indicato dopo insteadof ha la propria versione del metodo rimossa dalla classe.

<?php

trait FileLogger {
  function log() { echo "Writing to a file."; }
}
trait DatabaseLogger {
  function log() { echo "Writing to the database."; }
}

class Service {
  use FileLogger, DatabaseLogger {
    FileLogger::log insteadof DatabaseLogger;
  }
}

$service = new Service();
$service->log();
// Output: Writing to a file.

Risoluzione con più di due trait

Se tre o più trait entrano in conflitto, elenca tutti i trait da escludere dopo insteadof, separati da virgole:

<?php

trait Json    { function format() { echo "JSON output"; } }
trait Xml      { function format() { echo "XML output"; } }
trait Csv      { function format() { echo "CSV output"; } }

class Report {
  use Json, Xml, Csv {
    Json::format insteadof Xml, Csv;
  }
}

$report = new Report();
$report->format();
// Output: JSON output

Mantenere l'altro metodo con as

insteadof scarta un metodo — ma spesso non vuoi perderlo, vuoi solo averlo con un nome diverso in modo che entrambi siano disponibili. È questo che fa la parola chiave as: assegna un alias al metodo escluso con un nuovo nome, così sopravvive alla risoluzione del conflitto.

<?php

trait FileLogger {
  function log($msg) { return "[file] $msg"; }
}
trait DatabaseLogger {
  function log($msg) { return "[db] $msg"; }
}

class Service {
  use FileLogger, DatabaseLogger {
    FileLogger::log insteadof DatabaseLogger;  // FileLogger::log becomes log()
    DatabaseLogger::log as logToDb;            // DatabaseLogger::log survives as logToDb()
  }
}

$service = new Service();
echo $service->log("started"), "\n";      // [file] started
echo $service->logToDb("started"), "\n";  // [db] started

insteadof e as vengono quasi sempre usati insieme: insteadof sceglie il vincitore, as salva il perdente con un alias. La parola chiave as può anche modificare la visibilità di un metodo (ad esempio FileLogger::log as protected;).

Problemi noti

  • insteadof risolve solo i conflitti di nomi. Se i due metodi non condividono lo stesso nome, non c'è alcun conflitto e insteadof non è necessario.
  • Devi fare riferimento a un metodo che esiste effettivamente nel trait indicato, usando la sintassi Trait::method. Un errore di digitazione produce un errore fatale.
  • Non unisce i comportamenti. Il metodo escluso semplicemente non viene applicato; insteadof non chiama mai entrambi i metodi.
  • Un metodo di una classe figlia ha comunque la precedenza su un trait. L'ordine di risoluzione dei metodi è: i metodi definiti nella classe stessa sovrascrivono i metodi dei trait, e i metodi dei trait sovrascrivono i metodi ereditati (dalla classe padre).

Quando usarlo

Ricorri a insteadof ogni volta che componi una classe da più trait e due di essi espongono lo stesso nome di metodo — situazione comune quando si combinano trait di terze parti che non puoi controllare. Combinato con as, ti permette di comporre comportamenti da trait indipendenti senza rinominare il loro codice sorgente, mantenendo le tue classi modulari e prive di conflitti.

Esercitazione

Pratica
Cosa fa la parola chiave 'insteadof' in PHP?
Cosa fa la parola chiave 'insteadof' in PHP?
Was this page helpful?