Kotchasan Framework Documentation

Kotchasan Framework Documentation

FileCache - File-based Cache

TH 05 Feb 2026 06:23

FileCache - File-based Cache

ภาพรวม

FileCache เป็น Cache driver ที่เก็บข้อมูลในรูปแบบไฟล์บนระบบไฟล์ เป็น Cache driver ที่ไม่ต้องติดตั้งซอฟต์แวร์เพิ่มเติม และเหมาะสำหรับเว็บไซต์ขนาดเล็กถึงกลาง

คุณสมบัติหลัก

  • No Dependencies: ไม่ต้องติดตั้งซอฟต์แวร์เพิ่มเติม
  • TTL Support: รองรับ Time To Live (TTL)
  • Serialization: เก็บข้อมูลประเภทใดก็ได้ด้วย serialization
  • Directory Management: จัดการโฟลเดอร์ cache อัตโนมัติ
  • Thread Safe: ปลอดภัยสำหรับการใช้งานแบบ concurrent
  • Batch Operations: รองรับการทำงานกับหลาย keys พร้อมกัน

การติดตั้งและการใช้งาน

การสร้าง FileCache Instance

use Kotchasan\Cache\FileCache;

// สร้าง FileCache พื้นฐาน
$cache = new FileCache('/var/cache/myapp');

// ตรวจสอบสิทธิ์และสร้างโฟลเดอร์อัตโนมัติ
try {
    $cache = new FileCache('/var/cache/secure');
} catch (ConfigurationException $e) {
    echo "Cache configuration error: " . $e->getMessage();
}

การใช้งานพื้นฐาน

// เก็บข้อมูลใน cache
$cache->set('user:123', [
    'id' => 123,
    'name' => 'John Doe',
    'email' => 'john@example.com'
], 3600); // TTL 1 ชั่วโมง

// ดึงข้อมูลจาก cache
$userData = $cache->get('user:123');

// ตรวจสอบว่ามี cache หรือไม่
if ($cache->has('user:123')) {
    $userData = $cache->get('user:123');
} else {
    // โหลดข้อมูลจากแหล่งอื่น
    $userData = loadUserFromDatabase(123);
    $cache->set('user:123', $userData, 3600);
}

// ลบ cache
$cache->delete('user:123');

// ล้าง cache ทั้งหมด
$cache->clear();

เมธอดหลักของ FileCache

__construct(string $cacheDir)

สร้าง FileCache instance และตั้งค่าโฟลเดอร์ cache

// โฟลเดอร์ที่มีอยู่แล้ว
$cache = new FileCache('/existing/cache/directory');

// โฟลเดอร์ที่ยังไม่มี (จะสร้างอัตโนมัติ)
$cache = new FileCache('/new/cache/directory');

// จะเกิด ConfigurationException ถ้าไม่สามารถสร้างโฟลเดอร์ได้

set(string $key, $value, ?int $ttl = null): bool

เก็บข้อมูลใน cache

// เก็บข้อมูล string
$cache->set('message', 'Hello World', 300); // 5 นาที

// เก็บข้อมูล array
$cache->set('config', [
    'debug' => true,
    'version' => '1.0.0',
    'features' => ['auth', 'api', 'cache']
], 3600);

// เก็บข้อมูล object
$user = new stdClass();
$user->id = 123;
$user->name = 'John';
$cache->set('user_object', $user, 1800);

// เก็บไม่มี TTL (ไม่หมดอายุ)
$cache->set('permanent_data', 'This will not expire');

get(string $key, $default = null)

ดึงข้อมูลจาก cache

// ดึงข้อมูลพื้นฐาน
$value = $cache->get('message');

// ดึงข้อมูลพร้อม default value
$config = $cache->get('config', [
    'debug' => false,
    'version' => '1.0.0'
]);

// ตรวจสอบประเภทข้อมูล
$userData = $cache->get('user:123');
if (is_array($userData)) {
    echo "User name: " . $userData['name'];
}

has(string $key): bool

ตรวจสอบว่ามี cache key หรือไม่

if ($cache->has('user:123')) {
    $user = $cache->get('user:123');
    echo "Found user in cache";
} else {
    echo "User not in cache";
}

