Esiste un lavoro decente intorno alla mancanza di Generics di PHP che consente l'ispezione del codice statico per rilevare la coerenza del tipo?
Ho una classe astratta, che voglio sottoclasse e impone anche che uno dei metodi passi dal prendere un parametro di un tipo, a un parametro che è una sottoclasse di quel parametro.
abstract class AbstractProcessor {
abstract function processItem(Item $item);
}
class WoodProcessor extends AbstractProcessor {
function processItem(WoodItem $item){}
}
Questo non è permesso in PHP perché sta cambiando la firma dei metodi che non è consentita. Con i generici di stile Java puoi fare qualcosa di simile:
abstract class AbstractProcessor<T> {
abstract function processItem(T $item);
}
class WoodProcessor extends AbstractProcessor<WoodItem> {
function processItem(WoodItem $item);
}
Ma ovviamente PHP non supporta quelli.
Google per questo problema, le persone suggeriscono di utilizzare instanceof
per controllare gli errori in fase di esecuzione, ad es.
class WoodProcessor extends AbstractProcessor {
function processItem(Item $item){
if (!($item instanceof WoodItem)) {
throw new \InvalidArgumentException(
"item of class ".get_class($item)." is not a WoodItem");
}
}
}
Ma funziona solo in fase di runtime, non ti permette di ispezionare il tuo codice per errori usando l'analisi statica - quindi c'è un modo ragionevole di gestirlo in PHP?
Un esempio più completo del problema è:
class StoneItem extends Item{}
class WoodItem extends Item{}
class WoodProcessedItem extends ProcessedItem {
function __construct(WoodItem $woodItem){}
}
class StoneProcessedItem extends ProcessedItem{
function __construct(StoneItem $stoneItem){}
}
abstract class AbstractProcessor {
abstract function processItem(Item $item);
function processAndBoxItem(Box $box, Item $item) {
$processedItem = $this->processItem($item);
$box->insertItem($item);
}
//Lots of other functions that can call processItem
}
class WoodProcessor extends AbstractProcessor {
function processItem(Item $item) {
return new ProcessedWoodItem($item); //This has an inspection error
}
}
class StoneProcessor extends AbstractProcessor {
function processItem(Item $item) {
return new ProcessedStoneItem($item);//This has an inspection error
}
}
Poiché sto passando solo un Item
a new ProcessedWoodItem($item)
e si aspetta un WoodItem come parametro, l'ispezione del codice suggerisce che c'è un errore.