1. Khái niệm

Biến tĩnh cục bộ là biến được khai báo bên trong hàm với từ khóa static trong PHP.
Điểm đặc biệt:

  • chỉ tồn tại bên trong hàm (cục bộ).
  • Giá trị được giữ nguyên giữa các lần gọi hàm trong cùng một request.
  • Khác với biến cục bộ bình thường, biến tĩnh không bị khởi tạo lại mỗi lần gọi hàm.

2. Cú pháp

function myFunction() {
    static $var = initial_value;
    // ...
}

3. Ví dụ cơ bản

function counter() {
    static $count = 0; // Chỉ khởi tạo một lần
    $count++;
    echo $count . PHP_EOL;
}

counter(); // 1
counter(); // 2
counter(); // 3

Giải thích:

  • Lần đầu gọi hàm, $count được khởi tạo bằng 0.
  • Sau đó $count được tăng lên và giữ nguyên cho các lần gọi tiếp theo.
  • Không bị reset về 0 như biến cục bộ bình thường.

4. So sánh với biến cục bộ thông thường

function normalCounter() {
    $count = 0; // Luôn khởi tạo lại mỗi lần gọi
    $count++;
    echo $count . PHP_EOL;
}

normalCounter(); // 1
normalCounter(); // 1
normalCounter(); // 1

Kết quả luôn là 1$count bị reset mỗi lần gọi hàm.


5. Phạm vi sống (lifetime) của biến tĩnh

  • Biến tĩnh cục bộ chỉ sống trong phạm vi 1 request PHP.
  • Khi request kết thúc, biến sẽ mất giá trị.
  • không lưu qua nhiều request (khác với cache hoặc session).

6. Ứng dụng thực tế

a) Cache kết quả trong một hàm (giảm số lần xử lý nặng hoặc query DB)

function getConfig() {
    static $config = null;

    if ($config === null) {
        echo "Đang load config từ file...n";
        $config = parse_ini_file('config.ini');
    }

    return $config;
}

getConfig(); // Load từ file
getConfig(); // Lấy từ cache trong hàm, không load lại

b) Đếm số lần gọi hàm

function logAccess() {
    static $times = 0;
    $times++;
    echo "Hàm được gọi {$times} lầnn";
}

logAccess();
logAccess();
logAccess();

c) Giữ trạng thái giữa các lần gọi hàm

Ví dụ trong class xử lý dữ liệu, bạn không muốn lưu vào property của class nhưng vẫn cần giữ giá trị trong hàm.


7. Ưu điểm

  • Hiệu suất tốt hơn khi tránh lặp lại các thao tác nặng (query DB, đọc file, xử lý phức tạp).
  • Không cần dùng biến toàn cục hoặc property của class.
  • Giữ code gọn gàng, phạm vi hẹp → khó bị thay đổi ngoài ý muốn.

8. Nhược điểm

  • Chỉ có tác dụng trong cùng một request.
  • Nếu lạm dụng, có thể gây khó hiểu cho người đọc code (vì giá trị biến thay đổi "ngầm" giữa các lần gọi).
  • Không thể reset biến tĩnh từ bên ngoài hàm.

9. Khi nào nên dùng

  • Khi muốn cache tạm thời trong 1 request.
  • Khi cần giữ trạng thái nhỏ giữa các lần gọi hàm.
  • Khi muốn tránh query DB hoặc xử lý lặp lại trong 1 request.

10. Khi nào không nên dùng

  • Khi cần lưu dữ liệu qua nhiều request → dùng Session, APCu, Redis, Database.
  • Khi biến có thể gây xung đột logic nếu bị giữ giá trị giữa các lần gọi.
  • Khi muốn code minh bạch và dễ debug (tránh thay đổi "ngầm").

Tóm lại:
Biến tĩnh cục bộ trong PHP rất hữu ích để cache kết quả tạm thời trong 1 request hoặc giữ trạng thái nội bộ của hàm. Tuy nhiên, cần dùng hợp lý và nhớ rằng nó không lưu qua nhiều request.

Vài ví dụ về lưu dữ liệu cache bằng biến tĩnh cục bộ để tận dụng tối đa nó trong PHP, đặc biệt là trong bối cảnh như CodeIgniter hoặc WordPress.


11. Cache danh sách cột bảng (giống case của bạn)

function get_user_fields_without_pass() {
    static $fields = null;

    if ($fields === null) {
        // Lần đầu query để lấy danh sách cột
        $all_fields = $this->db->list_fields('wp_users');
        $fields = array_diff($all_fields, ['user_pass']);
    }

    return $fields; // Các lần sau trả từ cache
}

// Sử dụng
$this->db->select(implode(',', get_user_fields_without_pass()));
$this->db->from('wp_users');

💡 Lợi ích: list_fields() chỉ chạy 1 lần trong suốt request.


12. Cache dữ liệu user

function get_user_by_email($email) {
    static $cache = []; // cache theo email

    if (isset($cache[$email])) {
        return $cache[$email]; // trả từ cache
    }

    $user = $this->db->get_where('wp_users', ['user_email' => $email])->row_array();
    unset($user['user_pass']); // bỏ pass

    $cache[$email] = $user; // lưu vào cache

    return $user;
}

💡 Lợi ích: Nếu cùng một request cần lấy thông tin user đó nhiều lần, sẽ không query DB lại.


13. Cache dữ liệu cấu hình (config)

function get_config() {
    static $config = null;

    if ($config === null) {
        echo "Đang load config...n";
        $config = parse_ini_file('app.ini');
    }

    return $config;
}

// Gọi nhiều lần
get_config(); // load từ file
get_config(); // lấy từ cache

💡 Lợi ích: File chỉ được đọc 1 lần duy nhất.


14. Cache kết quả xử lý nặng

function fibonacci($n) {
    static $cache = [];

    if (isset($cache[$n])) {
        return $cache[$n]; // trả từ cache
    }

    if ($n < 2) {
        return $n;
    }

    $cache[$n] = fibonacci($n - 1) + fibonacci($n - 2);
    return $cache[$n];
}

echo fibonacci(40); // Lần đầu chậm
echo fibonacci(40); // Lần sau gần như ngay lập tức

💡 Lợi ích: Giảm thời gian tính toán đệ quy cực lớn.


15. Cache danh sách category

function get_categories() {
    static $categories = null;

    if ($categories === null) {
        $categories = $this->db->get('wp_terms')->result_array();
    }

    return $categories;
}

💡 Lợi ích: Nếu nhiều hàm cần danh sách category trong cùng request, chỉ query DB 1 lần.


📌 Nhớ: Cache bằng static chỉ tồn tại trong cùng 1 request.
Nếu muốn giữ qua nhiều request, bạn phải dùng APCu, Redis, Memcached hoặc file cache.