Mục lục bài viết

Nếu máy chưa có môi trường chạy PHP, hãy xem hướng dẫn cài đặt XAMPP trên Góc Học IT. Sau bài Cài đặt XAMPP và tổ chức mã nguồn PHP, bạn đã biết đặt dự án trong htdocs và mở trang PHP qua localhost. Bây giờ, hãy thử làm một website bán hàng có hai trang là Trang chủ và Sản phẩm. Cả hai cần cùng một menu, chân trang và giao diện CSS.

Giả sử bạn đã chép menu vào cả hai trang. Khi đổi tên mục “Sản phẩm” thành “Danh mục sản phẩm”, bạn phải sửa ở cả hai nơi. Nếu tách menu thành một file dùng chung, bạn chỉ cần sửa file đó. Đây là cách tổ chức mã nguồn PHP để việc cập nhật giao diện đơn giản hơn.

1. Tổ chức mã nguồn PHP theo thư mục

Nếu cài XAMPP ở vị trí mặc định trên Windows, hãy tạo thư mục banhang trong C:\xampp\htdocs. Mở thư mục banhang bằng Visual Studio Code và tạo các file sau.

Cách tổ chức mã nguồn PHP
banhang/
├── index.php
├── includes/
│   ├── header.php
│   ├── navbar.php
│   └── footer.php
├── pages/
│   └── san-pham.php
└── assets/
    └── css/
        └── style.css
Vị tríVai trò
index.phpHiển thị trang chủ.
pages/Chứa các trang nội dung như Sản phẩm, Giới thiệu hoặc Liên hệ.
includes/Chứa các phần được ghép vào nhiều trang, như menu và chân trang.
assets/Chứa các tài nguyên trình duyệt tải trực tiếp. Khi cần, có thể thêm assets/js/ và assets/img/.

Ví dụ này dùng dữ liệu mẫu trong PHP, vì vậy bạn chỉ cần bật Apache trong XAMPP Control Panel. Khi website có cơ sở dữ liệu, có thể gom các thiết lập kết nối vào nhóm file cấu hình. Khi triển khai, hãy giữ mật khẩu và khóa API ngoài thư mục web công khai và kho Git.

2. Tách phần đầu trang, menu và chân trang

Phần đầu trang — includes/header.php

File này mở tài liệu HTML, hiển thị tiêu đề trên tab trình duyệt và liên kết đến CSS. Mỗi trang sẽ đặt biến $pageTitle trước khi nạp file.

<!doctype html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?= htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8') ?> | Cửa hàng laptop</title>
    <link rel="stylesheet" href="/banhang/assets/css/style.css">
</head>
<body>

Cú pháp <?= ... ?> in giá trị ra HTML. Hàm htmlspecialchars() giúp trình duyệt hiển thị các ký tự như < và & dưới dạng văn bản trong tiêu đề.

Menu — includes/navbar.php

<nav aria-label="Điều hướng chính">
    <a href="/banhang/">Trang chủ</a>
    <a href="/banhang/pages/san-pham.php">Sản phẩm</a>
</nav>

Chân trang — includes/footer.php

Chân trang đóng hai thẻ body và html đã mở trong header.php.

<footer>
    <p>Cửa hàng laptop</p>
</footer>
</body>
</html>

3. Tổ chức mã nguồn PHP với các phần dùng chung

Trang chủ — index.php

<?php
$pageTitle = 'Trang chủ';

require __DIR__ . '/includes/header.php';
require __DIR__ . '/includes/navbar.php';
?>

<main>
    <h1>Chào mừng đến với cửa hàng laptop</h1>
    <p>Xem các mẫu laptop và giá tại trang Sản phẩm.</p>
</main>

<?php require __DIR__ . '/includes/footer.php'; ?>

Mở http://localhost/banhang/. Với cấu hình XAMPP thông thường, Apache sẽ dùng index.php làm trang mặc định của thư mục. PHP xử lý các file theo thứ tự xuất hiện trong mã nguồn. Trình duyệt nhận một tài liệu HTML gồm phần đầu trang, menu, nội dung chính và chân trang.

Trang sản phẩm — pages/san-pham.php

Trang này chuẩn bị tên và giá sản phẩm ở đầu file. Phần trong thẻ <main> chỉ duyệt dữ liệu và hiển thị. Cách sắp xếp này giúp bạn tìm chỗ sửa giá ngay cả khi phần HTML dài hơn.

<?php
$pageTitle = 'Sản phẩm';
$products = [
    ['name' => 'Laptop Dell', 'price' => 15000000],
    ['name' => 'Laptop Lenovo', 'price' => 18500000],
];

require __DIR__ . '/../includes/header.php';
require __DIR__ . '/../includes/navbar.php';
?>

<main>
    <h1>Danh sách sản phẩm</h1>

    <ul>
        <?php foreach ($products as $product): ?>
            <li>
                <?= htmlspecialchars($product['name'], ENT_QUOTES, 'UTF-8') ?>
                · <?= number_format($product['price'], 0, ',', '.') ?> ₫
            </li>
        <?php endforeach; ?>
    </ul>
</main>

<?php require __DIR__ . '/../includes/footer.php'; ?>