// ใช้ร่วมกับ lazy loading
function getConfig($section) {
    global $cache;

    $key = "config:{$section}";
    if (!$cache->has($key)) {
        $config = loadConfigFromFile($section);
        $cache->set($key, $config, 3600);
        return $config;
    }

    return $cache->get($key);
}

delete(string $key): bool

ลบ cache key

use Kotchasan\Database;

// ลบ cache เดียว
$deleted = $cache->delete('user:123');

if ($deleted) {
    echo "Cache deleted successfully";
} else {
    echo "Cache key not found";
}

// ลบ cache เมื่อข้อมูลเปลี่ยน
function updateUser($userId, $data) {
    // อัปเดตฐานข้อมูล
    Kotchasan\Database::create()
        ->update('users')
        ->set($data)
        ->where(['id', $userId])
        ->execute();

    // ลบ cache ที่เกี่ยวข้อง
    global $cache;
    $cache->delete("user:{$userId}");
    $cache->delete("user_profile:{$userId}");
}

clear(): bool

ล้าง cache ทั้งหมด

// ล้าง cache ทั้งหมด
$cache->clear();

// ใช้ในการทำความสะอาดระบบ
function maintenanceCleanup() {
    global $cache;

    echo "Clearing all cache...";
    if ($cache->clear()) {
        echo "Cache cleared successfully";
    } else {
        echo "Failed to clear cache";
    }
}

Batch Operations

setMultiple(array $values, ?int $ttl = null): bool

เก็บข้อมูลหลาย keys พร้อมกัน

// เก็บข้อมูลหลาย users
$users = [
    'user:123' => ['name' => 'John', 'email' => 'john@example.com'],
    'user:124' => ['name' => 'Jane', 'email' => 'jane@example.com'],
    'user:125' => ['name' => 'Bob', 'email' => 'bob@example.com']
];

$cache->setMultiple($users, 3600);

// เก็บ configuration หลายส่วน
$configs = [
    'app:database' => ['host' => 'localhost', 'port' => 3306],
    'app:redis' => ['host' => 'redis-server', 'port' => 6379],
    'app:email' => ['smtp' => 'smtp.gmail.com', 'port' => 587]
];

$cache->setMultiple($configs, 86400); // 24 ชั่วโมง;

getMultiple(array $keys, $default = null): array

ดึงข้อมูลหลาย keys พร้อมกัน

// ดึงข้อมูล users หลายคน
$userIds = ['user:123', 'user:124', 'user:125'];
$users = $cache->getMultiple($userIds);

foreach ($users as $key => $user) {
    if ($user !== null) {
        echo "User {$key}: " . $user['name'] . "\n";
    }
}

// ดึงข้อมูลพร้อม default values
$configKeys = ['app:database', 'app:redis', 'app:email'];
$configs = $cache->getMultiple($configKeys, []);

// ตรวจสอบข้อมูลที่ได้
foreach ($configs as $key => $config) {
    if (empty($config)) {
        echo "Config {$key} not found in cache\n";
    }
}

deleteMultiple(array $keys): bool

ลบหลาย keys พร้อมกัน

// ลบ cache users หลายคน
$userKeys = ['user:123', 'user:124', 'user:125'];
$cache->deleteMultiple($userKeys);

// ลบ cache ที่เกี่ยวข้องกับ feature
$featureKeys = [
    'feature_flags:auth',
    'feature_flags:api',
    'feature_flags:notifications'
];
$cache->deleteMultiple($featureKeys);

ตัวอย่างการใช้งานในโปรเจกต์จริง

1. User Profile Cache

use Kotchasan\Database;

class UserProfileCache {
    private $cache;

    public function __construct() {
        $this->cache = new FileCache('/var/cache/user_profiles');
    }

    public function getProfile($userId) {
        $cacheKey = "profile:{$userId}";

        $profile = $this->cache->get($cacheKey);
        if ($profile === null) {
            $profile = $this->loadProfileFromDatabase($userId);
            if ($profile) {
                $this->cache->set($cacheKey, $profile, 1800); // 30 นาที
            }
        }

        return $profile;
    }

