หลักการ SOLID ในการใช้งานจริง
ประยุกต์ใช้หลักการ SOLID ทั้งห้าข้อกับคลาส PHP จริง
หลักการ SOLID ในการใช้งานจริง เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงใช้ SOLID
SOLID คือหลักการออกแบบห้าข้อที่ช่วยให้ PHP เชิงวัตถุ ยืดหยุ่น ทดสอบได้ และไม่เสื่อมสภาพง่าย หลักการเหล่านี้ไม่ใช่กฎที่ต้องทำตามอย่าง盲目 แต่เป็นแนวทางที่ช่วยลดการเชื่อมโยงระหว่างส่วนต่าง ๆ และทำให้ความรับผิดชอบชัดเจนขึ้น ในบทเรียนนี้ เราจะนำแต่ละหลักการไปใช้กับคลาส PHP ที่สามารถนำไปใช้งานจริงได้
- Sความรับผิดชอบเดียว
- Oเปิดเพื่อขยาย ปิดเพื่อแก้ไข
- Lการแทนที่ของ Liskov
- Iการแยกส่วนอินเทอร์เฟซ
- Dการกลับทิศทางการพึ่งพา
ความรับผิดชอบเดียว
คลาสหนึ่งควรมี เหตุผลเดียวที่ต้องเปลี่ยนแปลง คลาสที่สร้างรายงาน จัดรูปแบบเป็น HTML และส่งอีเมลมีเหตุผลที่ต้องเปลี่ยนแปลงสามข้อ ให้แยกส่วนการจัดเก็บ การจัดรูปแบบ และการส่งต่อออกจากกัน
ด้านล่างนี้ Invoice มีหน้าที่เพียงจำลองข้อมูล ส่วนการแสดงผลและการบันทึกอยู่ที่อื่น
<?php
final class Invoice {
public function __construct(
public readonly string $number,
public readonly int $cents
) {}
public function total(): float { return $this->cents / 100; }
}
final class InvoiceRenderer {
public function toText(Invoice $i): string {
return sprintf('Invoice %s: $%.2f', $i->number, $i->total());
}
}
$i = new Invoice('INV-1', 12500);
echo (new InvoiceRenderer())->toText($i), PHP_EOL;
SRP: การสังเกตสัญญาณผิดปกติ
การละเมิด SRP ที่พบได้ทั่วไปคือคลาสที่ชื่อมีคำว่า และ หรือ Manager ที่ทำทุกอย่าง ให้สังเกตเมธอดที่เปลี่ยนแปลงด้วยเหตุผลทางธุรกิจที่ไม่เกี่ยวข้องกัน หากการเปลี่ยนกฎภาษีและการเปลี่ยนรูปแบบ PDF ต่างก็แตะคลาสเดียวกัน แสดงว่าคลาสนั้นมีความรับผิดชอบมากเกินไป
หลักการเปิด-ปิด
องค์ประกอบของซอฟต์แวร์ควร เปิดเพื่อขยาย ปิดเพื่อแก้ไข การเพิ่มประเภทส่วนลดใหม่ไม่ควรบังคับให้แก้ไข switch ขนาดใหญ่ ให้ใช้พหุรูปแบบ โดยให้แต่ละกฎเป็นคลาสของตนเองที่ใช้อินเทอร์เฟซร่วมกัน
<?php
interface Discount { public function apply(float $total): float; }
final class PercentOff implements Discount {
public function __construct(private float $pct) {}
public function apply(float $t): float { return $t * (1 - $this->pct / 100); }
}
final class FlatOff implements Discount {
public function __construct(private float $amount) {}
public function apply(float $t): float { return max(0, $t - $this->amount); }
}
function checkout(float $total, Discount ...$discounts): float {
foreach ($discounts as $d) { $total = $d->apply($total); }
return $total;
}
echo checkout(100, new PercentOff(10), new FlatOff(5)), PHP_EOL; // 85
การแทนที่ของ Liskov
ประเภทย่อยต้องใช้งานได้ทุกที่ที่คาดว่าจะใช้ประเภทพื้นฐาน โดย ไม่ทำให้ผู้เรียกคาดเดาผิด ตัวอย่างที่มีชื่อเสียงคือ Square extends Rectangle ซึ่งละเมิด LSP เพราะการกำหนดความกว้างต้องไม่เปลี่ยนความสูงโดยไม่แจ้งให้ทราบ ควรจำลองทั้งสองเป็นประเภทแยกกันที่อยู่เบื้องหลังอินเทอร์เฟซ Shape ร่วมกัน
<?php
interface Shape { public function area(): float; }
final class Rectangle implements Shape {
public function __construct(private float $w, private float $h) {}
public function area(): float { return $this->w * $this->h; }
}
final class Square implements Shape {
public function __construct(private float $side) {}
public function area(): float { return $this->side ** 2; }
}
$shapes = [new Rectangle(2, 3), new Square(4)];
foreach ($shapes as $s) { echo $s->area(), PHP_EOL; }
LSP และสัญญา
LSP ยังมีข้อจำกัดต่อสัญญาของเมธอดด้วย ประเภทย่อยอาจ ลดความเข้มงวดของเงื่อนไขก่อนทำงาน และ เพิ่มความเข้มงวดของเงื่อนไขหลังทำงาน ได้ แต่ห้ามทำตรงกันข้าม การโยนประเภทข้อผิดพลาดใหม่ที่ประเภทพื้นฐานไม่เคยประกาศไว้ หรือการคืนค่า null ในกรณีที่ประเภทพื้นฐานรับประกันว่าจะคืนอ็อบเจ็กต์ ถือเป็นการละเมิดการแทนที่ ประเภทผลลัพธ์แบบร่วมแปรผันและประเภทพารามิเตอร์แบบแย้งแปรผันของ PHP บังคับใช้บางส่วนของหลักการนี้ในระดับประเภท
การแยกส่วนอินเทอร์เฟซ
ผู้ใช้บริการไม่ควรพึ่งพาเมธอดที่ตนไม่ได้ใช้ อินเทอร์เฟซ Worker ขนาดใหญ่ที่มี work() และ eat() จะบังคับให้ RobotWorker ต้องสร้างโครงร่างสำหรับ eat() ให้แยกเป็นอินเทอร์เฟซตามบทบาทที่เจาะจง เพื่อให้ผู้ที่นำไปใช้แต่ละรายรับรองเฉพาะสิ่งที่ตนทำจริง
<?php
interface Workable { public function work(): string; }
interface Feedable { public function eat(): string; }
final class Human implements Workable, Feedable {
public function work(): string { return 'coding'; }
public function eat(): string { return 'lunch'; }
}
final class Robot implements Workable {
public function work(): string { return 'welding'; }
}
foreach ([new Human(), new Robot()] as $w) { echo $w->work(), PHP_EOL; }
การกลับทิศทางการพึ่งพา
นโยบายระดับสูงควรพึ่งพา สิ่งนามธรรม ไม่ใช่รายละเอียดที่เป็นรูปธรรม ให้ฉีดอินเทอร์เฟซแทนการระบุคลาสตายตัว วิธีนี้ทำให้คุณสลับตัวส่งอีเมลจริงเป็นตัวจำลองในการทดสอบ และใช้ผู้ให้บริการรายอื่นในระบบจริงได้โดยไม่ต้องแก้ไขผู้ใช้บริการ
<?php
interface Mailer { public function send(string $to, string $body): void; }
final class SmtpMailer implements Mailer {
public function send(string $to, string $body): void {
echo "SMTP -> $to: $body" . PHP_EOL;
}
}
final class SignupService {
public function __construct(private Mailer $mailer) {}
public function register(string $email): void {
$this->mailer->send($email, 'Welcome!');
}
}
(new SignupService(new SmtpMailer()))->register('a@b.com');
DIP และตัวจัดการ
การ กลับทิศทาง การพึ่งพาคือหลักการ ส่วนการ ฉีด การพึ่งพาคือเทคนิคหนึ่งที่ใช้ปฏิบัติตามหลักการนั้น ตัวจัดการ DI (PSR-11) จะเชื่อม SmtpMailer ที่เป็นรูปธรรมเข้ากับสิ่งนามธรรม Mailer ที่จุดประกอบระบบ ผู้ใช้บริการไม่เคยเขียน new SmtpMailer() ดังนั้นทิศทางการพึ่งพาของซอร์สโค้ดจึงชี้ไปยังสิ่งนามธรรม ไม่ใช่รายละเอียด
<?php
// Composition root wiring (pseudo-container)
$bindings = [
Mailer::class => fn() => new SmtpMailer(),
];
$resolve = fn(string $id) => $bindings[$id]();
$service = new SignupService($resolve(Mailer::class));
$service->register('user@example.com');
SOLID ร่วมกัน
หลักการเหล่านี้ช่วยเสริมกันและกัน ISP ทำให้อินเทอร์เฟซมีขนาดเล็ก เพื่อให้การฉีดตาม DIP ยังคงมุ่งเน้น OCP อาศัยพหุรูปแบบที่ LSP ช่วยให้ปลอดภัย SRP ทำให้คุณมีคลาสขนาดเล็กที่ทำให้ทุกอย่างนี้เป็นไปได้ มุ่งให้ ภายในมีความเป็นอันหนึ่งอันเดียวกัน และระหว่างส่วนต่าง ๆ เชื่อมโยงกันอย่างหลวม
- อย่าสร้างสิ่งนามธรรมมากเกินไปสำหรับคลาสที่ใช้เพียงครั้งเดียว
- แนะนำอินเทอร์เฟซเมื่อมีการนำไปใช้ครั้งที่สองหรือตัวจำลองสำหรับการทดสอบปรากฏขึ้น
การใช้วิจารณญาณเชิงปฏิบัติ
SOLID เป็นหนทาง ไม่ใช่จุดหมาย อินเทอร์เฟซที่สร้างขึ้นก่อนเวลาอันควรและมีการนำไปใช้เพียงแบบเดียวเพิ่มการอ้อมผ่านโดยไม่ให้ประโยชน์ (“การสร้างความทั่วไปโดยคาดเดา”) ให้ใช้หลักการเหล่านี้เมื่อการเปลี่ยนแปลงเกิดขึ้นจริงหรือเห็นได้ชัดว่ากำลังจะเกิดขึ้น การปรับโครงสร้างไปสู่ SOLID ทำได้ง่ายเมื่อมีการทดสอบแล้ว แต่การปรับโครงสร้างตามหลักการนี้อย่างไม่ไตร่ตรองตั้งแต่วันแรกเป็นการเสียเวลา
ตรวจสอบความเข้าใจ
ปัญหาการสืบทอด Square/Rectangle ละเมิดหลักการใด
ทบทวน
คุณได้นำหลักการ SOLID ทั้งห้าข้อมาใช้กับ PHP จริง:
- SRP: แต่ละคลาสมีเหตุผลเดียวที่ต้องเปลี่ยนแปลง
- OCP: ขยายผ่านคลาสที่ใช้พหุรูปแบบใหม่ แทนการแก้ไข switch
- LSP: ประเภทย่อยปฏิบัติตามสัญญาของประเภทพื้นฐาน
- ISP: ใช้อินเทอร์เฟซตามบทบาทขนาดเล็กแทนอินเทอร์เฟซขนาดใหญ่
- DIP: พึ่งพาสิ่งนามธรรม และฉีดรายละเอียดที่จุดประกอบระบบ
ใช้หลักการเหล่านี้เป็นแนวทางในการปรับโครงสร้าง ไม่ใช่ทำตามพิธีการ
คำถามที่พบบ่อย
บทเรียน “หลักการ SOLID ในการใช้งานจริง” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “หลักการ SOLID ในการใช้งานจริง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “หลักการ SOLID ในการใช้งานจริง”
ประยุกต์ใช้หลักการ SOLID ทั้งห้าข้อกับคลาส PHP จริง คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “หลักการ SOLID ในการใช้งานจริง” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- หลักการ SOLID ในการใช้งานจริง
- รูปแบบการสร้าง: Factory, Builder, Singleton
- รูปแบบโครงสร้าง: Adapter, Decorator, Facade
- รูปแบบพฤติกรรม: Strategy, Observer, Command