Generics सिर्फ एक ट्रेंड नहीं, बल्कि एक ज़रूरत क्यों है?
\n\nअगर आपने कभी PHP में ऐसा कोड लिखा है जो कलेक्शन, रिपॉजिटरी या सर्विस लेयर के साथ काम करता है, तो आपने शायद यह स्थिति देखी होगी: फंक्शन array लेता है, लेकिन अंदर क्या है — यह एक रहस्य है। हो सकता है उसमें यूज़र हों, या बिल्लियाँ। या इससे भी बुरा — दोनों ही। यहाँ पर Generics (जेनेरिक्स) काम आते हैं — टाइपिज़ेशन का एक शक्तिशाली टूल जो आपके कोड को पूर्वानुमानित, सुरक्षित और स्वयं-दस्तावेजीकरण बनाता है।
इस लेख में हम जानेंगे कि PHP में generics कैसे काम करते हैं, इनकी ज़रूरत क्यों है, और रियल प्रोजेक्ट्स में इनका उपयोग कैसे करें। आप सामान्य गलतियों से बचना और अपने कोड को प्रोफेशनल बनाना सीखेंगे। चलिए शुरू करते हैं!
\n\nGenerics को सरल शब्दों में समझें
\n\nमान लीजिए आप एक ऑनलाइन स्टोर के डेवलपर हैं। आपके पास Cart नाम का एक क्लास है जो प्रोडक्ट्स को स्टोर करता है। Generics के बिना आप ऐसा लिखेंगे:
class Cart {\n private array $items;\n \n public function addItem($item): void {\n $this->items[] = $item;\n }\n \n public function getItems(): array {\n return $this->items;\n }\n}\n\nसमस्या? $item कुछ भी हो सकता है — नंबर, स्ट्रिंग, Product ऑब्जेक्ट या null भी। IDE यह नहीं बताएगा कि getItems() से कौन सा टाइप रिटर्न हो रहा है। आपको डॉक्यूमेंटेशन देखनी पड़ेगी या डीबग करना पड़ेगा।
Generics इस समस्या को हल करते हैं। वे आपको यह बताने की अनुमति देते हैं: "अरे, यह क्लास सिर्फ प्रोडक्ट्स के साथ काम करता है!"। यह ऐसा दिखता है:
\n\nclass Cart {\n /** @param Product[] $items */\n private array $items;\n \n public function addItem(Product $item): void {\n $this->items[] = $item;\n }\n \n /** @return Product[] */\n public function getItems(): array {\n return $this->items;\n }\n}\n\nलेकिन यह सिर्फ एक नकल है। PHP में असली generics PHP 8.0 से आए, और पूर्ण समर्थन PHP 8.1+ में एट्रीब्यूट्स और स्टैटिक एनालिसिस (जैसे PHPStan या Psalm) के साथ मिला।
\n\nPHP में Generics वास्तव में कैसे काम करते हैं?
\n\nJava या C# के विपरीत, PHP में अभी तक सिंटैक्स स्तर पर generics का मूल समर्थन नहीं है। हालांकि, PHPDoc एनोटेशन और स्टैटिक एनालिसिस टूल्स की मदद से हम टाइपिज़ेशन के सभी लाभ प्राप्त कर सकते हैं।
\n\nटेम्पलेट टाइप्स (Template Types)
\n\nसबसे लोकप्रिय तरीका PHPDoc में @template का उपयोग करना है। कलेक्शन के साथ एक उदाहरण देखें:
/**\n * @template T\n */\nclass Collection {\n /** @var array<int, T> */\n private array $items = [];\n \n /**\n * @param T $item\n */\n public function add(mixed $item): void {\n $this->items[] = $item;\n }\n \n /**\n * @return T\n */\n public function get(int $index): mixed {\n return $this->items[$index] ?? throw new \\OutOfBoundsException();\n }\n}\n\nअब इस क्लास का उपयोग करते समय आप विशिष्ट टाइप निर्दिष्ट करते हैं:
\n\n/** @var Collection<User> $userCollection */\n$userCollection = new Collection();\n$userCollection->add(new User('Alice'));\n$user = $userCollection->get(0); // PHPStan जानता है: $user एक User है\necho $user->name; // सुरक्षित!\n\nGenerics के लिए सीमाएँ (Constraints)
\n\nकभी-कभी आप चाहते हैं कि T टाइप कोई भी न हो, बल्कि एक निश्चित इंटरफ़ेस को लागू करे। इसे bound (सीमा) कहते हैं:
\n\n/**\n * @template T of \\JsonSerializable\n */\nclass JsonCollection {\n /** @var array<int, T> */\n private array $items = [];\n \n public function toJson(): string {\n return json_encode($this->items);\n }\n}\n\nअब आप कलेक्शन में वह ऑब्जेक्ट नहीं जोड़ सकते जो JsonSerializable को लागू नहीं करता। IDE और स्टैटिक एनालाइज़र एरर दिखाएँगे।