    public function updateProfile($userId, $data) {
        // อัปเดตฐานข้อมูล
        $this->updateProfileInDatabase($userId, $data);

        // ลบ cache
        $this->cache->delete("profile:{$userId}");

        // โหลดข้อมูลใหม่และ cache
        return $this->getProfile($userId);
    }

    public function preloadProfiles($userIds) {
        $cacheKeys = array_map(function($id) {
            return "profile:{$id}";
        }, $userIds);

        $cachedProfiles = $this->cache->getMultiple($cacheKeys);
        $missingIds = [];

        foreach ($userIds as $userId) {
            $key = "profile:{$userId}";
            if ($cachedProfiles[$key] === null) {
                $missingIds[] = $userId;
            }
        }

        if (!empty($missingIds)) {
            $profiles = $this->loadMultipleProfilesFromDatabase($missingIds);
            $cacheData = [];

            foreach ($profiles as $profile) {
                $cacheData["profile:{$profile['id']}"] = $profile;
            }

            $this->cache->setMultiple($cacheData, 1800);
        }
    }

    private function loadProfileFromDatabase($userId) {
        return Kotchasan\Database::create()
            ->select(['id', 'name', 'email', 'avatar', 'settings'])
            ->from('user_profiles')
            ->where(['user_id', $userId])
            ->first();
    }

    private function loadMultipleProfilesFromDatabase($userIds) {
        return Kotchasan\Database::create()
            ->select(['id', 'name', 'email', 'avatar', 'settings'])
            ->from('user_profiles')
            ->where(['user_id', $userIds])
            ->fetchAll();
    }
}

2. Configuration Cache

class ConfigCache {
    private $cache;
    private $configPath;

    public function __construct($configPath = '/etc/myapp') {
        $this->cache = new FileCache('/var/cache/config');
        $this->configPath = $configPath;
    }

    public function get($section, $key = null) {
        $cacheKey = "config:{$section}";

        $config = $this->cache->get($cacheKey);
        if ($config === null) {
            $configFile = $this->configPath . "/{$section}.php";
            if (file_exists($configFile)) {
                $config = include $configFile;
                $this->cache->set($cacheKey, $config, 3600); // 1 ชั่วโมง
            } else {
                $config = [];
            }
        }

        if ($key !== null) {
            return $config[$key] ?? null;
        }

        return $config;
    }

    public function refresh($section = null) {
        if ($section) {
            $this->cache->delete("config:{$section}");
        } else {
            // ลบ config cache ทั้งหมด
            $this->clearConfigCache();
        }
    }

    public function warmup() {
        $configFiles = glob($this->configPath . '/*.php');
        $configs = [];

        foreach ($configFiles as $file) {
            $section = basename($file, '.php');
            $config = include $file;
            $configs["config:{$section}"] = $config;
        }

        $this->cache->setMultiple($configs, 3600);
    }

    private function clearConfigCache() {
        // ในการใช้งานจริงอาจต้องใช้ pattern matching
        // หรือเก็บรายการ config sections ไว้
        $sections = ['database', 'redis', 'email', 'app'];
        $keys = array_map(function($section) {
            return "config:{$section}";
        }, $sections);

        $this->cache->deleteMultiple($keys);
    }
}

// การใช้งาน
$config = new ConfigCache();

// ดึง config section
$dbConfig = $config->get('database');

// ดึง config key เฉพาะ
$dbHost = $config->get('database', 'host');

// Refresh config
$config->refresh('database');

// Warmup cache
$config->warmup();
*/

3. Page Cache

class PageCache {
    private $cache;

    public function __construct() {
        $this->cache = new FileCache('/var/cache/pages');
    }

