ป้ายกำกับ: SoC

PHP: Architectural Patterns (กลุ่มสถาปัตยกรรมเว็บ)PHP: Architectural Patterns (กลุ่มสถาปัตยกรรมเว็บ)


1. แนวคิดและหลักการทำงานของ Architectural Patterns (กลุ่มสถาปัตยกรรมเว็บ)

ในฐานะนักพัฒนา PHP ระดับสูง การเข้าใจถึง Architectural Patterns ไม่ใช่แค่เรื่องของการเลือกใช้ Framework แต่คือการทำความเข้าใจ “โครงสร้าง” ของระบบทั้งหมด วัตถุประสงค์หลักของสถาปัตยกรรมเหล่านี้คือการบรรลุ Separation of Concerns (SoC) ซึ่งหมายถึงการแยกส่วนความรับผิดชอบออกจากกันอย่างชัดเจน

เมื่อเรานำรูปแบบสถาปัตยกรรม เช่น Model-View-Controller (MVC), Service Layer, หรือ Repository Pattern มาใช้ จะช่วยให้โค้ดของเรามีคุณสมบัติดังนี้:

  • Maintainability: เมื่อต้องการแก้ไขฟังก์ชันใด ฟังก์ชันนั้นจะถูกจำกัดอยู่ในชั้น (Layer) ที่รับผิดชอบเท่านั้น ไม่ส่งผลกระทบต่อส่วนอื่นของระบบ
  • Testability: แต่ละ Component สามารถถูกทดสอบได้อย่างอิสระ (Unit Testing) โดยไม่ต้องรันระบบทั้งหมด
  • Scalability: ระบบสามารถขยายขนาดได้ง่าย เพราะการเพิ่มฟีเจอร์ใหม่ทำได้โดยการเพิ่ม Layer ใหม่ ไม่ใช่การยัดโค้ดเข้าไปในไฟล์เดิมๆ

2. ไวยากรณ์ (Syntax) และตัวอย่างโค้ดการใช้งาน

เราจะใช้รูปแบบ MVC เป็นตัวอย่างหลัก เนื่องจากเป็น Pattern ที่พบได้บ่อยที่สุดใน PHP Frameworks ส่วนใหญ่ การทำความเข้าใจว่า Model, View, และ Controller มีหน้าที่อะไร จะช่วยให้คุณจัดโครงสร้างโค้ดได้อย่างถูกต้อง

  • Model (M): จัดการกับ Business Logic และ Data Interaction (เช่น การติดต่อฐานข้อมูล)
  • View (V): รับผิดชอบในการแสดงผล (Presentation Layer) มักจะเป็น HTML/Template Engine
  • Controller (C): ทำหน้าที่เป็นตัวกลาง (Mediator) รับ Input จากผู้ใช้และเรียก Model เพื่อประมวลผล ก่อนจะส่งข้อมูลไปให้ View แสดงผล
<pre class="wp-block-syntaxhighlighter-code"><?php
// ------------------------------------
// 1. Model Layer (Business Logic & Data)
// ------------------------------------
class UserModel {
    private $db;

    public function __construct($databaseConnection) {
        $this->db = $databaseConnection; // Dependency Injection
    }

    /**
     * ดึงข้อมูลผู้ใช้จากฐานข้อมูล
     */
    public function findUserById(int $userId): ?array {
        // ในความเป็นจริงควรใช้ Prepared Statements เสมอ
        $stmt = $this->db->prepare("SELECT * FROM users WHERE id = :id");
        $stmt->bindParam(':id', $userId);
        $stmt->execute();
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }
}

// ------------------------------------
// 2. Controller Layer (Handling Request)
// ------------------------------------
class UserController {
    private UserModel $userModel;

    public function __construct(UserModel $model) {
        $this->userModel = $model; // รับ Model เข้ามาผ่าน Constructor
    }

    /**
     * จัดการ Logic เมื่อมีการร้องขอหน้าโปรไฟล์ผู้ใช้
     */
    public function showProfile(int $userId): void {
        // 1. เรียก Model เพื่อดึงข้อมูล (Business Logic)
        $userData = $this->userModel->findUserById($userId);

        if (!$userData) {
            http_response_code(404);
            echo "Error: User not found.";
            return;
        }

        // 2. ส่งข้อมูลที่ได้ไปให้ View แสดงผล (Separation of Concerns)
        $viewData = [
            'user' => $userData,
            'title' => 'User Profile'
        ];
        View::render('profile', $viewData); // สมมติว่ามีคลาส View
    }
}

// ------------------------------------
// 3. View Layer (Presentation) - จำลองการทำงาน
// ------------------------------------
class View {
    public static function render(string $template, array $data): void {
        // ในความเป็นจริงคือการ include ไฟล์ template และส่งตัวแปรเข้าไป
        echo "<h1>" . ($data['title'] ?? 'Page') . "</h1>";
        echo "<p>Welcome back, " . htmlspecialchars($data['user']['name']) . "</p>";
    }
}

// --- การเรียกใช้งาน (Simulation) ---
$db = new class { // Mock DB connection
    public function prepare(string $sql): object { return new stdClass(); }
    public function bindParam(string $param, mixed $value): void {}
    public function execute(): bool { return true; }
    public function fetch(int $mode): ?array { return ['id' => 1, 'name' => 'John Doe', 'email' => '[email protected]']; }
};

$userModel = new UserModel($db);
$controller = new UserController($userModel);

// เริ่มต้นการทำงานของระบบ
$controller->showProfile(1);
?></pre>

3. Best Practices และคำแนะนำด้าน Performance / Security

  • Dependency Injection (DI): ควรใช้ DI Container เพื่อจัดการการสร้าง Object แทนการใช้ `new` โดยตรง การทำเช่นนี้จะทำให้โค้ดของเราเป็น Loose Coupling และง่ายต่อการ Mock ใน Unit Test
  • Security (SQL Injection): ห้ามรัน Query ที่สร้างจาก String Concatenation โดยเด็ดขาด! ต้องใช้ Prepared Statements เสมอ ไม่ว่าจะเป็น PDO หรือ ORM ใดๆ ก็ตาม
  • Performance (Caching): ใช้ Caching Layer เช่น Redis หรือ Memcached สำหรับข้อมูลที่ถูกเรียกบ่อยแต่ไม่เปลี่ยนแปลงบ่อย (เช่น ข้อมูลการตั้งค่าระบบ, รายชื่อหมวดหมู่) เพื่อลดภาระของ Database

โดยสรุปแล้ว การเลือกใช้ Architectural Pattern ที่เหมาะสม ไม่ได้หมายถึงการเพิ่มความซับซ้อน แต่คือการสร้าง “ขอบเขต” (Boundaries) ให้กับโค้ดของคุณอย่างชัดเจน ทำให้ระบบ PHP ของคุณมีความยืดหยุ่น ทนทานต่อการเปลี่ยนแปลง และพร้อมสำหรับการเติบโตในระยะยาว