Bấm Sản phẩm trên menu hoặc mở http://localhost/banhang/pages/san-pham.php. Giá của Laptop Dell sẽ hiển thị là 15.000.000 ₫.

Giao diện dùng chung — assets/css/style.css

body {
    margin: 0;
    font: 1rem/1.6 Arial, sans-serif;
    color: #1e293b;
}

nav {
    display: flex;
    gap: 1rem;
    padding: 1rem 1.5rem;
    background: #0f766e;
}

nav a {
    color: white;
}

main,
footer {
    padding: 1rem 1.5rem;
}

footer {
    background: #f1f5f9;
}

Tải lại cả hai trang. Nếu menu ở cả hai trang đều có nền xanh, trình duyệt đã tải cùng một file CSS từ hai URL trang khác nhau.

4. Phân biệt đường dẫn trong PHP và đường dẫn trên trình duyệt

Hai dòng dưới đây có vẻ giống nhau vì đều chứa dấu /. Chúng được xử lý ở hai nơi khác nhau.

Đoạn mãAi xử lý?Đường dẫn được tính từ đâu?
require __DIR__ . '/../includes/header.php';PHPTừ thư mục chứa file đang viết, tức pages/ trong ví dụ này.
href="/banhang/assets/css/style.css"Trình duyệtTừ gốc của website, tức http://localhost/ trong ví dụ này.

__DIR__ là đường dẫn trên máy chủ đến thư mục chứa file PHP đang dùng hằng đó. Trong index.php, nó trỏ tới C:\xampp\htdocs\banhang, nên có thể đi thẳng vào includes/. Trong pages/san-pham.php, nó trỏ tới C:\xampp\htdocs\banhang\pages. Dấu .. đưa đường dẫn lên thư mục cha banhang/ rồi mới vào includes/.

Đối với CSS, trình duyệt đọc URL trong thẻ <link> và gửi một yêu cầu riêng. Dấu / ở đầu /banhang/assets/css/style.css khiến URL bắt đầu từ gốc website trên cả hai trang. Nếu viết href="assets/css/style.css", trình duyệt sẽ tìm trong /banhang/assets/ ở trang chủ, nhưng sẽ tìm trong /banhang/pages/assets/ ở trang sản phẩm. Nếu đổi tên thư mục dự án, hãy cập nhật phần /banhang/ trong các URL dùng chung.

5. Khi nào dùng include, require và _once?

Câu lệnhNếu file không nạp đượcNếu file đã được nạp trong cùng lần chạy
includePHP phát cảnh báo và có thể tiếp tục chạy.Có thể nạp lại.
requirePHP báo lỗi. Quá trình thực thi sẽ dừng nếu lỗi không được xử lý.Có thể nạp lại.
include_onceCó hành vi như include.Bỏ qua lần nạp tiếp theo.
require_onceCó hành vi như require.Bỏ qua lần nạp tiếp theo.

Ví dụ dùng require vì mỗi thành phần giao diện là một phần bắt buộc và mỗi trang gọi nó đúng một lần. Hậu tố _once hữu ích khi nhiều file cùng nạp một thư viện chứa hàm hoặc lớp. PHP sẽ bỏ qua lần nạp tiếp theo trong cùng lần chạy, giúp tránh khai báo trùng.

6. Bài tập tổ chức mã nguồn PHP

  1. Kiểm tra phần dùng chung. Đổi chữ “Sản phẩm” thành “Danh mục sản phẩm” trong includes/navbar.php. Tải lại cả hai trang và kiểm tra menu đã đổi ở cả hai nơi.
  2. Tìm lỗi đường dẫn PHP. Trong pages/san-pham.php, tạm bỏ .. ở dòng nạp header. Đọc đường dẫn PHP báo lỗi, xác định nó đã tìm thư mục includes/ ở đâu rồi khôi phục dòng đúng.
  3. Tìm lỗi đường dẫn CSS. Tạm đổi URL CSS trong header.php thành assets/css/style.css. Mở tab Network trong công cụ nhà phát triển, tải lại trang sản phẩm và tìm yêu cầu CSS trả về 404. Sau đó khôi phục URL bắt đầu bằng /banhang/.
  4. Thêm trang Liên hệ. Tạo pages/lien-he.php, đặt tiêu đề riêng, nạp ba thành phần giao diện dùng chung và thêm liên kết vào menu. Kiểm tra có thể chuyển qua lại giữa cả ba trang.

Khi thêm một trang mới, hãy bắt đầu bằng phần nội dung riêng của trang đó. Phần giao diện xuất hiện ở nhiều nơi có thể đưa vào includes/. Khi gặp lỗi đường dẫn, hãy xác định trước dòng đó do PHP hay trình duyệt xử lý.

Tác giả

HV Lee

500+ bài viết về lập trình, phần cứng, mạng máy tính và công nghệ. Chia sẻ kiến thức từ những gì đã học, đã dạy và đã trải nghiệm — để người học CNTT hiểu sâu hơn và làm được nhiều hơn.

Gợi ý tiếp theo

Mảng 2 chiều (2 dimensional array) trong PHP

Học tiếp