हर एक के समझौतों को जानकर सही डिज़ाइन औज़ार चुनें - एक अनुबंध, एक एल्गोरिदम का ढाँचा, या क्षैतिज पुनः प्रयोग।
इस पाठ को Kodokon में खोलेंPHP आपको चार डिज़ाइन औज़ार देती है जो आंशिक रूप से एक-दूसरे से जुड़ते हैं: कंक्रीट वंशानुक्रम, एब्स्ट्रैक्ट क्लास, इंटरफ़ेस और ट्रेट। चुनाव एक ही प्रश्न पर आकर टिकता है: आप क्या साझा करना चाहते हैं? एक अनुबंध: इंटरफ़ेस। एक अनुबंध और साथ में एक कार्यान्वयन का ढाँचा: एब्स्ट्रैक्ट क्लास। बिना किसी पदानुक्रमिक संबंध वाली क्लासों के बीच साझा कोड: ट्रेट। जहाँ तक कंक्रीट वंशानुक्रम की बात है, इसे सही ठहराना उत्तरोत्तर कठिन होता जा रहा है: यह कसकर युग्मित करता है, और PHP केवल एक ही पैरेंट की अनुमति देती है।
<?php
declare(strict_types=1);
abstract class Exporter
{
public function export(array $rows): string
{
return $this->head() . $this->body($rows);
}
abstract protected function head(): string;
abstract protected function body(
array $rows
): string;
}
final class CsvExporter extends Exporter
{
protected function head(): string
{
return "id;name\n";
}
protected function body(array $rows): string
{
$lines = array_map(
fn (array $r): string => implode(';', $r),
$rows,
);
return implode("\n", $lines);
}
}
$csv = new CsvExporter();
echo $csv->export([[1, 'Ada'], [2, 'Linus']]);इंटरफ़ेस शुद्ध अनुबंध है: सिग्नेचर और कॉन्स्टेंट, न कोई स्थिति और न कोई कार्यान्वयन। एब्स्ट्रैक्ट क्लास पर इसका निर्णायक लाभ: एक क्लास इनमें से कई को कार्यान्वित कर सकती है, और कोई भी मौजूदा क्लास बाद में भी अनुबंध को अपना सकती है। इसके विपरीत, एब्स्ट्रैक्ट क्लास स्थिति और साझा कोड साथ रखती है, पर आपका इकलौता वंशानुक्रम स्लॉट खर्च कर देती है। व्यवहार में: अपने पैरामीटर का टाइप इंटरफ़ेस से रखें (Cache, न कि ArrayCache) ताकि आप कार्यान्वयन बदल सकें, परीक्षणों में भी और उत्पादन में भी।
<?php
declare(strict_types=1);
interface Cache
{
public function get(string $key): ?string;
public function set(
string $key,
string $value
): void;
}
final class ArrayCache implements Cache
{
private array $items = [];
public function get(string $key): ?string
{
return $this->items[$key] ?? null;
}
public function set(
string $key,
string $value
): void {
$this->items[$key] = $value;
}
}
$cache = new ArrayCache();
$cache->set('lang', 'PHP');
echo $cache->get('lang');ट्रेट क्षैतिज साझाकरण की समस्या हल करते हैं: बिना किसी साझा पूर्वज वाली क्लासों में वही मेथड इंजेक्ट करना। जब दो ट्रेट एक ही नाम का मेथड प्रदान करते हैं, तो PHP आपके लिए चुनाव करने से इनकार कर देती है और एक स्पष्ट समाधान की माँग करती है: insteadof उस संस्करण को नामित करता है जिसे रखना है, और as एक उपनाम बनाता है ताकि दूसरा भी सुलभ बना रहे। यह जान-बूझकर वाचाल है - विरोध कोड में दिखता रहना चाहिए।
<?php
declare(strict_types=1);
trait FileLogger
{
public function log(string $message): void
{
echo "[file] $message\n";
}
}
trait AuditLogger
{
public function log(string $message): void
{
echo "[audit] $message\n";
}
}
final class PaymentService
{
use FileLogger, AuditLogger {
FileLogger::log insteadof AuditLogger;
AuditLogger::log as audit;
}
}
$service = new PaymentService();
$service->log('Payment received');
$service->audit('Payment received');log() मेथड घोषित करता है। क्या होता है?insteadof से स्पष्ट रूप से समाधान न किया जाए