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.
quelle
Antworten:
Sie können Methoden ohne Argumente verwenden und die Parameter stattdessen mit doc-Blöcken dokumentieren:
Ich werde nicht sagen, dass ich das für eine gute Idee halte.
Ihr Problem ist, dass Sie einen Kontext mit einer variablen Anzahl von Mitgliedern haben - anstatt zu versuchen, diese als Argumente durchzusetzen, ist es eine bessere und zukunftssicherere Idee, einen Kontexttyp einzuführen, der alle möglichen Argumente enthält, so dass das Argument Liste muss sich nie ändern.
Wie so:
Statische Factory-Methoden sind natürlich optional - könnten aber nützlich sein, wenn nur bestimmte bestimmte Kombinationen von Elementen einen aussagekräftigen Kontext ergeben. In diesem Fall möchten Sie möglicherweise auch
__construct()
als geschützt / privat deklarieren .quelle