Existe-t-il un travail décent autour du manque de PHP de génériques qui permettent l'inspection statique du code pour détecter la cohérence des types?
J'ai une classe abstraite, que je veux sous-classer et imposer également que l'une des méthodes passe de la prise d'un paramètre d'un type à la prise d'un paramètre qui est une sous-classe de ce paramètre.
abstract class AbstractProcessor {
abstract function processItem(Item $item);
}
class WoodProcessor extends AbstractProcessor {
function processItem(WoodItem $item){}
}
Ceci n'est pas autorisé en PHP car il modifie la signature des méthodes, ce qui n'est pas autorisé. Avec les génériques de style Java, vous pourriez faire quelque chose comme:
abstract class AbstractProcessor<T> {
abstract function processItem(T $item);
}
class WoodProcessor extends AbstractProcessor<WoodItem> {
function processItem(WoodItem $item);
}
Mais évidemment, PHP ne les prend pas en charge.
Google pour ce problème, les gens suggèrent d'utiliser instanceof
pour vérifier les erreurs au moment de l'exécution, par exemple
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");
}
}
}
Mais cela ne fonctionne qu'au moment de l'exécution, cela ne vous permet pas d'inspecter votre code à la recherche d'erreurs à l'aide de l'analyse statique - existe-t-il donc un moyen sensé de gérer cela en PHP?
Un exemple plus complet du problème est:
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
}
}
Parce que je passe juste un Item
to new ProcessedWoodItem($item)
et qu'il attend un WoodItem comme paramètre, l'inspection du code suggère qu'il y a une erreur.
la source
Réponses:
Vous pouvez utiliser des méthodes sans arguments, en documentant les paramètres avec des blocs doc à la place:
Je ne vais pas dire que je pense que c'est une bonne idée.
Votre problème est que vous avez un contexte avec un nombre variable de membres - plutôt que d'essayer de les forcer en tant qu'arguments, une idée meilleure et plus à l'épreuve du temps consiste à introduire un type de contexte pour transporter tous les arguments possibles, de sorte que l'argument la liste n'a jamais besoin de changer.
Ainsi:
Les méthodes de fabrique statique sont bien sûr facultatives - mais pourraient être utiles, si seulement certaines combinaisons spécifiques de membres produisent un contexte significatif. Si c'est le cas, vous pouvez également déclarer
__construct()
comme protégé / privé.la source