คุณเคยเปิดโปรเจกต์ PHP เก่าของตัวเองแล้วรู้สึกหลงทางไหม? ไฟล์กระจัดกระจาย ไม่รู้ว่า Logic อยู่ตรงไหน Database อยู่ที่ไหน — ปัญหานี้เกิดจากการไม่มี โครงสร้างโปรเจกต์ที่ชัดเจน ตั้งแต่แรก บทความนี้จะพาคุณเรียนรู้วิธีจัดระเบียบโปรเจกต์ PHP อย่างมืออาชีพ พร้อมตัวอย่างโค้ดจริงสำหรับ CodeIgniter 4 และ Laravel
ทำไมโครงสร้างโปรเจกต์ถึงสำคัญ?
PHP ถูกใช้งานในเว็บไซต์กว่า 80% ทั่วโลก ตั้งแต่บล็อกเล็กๆ ไปจนถึงระบบขนาดใหญ่อย่าง Facebook, Wikipedia และ Slack ล้วนใช้ PHP เป็นแกนหลัก สิ่งที่ทำให้โปรเจกต์เหล่านี้ดูแลรักษาได้ง่ายคือ โครงสร้างไฟล์และโฟลเดอร์ที่มีระเบียบ
เมื่อโปรเจกต์ขยายตัว สมาชิกในทีมเพิ่มขึ้น หรือคุณต้องกลับมาแก้ไขโค้ดหลังจากผ่านไปหลายเดือน โครงสร้างที่ดีจะช่วยให้:
✅ ประโยชน์ของโครงสร้างที่ดี
นำทางในโค้ดได้ง่าย · ทำงานร่วมกันในทีมได้ลื่นขึ้น · เพิ่มฟีเจอร์ใหม่โดยไม่กระทบส่วนอื่น · เขียน Unit Test ได้สะดวก · Deploy และ Maintain ได้ง่ายในระยะยาว
โครงสร้างโฟลเดอร์มาตรฐาน PHP
โปรเจกต์ PHP สมัยใหม่ควรแยกหน้าที่ของแต่ละส่วนออกจากกันอย่างชัดเจน นี่คือโครงสร้างที่นิยมใช้กัน:
├── bin/
├── config/
├── public/
├── src/
│ ├── Controllers/
│ ├── Models/
│ └── Services/
├── templates/
├── tests/
├── var/
├── vendor/
├── .env
├── composer.json
└── README.md
หลักสำคัญคือ โฟลเดอร์ public/ ควรเป็นจุดเดียวที่ Web Server เข้าถึงได้จากภายนอก ส่วนโค้ดหลักทั้งหมดอยู่ใน src/ ซึ่ง User ไม่สามารถเข้าถึงโดยตรงได้ เป็นการป้องกันความปลอดภัยขั้นพื้นฐาน
โครงสร้างใน CodeIgniter 4
CodeIgniter 4 มาพร้อมโครงสร้างที่ออกแบบมาอย่างดี ทำให้ผู้เริ่มต้นเข้าใจง่าย มาดูตัวอย่าง Controller และ Model ที่เขียนถูกหลักการ:
Controller — รับ Request และส่งต่อให้ Model
<?php
namespace App\Controllers;
use App\Models\ArticleModel;
use CodeIgniter\HTTP\RedirectResponse;
class ArticleController extends BaseController
{
protected ArticleModel $model;
public function __construct()
{
$this->model = new ArticleModel();
}
public function index(): string
{
$data = [
'articles' => $this->model->findAll(),
'title' => 'บทความทั้งหมด',
];
return view('articles/index', $data);
}
public function show(int $id): string
{
$article = $this->model->find($id);
if (! $article) {
throw new \CodeIgniter\Exceptions\PageNotFoundException();
}
return view('articles/show', ['article' => $article]);
}
}Model — จัดการข้อมูลและ Business Logic
<?php
namespace App\Models;
use CodeIgniter\Model;
class ArticleModel extends Model
{
protected $table = 'articles';
protected $primaryKey = 'id';
protected $returnType = 'array';
protected $allowedFields = ['title', 'body', 'slug', 'author_id'];
protected $validationRules = [
'title' => 'required|min_length[5]|max_length[200]',
'body' => 'required|min_length[20]',
];
public function getLatest(int $limit = 10): array
{
return $this->orderBy('created_at', 'DESC')
->limit($limit)
->findAll();
}
}โครงสร้างใน Laravel — Blade Template
Laravel ใช้ Blade เป็น Template Engine ที่ช่วยให้ View สะอาดและอ่านง่าย ตัวอย่างด้านล่างแสดงการใช้ Layout Inheritance และ Component:
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<title>@yield('title', 'My App')</title>
</head>
<body>
@include('partials.navbar')
<main class="container">
@yield('content') {{-- ส่วนที่ Child View จะ inject เนื้อหาเข้ามา --}}
</main>
@stack('scripts') {{-- สำหรับ JavaScript เฉพาะหน้า --}}
</body>
</html>@extends('layouts.app')
@section('title', 'บทความทั้งหมด')
@section('content')
<h1>บทความล่าสุด</h1>
@forelse($articles as $article)
<div class="card">
<h2>{{ $article->title }}</h2>
<p>{{ Str::limit($article->body, 150) }}</p>
<a href="{{ route('articles.show', $article) }}">
อ่านต่อ →
</a>
</div>
@empty
<p>ยังไม่มีบทความ</p>
@endforelse
{{ $articles->links() }} {{-- Pagination --}}
@endsectionจัดการ Configuration อย่างปลอดภัย
หนึ่งในข้อผิดพลาดที่พบบ่อยที่สุดของนักพัฒนาหน้าใหม่คือการ เขียน password หรือ API key ลงในโค้ดโดยตรง วิธีที่ถูกต้องคือใช้ไฟล์ .env และโหลดค่าผ่าน Config Class:
DB_HOST=localhost
DB_NAME=my_database
DB_USER=root
DB_PASS=supersecret123
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=587
APP_DEBUG=false
APP_ENV=production
<?php
namespace Config;
use CodeIgniter\Database\Config;
class Database extends Config
{
public array $default = [
'hostname' => env('DB_HOST', 'localhost'),
'database' => env('DB_NAME', 'ci4app'),
'username' => env('DB_USER', 'root'),
'password' => env('DB_PASS', ''),
'DBDriver' => 'MySQLi',
'charset' => 'utf8mb4',
];
}💡 เคล็ดลับ: เพิ่ม .env เข้าไปใน .gitignore เสมอ แล้วสร้าง .env.example ที่มีแค่ชื่อตัวแปรโดยไม่มีค่าจริง เพื่อให้ทีมรู้ว่าต้องตั้งค่าอะไรบ้าง
เปรียบเทียบโครงสร้าง: CI4 vs Laravel
แม้ทั้งสองเฟรมเวิร์กจะมีแนวคิด MVC เหมือนกัน แต่มีความแตกต่างในโครงสร้างไฟล์ที่ควรรู้:
| ส่วนประกอบ | CodeIgniter 4 | Laravel 11+ | หน้าที่ |
|---|
| Controllers | app/Controllers/ | app/Http/Controllers/ | รับ Request, เรียก Model, Return View |
| Models | app/Models/ | app/Models/ | จัดการข้อมูลและ Business Logic |
| Views | app/Views/ | resources/views/ | HTML Template แสดงผล |
| Routes | app/Config/Routes.php | routes/web.php | กำหนด URL → Controller |
| Config | app/Config/ | config/ | ค่าตั้งค่าระบบ |
| Migrations | app/Database/Migrations/ | database/migrations/ | สร้าง/แก้ไขตารางในฐานข้อมูล |
| Assets | public/ | public/ | CSS, JS, Images ที่ Browser เข้าถึงได้ |
| Tests | tests/ | tests/ | Automated Testing |
เพิ่ม Service Layer — แยก Logic ออกจาก Controller
เมื่อ Business Logic ซับซ้อนขึ้น ควรแยกออกมาเป็น Service Class เพื่อให้ Controller บางและทดสอบได้ง่าย:
<?php
namespace App\Services;
use App\Models\ArticleModel;
class ArticleService
{
public function __construct(
private readonly ArticleModel $model
) {}
public function create(array $data): int
{
$data['slug'] = $this->makeSlug($data['title']);
$data['author_id'] = user_id();
return $this->model->insert($data);
}
private function makeSlug(string $title): string
{
return strtolower(str_replace(' ', '-', $title));
}
}สรุป: หลัก 5 ข้อในการจัดโครงสร้าง PHP Project
การจัดโครงสร้าง PHP Project ที่ดีไม่ใช่เรื่องซับซ้อน เพียงแค่ยึดหลักพื้นฐานเหล่านี้:
1. แยก public/ ออกจาก source code — ป้องกันไม่ให้ User เข้าถึงโค้ดหลัก
2. ใช้ .env สำหรับค่า secret ทุกอย่าง — ไม่เขียน password ลงในโค้ด
3. ยึดหลัก MVC อย่างเคร่งครัด — Controller บาง, Model จัดการ Logic, View แสดงผลล้วนๆ
4. เพิ่ม Service Layer เมื่อ Logic ซับซ้อน — ทำให้โค้ดทดสอบได้ง่าย
5. เขียน Test ในโฟลเดอร์ tests/ — ป้องกัน Bug เมื่อแก้ไขโค้ดในอนาคต
ทั้ง CodeIgniter 4 และ Laravel ต่างมีโครงสร้างที่ออกแบบมาตามหลักการเหล่านี้แล้ว สิ่งที่คุณต้องทำคือ ทำความเข้าใจว่าแต่ละส่วนทำหน้าที่อะไร และเขียนโค้ดให้อยู่ในที่ที่ถูกต้อง เพียงเท่านี้โปรเจกต์ของคุณก็จะดูแลรักษาได้ง่ายขึ้นอย่างเห็นได้ชัด