    public function get($url, $params = []) {
        $cacheKey = $this->generateCacheKey($url, $params);
        return $this->cache->get($cacheKey);
    }

$ttl = 360; // 0) {
        $cacheKey = $this->generateCacheKey($url, $params);
        return $this->cache->set($cacheKey, [
            'content' => $content,
            'cached_at' => time(),
            'url' => $url,
            'params' => $params
        ], $ttl);
    }

    public function invalidate($url, $params = []) {
        $cacheKey = $this->generateCacheKey($url, $params);
        return $this->cache->delete($cacheKey);
    }

    public function invalidatePattern($pattern) {
        // ในการใช้งานจริงอาจต้องเก็บ metadata ของ cache keys
        // หรือใช้ directory structure เพื่อง่ายต่อการลบ

        // ตัวอย่างการลบ cache ทั้งหมดที่เกี่ยวข้องกับ user
        if (strpos($pattern, 'user:') === 0) {
            $userId = substr($pattern, 5);
            $keysToDelete = [
                "page:user/{$userId}",
                "page:user/{$userId}/profile",
                "page:user/{$userId}/settings"
            ];

            $this->cache->deleteMultiple($keysToDelete);
        }
    }

    private function generateCacheKey($url, $params) {
        $key = 'page:' . $url;
        if (!empty($params)) {
            ksort($params);
            $key .= ':' . md5(serialize($params));
        }
        return $key;
    }
}

// Middleware สำหรับ cache pages
function pageCacheMiddleware($request, $response) {
    $pageCache = new PageCache();
    $url = $request->getUri()->getPath();
    $params = $request->getQueryParams();

    // ตรวจสอบ cache
    $cachedPage = $pageCache->get($url, $params);
    if ($cachedPage !== null) {
        $response->getBody()->write($cachedPage['content']);
        return $response->withHeader('X-Cache', 'HIT');
    }

    // ประมวลผล request
    $response = $next($request, $response);

    // เก็บ response ใน cache
    $content = (string) $response->getBody();
    $pageCache->set($url, $content, $params, 1800); // 30 นาที

    return $response->withHeader('X-Cache', 'MISS');
}

Performance และ Best Practices

1. Cache Key Naming

// ใช้ namespace pattern
$userKey = "user:{$userId}";
$productKey = "product:{$productId}";
$categoryKey = "category:{$categoryId}:products";

// รวม parameters ใน key
$searchKey = "search:" . md5(serialize([
    'query' => $query,
    'filters' => $filters,
    'sort' => $sort,
    'page' => $page
]));

2. Cache Expiration Strategy

// TTL แยกตามประเภทข้อมูล
$cache->set('user_profile:123', $profile, 1800);    // 30 นาที
$cache->set('product_list', $products, 900);        // 15 นาที
$cache->set('site_config', $config, 86400);         // 1 วัน
$cache->set('session_data', $session, 7200);        // 2 ชั่วโมง;

3. Error Handling

$ttl = 360; // 0) {
    try {
        if ($cache->has($key)) {
            return $cache->get($key);
        }

        $data = $loader();
        $cache->set($key, $data, $ttl);

        return $data;

    } catch (Exception $e) {
        error_log("Cache error for key {$key}: " . $e->getMessage());

        // คืนค่าข้อมูลโดยไม่ใช้ cache
        return $loader();
    }
}

4. Cache Monitoring

class FileCacheMonitor {
    private $cache;
    private $stats = [
        'hits' => 0,
        'misses' => 0,
        'sets' => 0,
        'deletes' => 0
    ];

    public function __construct(FileCache $cache) {
        $this->cache = $cache;
    }

    public function get($key, $default = null) {
        if ($this->cache->has($key)) {
            $this->stats['hits']++;
            return $this->cache->get($key, $default);
        } else {
            $this->stats['misses']++;
            return $default;
        }
    }

    public function set($key, $value, $ttl = null) {
        $this->stats['sets']++;
        return $this->cache->set($key, $value, $ttl);
    }

    public function delete($key) {
        $this->stats['deletes']++;
        return $this->cache->delete($key);
    }

    public function getStats() {
        $total = $this->stats['hits'] + $this->stats['misses'];
        return array_merge($this->stats, [
            'total_requests' => $total,
            'hit_ratio' => $total > 0 ? ($this->stats['hits'] / $total) * 100 : 0
        ]);
    }
}

FileCache เป็น Cache driver ที่เหมาะสำหรับการใช้งานทั่วไป ไม่ต้องพึ่งพาระบบภายนอก และสามารถให้ประสิทธิภาพที่ดีสำหรับเว็บไซต์ขนาดเล็กถึงกลาง