Hàm (Function)

Sau khi nắm vững vòng lặp trong PHP, bước tiếp theo là học cách tổ chức code hiệu quả với hàm trong PHP. Hàm giúp bạn gom nhóm các đoạn code thực hiện một nhiệm vụ cụ thể, tránh lặp lại code và làm chương trình dễ đọc, dễ bảo trì hơn. Thay vì viết cùng một đoạn code 10 lần ở 10 nơi khác nhau, bạn chỉ cần tạo 1 hàm và gọi nó 10 lần.

1. Hàm là gì?

Hàm (Function) là một khối code có tên, thực hiện một nhiệm vụ cụ thể. Bạn có thể gọi hàm nhiều lần mà không cần viết lại code. Ví dụ thực tế:

  • ✅ Hàm tính tổng 2 số
  • ✅ Hàm kiểm tra email hợp lệ
  • ✅ Hàm kết nối database
  • ✅ Hàm gửi email
  • ✅ Hàm format tiền tệ

PHP có 2 loại hàm:

  • Hàm built-in: PHP cung cấp sẵn (strlen(), array_push(), date()…)
  • Hàm tự định nghĩa: Lập trình viên tự tạo theo nhu cầu
CẤU TRÚC HÀM TRONG PHP function tinhTong($a, $b) { ↓ Từ khóa ↓ Tên hàm ↓ Tham số Khối code (Function Body) // Khai báo biến cục bộ $tong = $a + $b; // Xử lý logic $tong = $tong * 2; // Trả về kết quả return $tong; } 💡 Gọi hàm: $ket_qua = tinhTong(10, 20); // $ket_qua = 60
Hình 1: Cấu trúc hàm trong PHP

2. Cú pháp tạo hàm

<?php
// Cú pháp cơ bản
function ten_ham() {
  // Code thực thi
}

// Ví dụ 1: Hàm đơn giản
function chao() {
  echo "Xin chào!";
}

// Gọi hàm
chao(); // Kết quả: Xin chào!
chao(); // Kết quả: Xin chào!

// Ví dụ 2: Hàm in dấu sao
function inDauSao() {
  echo "*****<br>";
}

inDauSao();
inDauSao();
inDauSao();
/*
Kết quả:
*****
*****
*****
*/
?>

2.1. Quy tắc đặt tên hàm

<?php
// ✅ Đúng
function tinhTong() { }
function tinh_tong() { }
function TinhTong() { }
function _private() { }

// ❌ Sai
function 123ham() { }      // Bắt đầu bằng số
function tinh-tong() { }   // Có dấu gạch ngang
function tinh tong() { }   // Có khoảng trắng

// Lưu ý: PHP không phân biệt hoa thường tên hàm
function chaoMung() { }
ChaoMung(); // Vẫn chạy được
?>

💡 Quy ước đặt tên:
– Dùng động từ: tinhTong(), guiEmail(), kiemTraTuoi()
– Rõ ràng, mô tả đúng nhiệm vụ
– Dùng camelCase hoặc snake_case nhất quán

3. Hàm có tham số (Parameters)

Tham số cho phép truyền dữ liệu vào hàm để xử lý:

<?php
// Cú pháp
function ten_ham($tham_so_1, $tham_so_2) {
  // Code sử dụng tham số
}

// Ví dụ 1: Hàm tính tổng 2 số
function tinhTong($a, $b) {
  $tong = $a + $b;
  echo "Tổng: $tong";
}

tinhTong(10, 20);  // Tổng: 30
tinhTong(5, 7);    // Tổng: 12

// Ví dụ 2: Hàm chào theo tên
function chao($ten) {
  echo "Xin chào, $ten!<br>";
}

chao("Nguyễn Văn A");  // Xin chào, Nguyễn Văn A!
chao("Trần Thị B");    // Xin chào, Trần Thị B!
?>
THAM SỐ VÀ ĐỐI SỐ TRONG HÀM ĐỊNH NGHĨA HÀM (Function Definition) function chao($ten, $tuoi = 18) { ... } THAM SỐ BẮT BUỘC $ten Phải truyền khi gọi hàm THAM SỐ MẶC ĐỊNH $tuoi = 18 Có thể bỏ qua GỌI HÀM (Function Call) chao("Nguyễn Văn A", 20); ✅ Truyền đầy đủ 2 tham số → $ten = "Nguyễn Văn A", $tuoi = 20 chao("Trần Thị B"); ✅ Bỏ qua tham số 2 → $ten = "Trần Thị B", $tuoi = 18 (dùng mặc định) 💡 Tham số mặc định phải đặt sau tham số bắt buộc
Hình 2: Tham số và đối số trong hàm

3.1. Tham số mặc định (Default Parameters)

<?php
// Tham số có giá trị mặc định
function chao($ten = "Khách") {
  echo "Xin chào, $ten!<br>";
}

chao("An");     // Xin chào, An!
chao();         // Xin chào, Khách! (dùng giá trị mặc định)

// Ví dụ 2: Tính lũy thừa
function luyThua($co_so, $so_mu = 2) {
  return pow($co_so, $so_mu);
}

echo luyThua(5);      // 25 (5^2)
echo luyThua(5, 3);   // 125 (5^3)
?>

3.2. Số lượng tham số linh hoạt

<?php
// Dùng func_get_args() để nhận mảng tham số
function tinhTongNhieuSo() {
  $args = func_get_args();
  $tong = 0;
  
  foreach ($args as $so) {
    $tong += $so;
  }
  
  return $tong;
}

echo tinhTongNhieuSo(1, 2, 3);           // 6
echo tinhTongNhieuSo(10, 20, 30, 40);    // 100

// PHP 5.6+: Dùng toán tử ... (spread operator)
function tinhTong(...$so) {
  return array_sum($so);
}

echo tinhTong(5, 10, 15, 20);  // 50
?>

4. Hàm trả về giá trị (Return)

Dùng return để hàm trả về kết quả thay vì chỉ in ra:

<?php
// Không return - chỉ in ra
function tinhTong1($a, $b) {
  echo $a + $b;
}

// Có return - trả về giá trị
function tinhTong2($a, $b) {
  return $a + $b;
}

// So sánh
tinhTong1(5, 3);  // In ra: 8 (không lưu được)

$ket_qua = tinhTong2(5, 3);  // Lưu vào biến
echo $ket_qua;                // 8
echo $ket_qua * 2;            // 16 (có thể tính toán tiếp)
?>

4.1. Ví dụ thực tế

<?php
// Hàm kiểm tra số chẵn
function laSoChan($so) {
  if ($so % 2 == 0) {
    return true;
  } else {
    return false;
  }
}

// Hoặc ngắn gọn hơn
function laSoChan2($so) {
  return $so % 2 == 0;
}

if (laSoChan(10)) {
  echo "10 là số chẵn";
}

// Hàm tính điểm trung bình
function tinhDiemTB($diem_toan, $diem_ly, $diem_hoa) {
  return ($diem_toan + $diem_ly + $diem_hoa) / 3;
}

$dtb = tinhDiemTB(8, 7, 9);
echo "Điểm TB: " . number_format($dtb, 2);  // 8.00
?>

4.2. Return sớm (Early Return)

<?php
function kiemTraTuoi($tuoi) {
  // Return sớm nếu điều kiện không hợp lệ
  if ($tuoi < 0) {
    return "Tuổi không hợp lệ";
  }
  
  if ($tuoi < 18) {
    return "Vị thành niên";
  }
  
  if ($tuoi < 60) {
    return "Trưởng thành";
  }
  
  return "Cao tuổi";
}

echo kiemTraTuoi(-5);   // Tuổi không hợp lệ
echo kiemTraTuoi(15);   // Vị thành niên
echo kiemTraTuoi(30);   // Trưởng thành
echo kiemTraTuoi(65);   // Cao tuổi
?>

5. Phạm vi biến (Variable Scope)

Biến trong hàm có phạm vi riêng, khác với biến bên ngoài:

<?php
$x = 10;  // Biến toàn cục

function testScope() {
  $y = 20;  // Biến cục bộ
  
  // ❌ Không truy cập được $x
  // echo $x;  // Lỗi: Undefined variable
  
  echo $y;  // 20 - OK
}

testScope();

// ❌ Không truy cập được $y
// echo $y;  // Lỗi: Undefined variable
?>
PHẠM VI BIẾN: GLOBAL vs LOCAL GLOBAL SCOPE (Phạm vi toàn cục) $bien_toan_cuc = 100; ✅ Truy cập được ở ngoài hàm ❌ KHÔNG truy cập trong hàm (trừ khi dùng global) function myFunction() { LOCAL SCOPE (Phạm vi cục bộ) $bien_cuc_bo = 50; ✅ Chỉ truy cập được TRONG hàm này ❌ KHÔNG truy cập được bên ngoài hàm global $bien_toan_cuc; // Truy cập biến toàn cục echo $bien_toan_cuc; // OK - Có thể dùng } ⚠️ LƯU Ý Biến cục bộ và biến toàn cục cùng tên là 2 biến KHÁC NHAU
Hình 3: Phạm vi biến Global và Local

5.1. Sử dụng biến toàn cục trong hàm

<?php
$bien_toan_cuc = 100;

// Cách 1: Dùng từ khóa global
function ham1() {
  global $bien_toan_cuc;
  echo $bien_toan_cuc;  // 100
}

// Cách 2: Dùng $GLOBALS
function ham2() {
  echo $GLOBALS['bien_toan_cuc'];  // 100
}

ham1();
ham2();
?>

5.2. Biến tĩnh (Static Variables)

<?php
function demSo() {
  static $dem = 0;  // Giữ giá trị giữa các lần gọi
  $dem++;
  echo "Đã gọi $dem lần<br>";
}

demSo();  // Đã gọi 1 lần
demSo();  // Đã gọi 2 lần
demSo();  // Đã gọi 3 lần

// So sánh với biến thường
function demSo2() {
  $dem = 0;  // Reset về 0 mỗi lần gọi
  $dem++;
  echo "Đã gọi $dem lần<br>";
}

demSo2();  // Đã gọi 1 lần
demSo2();  // Đã gọi 1 lần (không tăng)
?>

6. Tham chiếu (Pass by Reference)

Mặc định PHP truyền tham số theo giá trị (copy). Dùng & để truyền theo tham chiếu:

<?php
// Truyền theo giá trị (mặc định)
function tangGiaTri($so) {
  $so++;
}

$x = 10;
tangGiaTri($x);
echo $x;  // 10 (không đổi)

// Truyền theo tham chiếu
function tangThamChieu(&$so) {
  $so++;
}

$y = 10;
tangThamChieu($y);
echo $y;  // 11 (đã thay đổi)

// Ví dụ thực tế: Swap 2 số
function hoanDoi(&$a, &$b) {
  $temp = $a;
  $a = $b;
  $b = $temp;
}

$x = 5;
$y = 10;
echo "Trước: x=$x, y=$y<br>";
hoanDoi($x, $y);
echo "Sau: x=$x, y=$y";  // x=10, y=5
?>

7. Type Hinting và Return Type

PHP 7+ hỗ trợ khai báo kiểu dữ liệu cho tham số và giá trị trả về:

<?php
// Type hinting cho tham số
function tinhTong(int $a, int $b) {
  return $a + $b;
}

echo tinhTong(5, 10);     // 15
echo tinhTong(5.5, 10.2); // 15 (tự động ép kiểu thành int)

// Return type
function layTen(): string {
  return "Nguyễn Văn A";
}

function laSoChan(int $so): bool {
  return $so % 2 == 0;
}

// Nullable type (PHP 7.1+)
function timSinhVien(int $id): ?array {
  // Trả về array hoặc null
  if ($id > 0) {
    return ["id" => $id, "ten" => "SV $id"];
  }
  return null;
}

var_dump(timSinhVien(5));   // array
var_dump(timSinhVien(-1));  // null
?>

8. Hàm đệ quy (Recursive Function)

Hàm gọi chính nó để giải quyết bài toán:

<?php
// Ví dụ 1: Tính giai thừa
function giaiThua($n) {
  if ($n <= 1) {
    return 1;  // Điểm dừng
  }
  return $n * giaiThua($n - 1);
}

echo giaiThua(5);  // 120 (5 * 4 * 3 * 2 * 1)

/*
Giải thích:
giaiThua(5) = 5 * giaiThua(4)
            = 5 * 4 * giaiThua(3)
            = 5 * 4 * 3 * giaiThua(2)
            = 5 * 4 * 3 * 2 * giaiThua(1)
            = 5 * 4 * 3 * 2 * 1
            = 120
*/

// Ví dụ 2: Dãy Fibonacci
function fibonacci($n) {
  if ($n <= 1) {
    return $n;
  }
  return fibonacci($n - 1) + fibonacci($n - 2);
}

// In 10 số Fibonacci đầu tiên
for ($i = 0; $i < 10; $i++) {
  echo fibonacci($i) . " ";
}
// Kết quả: 0 1 1 2 3 5 8 13 21 34
?>

⚠️ Lưu ý: Hàm đệ quy phải có điểm dừng (base case), nếu không sẽ gây lỗi tràn bộ nhớ (stack overflow).

9. Hàm ẩn danh (Anonymous Function)

Hàm không có tên, thường dùng làm callback:

<?php
// Gán hàm ẩn danh vào biến
$chao = function($ten) {
  echo "Xin chào, $ten!";
};

$chao("An");  // Xin chào, An!

// Dùng làm callback
$mang = [1, 2, 3, 4, 5];

$mang_binh_phuong = array_map(function($so) {
  return $so * $so;
}, $mang);

print_r($mang_binh_phuong);  // [1, 4, 9, 16, 25]

// Lọc số chẵn
$so_chan = array_filter($mang, function($so) {
  return $so % 2 == 0;
});

print_r($so_chan);  // [2, 4]
?>

9.1. Arrow Function (PHP 7.4+)

<?php
// Cú pháp ngắn gọn hơn
$mang = [1, 2, 3, 4, 5];

// Arrow function
$binh_phuong = array_map(fn($x) => $x * $x, $mang);
print_r($binh_phuong);  // [1, 4, 9, 16, 25]

// So sánh
$tong = 10;

// Anonymous function: Cần 'use'
$cong1 = function($x) use ($tong) {
  return $x + $tong;
};

// Arrow function: Tự động access biến ngoài
$cong2 = fn($x) => $x + $tong;

echo $cong1(5);  // 15
echo $cong2(5);  // 15
?>

10. Một số hàm built-in hữu ích

10.1. Hàm xử lý chuỗi

<?php
$text = "Lập Trình Không Khó";

echo strlen($text);              // 22 (độ dài)
echo strtoupper($text);          // LẬP TRÌNH KHÔNG KHÓ
echo strtolower($text);          // lập trình không khó
echo str_replace("Khó", "Dễ", $text);  // Lập Trình Không Dễ

$email = "  test@email.com  ";
echo trim($email);               // test@email.com (xóa khoảng trắng)
?>

10.2. Hàm xử lý mảng

<?php
$mang = [3, 1, 4, 1, 5, 9];

echo count($mang);        // 6
echo max($mang);          // 9
echo min($mang);          // 1
echo array_sum($mang);    // 23

sort($mang);              // Sắp xếp tăng dần
print_r($mang);           // [1, 1, 3, 4, 5, 9]

$mang2 = [1, 2, 3];
array_push($mang2, 4, 5); // Thêm vào cuối
print_r($mang2);          // [1, 2, 3, 4, 5]
?>

10.3. Hàm xử lý ngày tháng

<?php
echo date("d/m/Y");           // 06/05/2026
echo date("H:i:s");           // 14:30:45
echo date("l, d F Y");        // Wednesday, 06 May 2026

$timestamp = strtotime("2026-12-31");
echo date("d/m/Y", $timestamp);  // 31/12/2026

// Tính số ngày giữa 2 ngày
$ngay1 = strtotime("2026-01-01");
$ngay2 = strtotime("2026-12-31");
$so_ngay = ($ngay2 - $ngay1) / (60 * 60 * 24);
echo "Số ngày: $so_ngay";  // 364
?>

11. Ví dụ tổng hợp

11.1. Hệ thống xác thực đơn giản

<?php
function kiemTraEmail($email) {
  return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

function kiemTraMatKhau($mat_khau) {
  // Ít nhất 8 ký tự, có chữ và số
  if (strlen($mat_khau) < 8) {
    return false;
  }
  
  if (!preg_match('/[a-zA-Z]/', $mat_khau)) {
    return false;
  }
  
  if (!preg_match('/[0-9]/', $mat_khau)) {
    return false;
  }
  
  return true;
}

function dangKy($email, $mat_khau) {
  if (!kiemTraEmail($email)) {
    return "Email không hợp lệ";
  }
  
  if (!kiemTraMatKhau($mat_khau)) {
    return "Mật khẩu phải có ít nhất 8 ký tự, gồm chữ và số";
  }
  
  // Lưu vào database (giả lập)
  return "Đăng ký thành công!";
}

echo dangKy("test@email.com", "pass123");
?>

11.2. Tính toán hóa đơn

<?php
function tinhThue($tien, $thue_suat = 10) {
  return $tien * ($thue_suat / 100);
}

function tinhGiamGia($tien, $ma_giam_gia = "") {
  $muc_giam = [
    "SALE10" => 10,
    "SALE20" => 20,
    "VIP30" => 30
  ];
  
  if (isset($muc_giam[$ma_giam_gia])) {
    return $tien * ($muc_giam[$ma_giam_gia] / 100);
  }
  
  return 0;
}

function tinhTongHoaDon($tien_hang, $ma_giam_gia = "") {
  $giam_gia = tinhGiamGia($tien_hang, $ma_giam_gia);
  $sau_giam = $tien_hang - $giam_gia;
  $thue = tinhThue($sau_giam);
  $tong = $sau_giam + $thue;
  
  return [
    "tien_hang" => $tien_hang,
    "giam_gia" => $giam_gia,
    "sau_giam" => $sau_giam,
    "thue" => $thue,
    "tong_cong" => $tong
  ];
}

$hoa_don = tinhTongHoaDon(1000000, "SALE20");

echo "Tiền hàng: " . number_format($hoa_don['tien_hang']) . " VNĐ<br>";
echo "Giảm giá: " . number_format($hoa_don['giam_gia']) . " VNĐ<br>";
echo "Thuế VAT: " . number_format($hoa_don['thue']) . " VNĐ<br>";
echo "<strong>Tổng cộng: " . number_format($hoa_don['tong_cong']) . " VNĐ</strong>";
?>

Tóm tắt

Qua bài này bạn đã nắm được:

  • Hàm trong PHP là khối code có tên, thực hiện nhiệm vụ cụ thể, tái sử dụng được
  • ✅ Cú pháp: function ten_ham($tham_so) { ... }
  • Tham số: Truyền dữ liệu vào hàm, có thể có giá trị mặc định
  • Return: Trả về kết quả từ hàm, dùng return $gia_tri;
  • Scope: Biến trong hàm là cục bộ, dùng global để truy cập biến toàn cục
  • Tham chiếu: Dùng & để truyền tham số theo tham chiếu
  • Type hinting: Khai báo kiểu dữ liệu tham số và return type (PHP 7+)
  • Hàm đệ quy: Hàm gọi chính nó, cần có điểm dừng
  • Anonymous function: Hàm không tên, dùng làm callback
  • Arrow function: Cú pháp ngắn gọn fn($x) => $x * 2 (PHP 7.4+)

Bài tiếp theo, bạn sẽ học về mảng trong PHP để lưu trữ và xử lý nhiều dữ liệu cùng lúc.

🎯 Bài tập thực hành

  1. Bài 1: Viết hàm laSoNguyenTo($n) kiểm tra số nguyên tố. Hàm trả về true nếu là số nguyên tố, false nếu không.
  2. Bài 2: Viết hàm formatTien($so) format số thành dạng tiền tệ VNĐ. VD: formatTien(1500000) → "1,500,000 VNĐ"
  3. Bài 3: Viết hàm tinhDiemTB($diem_array) nhận mảng điểm, trả về:
    • Điểm trung bình
    • Điểm cao nhất
    • Điểm thấp nhất

Gợi ý Bài 1:

<?php
function laSoNguyenTo($n) {
  if ($n < 2) {
    return false;
  }
  
  for ($i = 2; $i <= sqrt($n); $i++) {
    if ($n % $i == 0) {
      return false;
    }
  }
  
  return true;
}

// Test
var_dump(laSoNguyenTo(7));   // true
var_dump(laSoNguyenTo(10));  // false
var_dump(laSoNguyenTo(13));  // true
?>

Gợi ý Bài 2:

<?php
function formatTien($so) {
  return number_format($so, 0, ',', '.') . " VNĐ";
}

echo formatTien(1500000);   // 1,500,000 VNĐ
echo formatTien(250000);    // 250,000 VNĐ
?>

Gợi ý Bài 3:

<?php
function tinhDiemTB($diem_array) {
  if (empty($diem_array)) {
    return null;
  }
  
  $trung_binh = array_sum($diem_array) / count($diem_array);
  $cao_nhat = max($diem_array);
  $thap_nhat = min($diem_array);
  
  return [
    "trung_binh" => round($trung_binh, 2),
    "cao_nhat" => $cao_nhat,
    "thap_nhat" => $thap_nhat
  ];
}

$diem = [7.5, 8.0, 6.5, 9.0, 8.5];
$ket_qua = tinhDiemTB($diem);

echo "Điểm TB: " . $ket_qua['trung_binh'] . "<br>";
echo "Cao nhất: " . $ket_qua['cao_nhat'] . "<br>";
echo "Thấp nhất: " . $ket_qua['thap_nhat'];
?>

Để lại bình luận

Email của bạn sẽ không được hiển thị.