Is there any decent work around to PHP's lack of Generics that allow static code inspection to detect type consistency?
I have an abstract class, that I want to sub-class and also enforce that one of the methods changes from taking a parameter of one type, to taking a parameter which is a sub-class of that parameter.
abstract class AbstractProcessor {
abstract function processItem(Item $item);
}
class WoodProcessor extends AbstractProcessor {
function processItem(WoodItem $item){}
}
This is not allowed in PHP because it's changing the methods signature which is not allowed. With Java style generics you could do something like:
abstract class AbstractProcessor<T> {
abstract function processItem(T $item);
}
class WoodProcessor extends AbstractProcessor<WoodItem> {
function processItem(WoodItem $item);
}
But obviously PHP doesn't support those.
Google for this problem, people suggest using instanceof to check errors at run-time e.g.
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");
}
}
}
But that only works at runtime, it doesn't allow you to inspect your code for errors using static analysis - so is there any sensible way of handling this in PHP?
A more complete example of the problem is:
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
}
}
Because I'm passing in just an Item to new ProcessedWoodItem($item) and it expects a WoodItem as the parameter, the code inspection suggests there is an error.