Чи є якась гідна робота щодо відсутності в програмі PHP відсутності Generics, що дозволяє статичному контролю коду виявити узгодженість типу?
У мене є абстрактний клас, який я хочу підклас, а також примусити, що один з методів змінюється від прийняття параметра одного типу до прийняття параметра, який є підкласом цього параметра.
abstract class AbstractProcessor {
abstract function processItem(Item $item);
}
class WoodProcessor extends AbstractProcessor {
function processItem(WoodItem $item){}
}
Це не дозволено в PHP, оскільки це змінює підпис методів, який заборонено. З дженериками стилю Java ви можете зробити щось на кшталт:
abstract class AbstractProcessor<T> {
abstract function processItem(T $item);
}
class WoodProcessor extends AbstractProcessor<WoodItem> {
function processItem(WoodItem $item);
}
Але очевидно, що PHP не підтримує їх.
Google для цієї проблеми люди пропонують використовувати instanceof
для перевірки помилок під час виконання, наприклад
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");
}
}
}
Але це працює лише під час виконання, це не дозволяє перевірити код на предмет помилок, використовуючи статичний аналіз - так чи є розумний спосіб поводження з цим у PHP?
Більш повний приклад проблеми:
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
}
}
Оскільки я переходжу лише Item
до new ProcessedWoodItem($item)
та, і він очікує WoodItem як параметр, перевірка коду дозволяє припуститись помилку.