Apakah ada pekerjaan yang layak untuk kurangnya PHP Generics yang memungkinkan pemeriksaan kode statis untuk mendeteksi konsistensi jenis?
Saya memiliki kelas abstrak, yang ingin saya sub-kelas dan juga menegakkan bahwa salah satu metode berubah dari mengambil parameter dari satu jenis, untuk mengambil parameter yang merupakan sub-kelas dari parameter itu.
abstract class AbstractProcessor {
abstract function processItem(Item $item);
}
class WoodProcessor extends AbstractProcessor {
function processItem(WoodItem $item){}
}
Ini tidak diizinkan dalam PHP karena itu mengubah metode tanda tangan yang tidak diizinkan. Dengan generik gaya Java, Anda dapat melakukan sesuatu seperti:
abstract class AbstractProcessor<T> {
abstract function processItem(T $item);
}
class WoodProcessor extends AbstractProcessor<WoodItem> {
function processItem(WoodItem $item);
}
Tapi jelas PHP tidak mendukung itu.
Google untuk masalah ini, orang menyarankan menggunakan instanceof
untuk memeriksa kesalahan pada saat run-time misalnya
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");
}
}
}
Tapi itu hanya berfungsi saat runtime, itu tidak memungkinkan Anda untuk memeriksa kode Anda untuk kesalahan menggunakan analisis statis - jadi apakah ada cara yang masuk akal untuk menangani ini di PHP?
Contoh masalah yang lebih lengkap adalah:
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
}
}
Karena saya melewati hanya Item
ke new ProcessedWoodItem($item)
dan mengharapkan WoodItem sebagai parameter, pemeriksaan kode menunjukkan ada kesalahan.
sumber
Jawaban:
Anda dapat menggunakan metode tanpa argumen, mendokumentasikan parameter dengan blok-doc sebagai gantinya:
Saya tidak akan mengatakan saya pikir ini adalah ide yang bagus.
Masalah Anda adalah, Anda memiliki konteks dengan jumlah variabel anggota - alih-alih mencoba memaksa mereka sebagai argumen, ide yang lebih baik dan lebih banyak bukti di masa depan adalah memperkenalkan tipe konteks untuk membawa semua argumen yang mungkin, sehingga argumen daftar tidak perlu diubah.
Seperti itu:
Metode pabrik statis tentu saja opsional - tetapi bisa berguna, jika hanya kombinasi anggota tertentu yang menghasilkan konteks yang bermakna. Jika demikian, Anda mungkin ingin mendeklarasikan
__construct()
sebagai dilindungi / pribadi juga.sumber