Gibt es eine anständige Lösung für das Fehlen von Generika in PHP, die eine statische Codeprüfung ermöglichen, um die Typkonsistenz festzustellen?
Ich habe eine abstrakte Klasse, die ich unterordnen möchte, und erzwinge auch, dass sich eine der Methoden von der Verwendung eines Parameters eines Typs zur Verwendung eines Parameters ändert, der eine Unterklasse dieses Parameters ist.
abstract class AbstractProcessor {
abstract function processItem(Item $item);
}
class WoodProcessor extends AbstractProcessor {
function processItem(WoodItem $item){}
}
Dies ist in PHP nicht zulässig, da die Methodensignatur geändert wird, was nicht zulässig ist. Mit Generika im Java-Stil können Sie Folgendes tun:
abstract class AbstractProcessor<T> {
abstract function processItem(T $item);
}
class WoodProcessor extends AbstractProcessor<WoodItem> {
function processItem(WoodItem $item);
}
Aber offensichtlich unterstützt PHP diese nicht.
Google für dieses Problem schlagen die Leute vor instanceof
, Fehler zur Laufzeit zu überprüfen, z
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");
}
}
}
Dies funktioniert jedoch nur zur Laufzeit. Sie können Ihren Code nicht mithilfe einer statischen Analyse auf Fehler untersuchen. Gibt es also eine sinnvolle Möglichkeit, dies in PHP zu handhaben?
Ein vollständigeres Beispiel für das Problem ist:
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
}
}
Da ich nur ein Item
to übergebe new ProcessedWoodItem($item)
und ein WoodItem als Parameter erwartet, deutet die Codeüberprüfung darauf hin, dass ein Fehler vorliegt.