¿Existe algún trabajo decente en torno a la falta de genéricos de PHP que permitan la inspección de código estático para detectar la consistencia de tipo?
Tengo una clase abstracta, que quiero subclasificar y también imponer que uno de los métodos cambie de tomar un parámetro de un tipo, a tomar un parámetro que es una subclase de ese parámetro.
abstract class AbstractProcessor {
abstract function processItem(Item $item);
}
class WoodProcessor extends AbstractProcessor {
function processItem(WoodItem $item){}
}
Esto no está permitido en PHP porque está cambiando la firma de métodos que no está permitido. Con los genéricos de estilo Java podrías hacer algo como:
abstract class AbstractProcessor<T> {
abstract function processItem(T $item);
}
class WoodProcessor extends AbstractProcessor<WoodItem> {
function processItem(WoodItem $item);
}
Pero obviamente PHP no los admite.
Google para este problema, la gente sugiere usar instanceof
para verificar errores en tiempo de ejecución, por ejemplo
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");
}
}
}
Pero eso solo funciona en tiempo de ejecución, no le permite inspeccionar su código en busca de errores utilizando análisis estático, entonces, ¿hay alguna forma sensata de manejar esto en PHP?
Un ejemplo más completo del problema es:
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
}
}
Debido a que paso solo un Item
to new ProcessedWoodItem($item)
y espera un WoodItem como parámetro, la inspección del código sugiere que hay un error.