کش کردن و بهینه‌سازی عملکرد در PHP

۱۴۰۵/۰۸/۱۳ | چهارشنبه، ۱۳ آبان
دوره آموزشی ویژه 4 اپیزود اول تمام دوره های آموزشی ویدیویی رایگان میباشد دانلود رایگان

دورهٔ جامع CSS از صفر

آموزش CSS از صفر در ۲۲ ویدیو: مدل جعبه، انتخاب‌گر، فلکس‌باکس، گرید، واکنش‌گرایی، متغیرها، انیمیشن و معماری، تا پروژهٔ کامل صفحهٔ محصول؛ کد کنار خروجی ...

مدرس دوره : تیم 22 اپیزود ویدیویی 03 ساعت و 33 دقیقه و 59 ثانیه آموزش ویدیویی
متن پرونده شماره 251 - پی اچ پی
کش در PHP
محصول اورجینال INZIP
قالب وردپرس باریستا مخصوص کافه تم نسکافه ای روشن (دو زبانه)

قالب وردپرس باریستا مخصوص کافه تم نسکافه ای روشن (دو زبانه)

دانلود پوسته وردپرس باریستا؛ قالب کافیشاپ، رُستری قهوه و فروشگاه قهوه دوزبانه با منوی رومیزی، رزرو آنلاین میز با کد پیامکی و ووکامرس. طراحی اختصاصی inzip.ir

تحویل آنی آپدیت رایگان بدون قفل لایسنس پشتیبانی واقعی
۳,۹۹۰,۰۰۰ تومان ۲,۹۶۰,۰۰۰ تومان
بازدید و دانلود آنی
٪۲۶
تخفیف ویژه
سود شما
۱,۰۳۰,۰۰۰ تومان

کش کردن و بهینه‌سازی عملکرد در PHP

کش (Cache) یکی از مهم‌ترین تکنیک‌های بهینه‌سازی عملکرد است. با استفاده صحیح از کش، می‌توان سرعت اپلیکیشن را ده‌ها برابر افزایش داد.

انواع کش در PHP

انواع کش OPcache کد کامپایل شده PHP Data Cache Redis Memcached Page Cache HTML کامل صفحه Browser Cache HTTP Headers

OPcache (مهم‌ترین بهینه‌سازی)

OPcache اسکریپت‌های PHP کامپایل شده را در حافظه نگه می‌دارد:

# php.ini
[opcache]
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
opcache.fast_shutdown=1

# بررسی در PHP
var_dump(opcache_get_status());

کش ساده با File

<?php
class FileCache {
    private string $cacheDir;
    
    public function __construct(string $cacheDir = 'cache/') {
        $this->cacheDir = $cacheDir;
        if (!is_dir($cacheDir)) {
            mkdir($cacheDir, 0755, true);
        }
    }
    
    public function get(string $key): mixed {
        $file = $this->getFilePath($key);
        
        if (!file_exists($file)) {
            return null;
        }
        
        $content = file_get_contents($file);
        $data = unserialize($content);
        
        if ($data['expires'] < time()) {
            unlink($file);
            return null;
        }
        
        return $data['value'];
    }
    
    public function set(string $key, mixed $value, int $ttl = 3600): void {
        $data = [
            'value'   => $value,
            'expires' => time() + $ttl,
            'created' => time()
        ];
        
        file_put_contents($this->getFilePath($key), serialize($data), LOCK_EX);
    }
    
    public function delete(string $key): void {
        $file = $this->getFilePath($key);
        if (file_exists($file)) unlink($file);
    }
    
    public function flush(): void {
        $files = glob($this->cacheDir . '*');
        foreach ($files as $file) {
            if (is_file($file)) unlink($file);
        }
    }
    
    private function getFilePath(string $key): string {
        return $this->cacheDir . md5($key) . '.cache';
    }
}

// استفاده
$cache = new FileCache();
$data = $cache->get('users');

if ($data === null) {
    $data = $db->query('SELECT * FROM users')->fetchAll();
    $cache->set('users', $data, 600); // 10 دقیقه
}
?>

کش با Redis

<?php
// composer require predis/predis

use Predis\Client;

class RedisCache {
    private Client $redis;
    
    public function __construct() {
        $this->redis = new Client([
            'scheme' => 'tcp',
            'host'   => '127.0.0.1',
            'port'   => 6379,
            'password' => null
        ]);
    }
    
    public function get(string $key): mixed {
        $value = $this->redis->get($key);
        return $value ? unserialize($value) : null;
    }
    
    public function set(string $key, mixed $value, int $ttl = 3600): void {
        $this->redis->setex($key, $ttl, serialize($value));
    }
    
    public function remember(string $key, int $ttl, callable $callback): mixed {
        $value = $this->get($key);
        if ($value !== null) return $value;
        
        $value = $callback();
        $this->set($key, $value, $ttl);
        return $value;
    }
    
    public function delete(string $key): void {
        $this->redis->del([$key]);
    }
    
    public function has(string $key): bool {
        return $this->redis->exists($key) > 0;
    }
    
    public function flush(): void {
        $this->redis->flushdb();
    }
    
    // Cache Tags (Redis Sets)
    public function tag(string $tag): TaggedCache {
        return new TaggedCache($this->redis, $tag);
    }
}

// استفاده ساده
$cache = new RedisCache();
$users = $cache->remember('all_users', 600, function() use ($db) {
    return $db->query('SELECT * FROM users')->fetchAll();
});
?>

کش با Memcached

<?php
$memcached = new Memcached();
$memcached->addServer('localhost', 11211);

$key = 'product_123';
$data = $memcached->get($key);

if ($data === false) {
    $data = $db->query(...);
    $memcached->set($key, $data, 600);
}

$memcached->delete($key);
?>

Pattern: Cache Aside

<?php
function getUserPosts(int $userId): array {
    $cacheKey = "user:{$userId}:posts";
    
    $cache = new RedisCache();
    $posts = $cache->get($cacheKey);
    
    if ($posts !== null) {
        return $posts; // cache hit
    }
    
    // cache miss - از دیتابیس بخوان
    $posts = $db->prepare('SELECT * FROM posts WHERE user_id = ?');
    $posts->execute([$userId]);
    $posts = $posts->fetchAll();
    
    // در کش ذخیره کن
    $cache->set($cacheKey, $posts, 300);
    
    return $posts;
}

// هنگام به‌روزرسانی، کش را پاک کن
function updateUserPost(int $postId): void {
    // به‌روزرسانی دیتابیس
    $db->prepare('UPDATE posts SET ... WHERE id = ?')->execute([$postId]);
    
    // پاک کردن کش مرتبط
    $cache = new RedisCache();
    $cache->tag('user_posts')->flush();
}
?>

کش Query با APCu

<?php
// APCu برای سرور محلی، سریع‌تر از Redis
function getConfig(string $key): mixed {
    $cacheKey = "config:{$key}";
    
    $cached = apcu_fetch($cacheKey, $success);
    if ($success) return $cached;
    
    $value = $db->query('SELECT value FROM settings WHERE key = ?', [$key]);
    
    apcu_store($cacheKey, $value, 3600);
    
    return $value;
}

// حذف همه
apcu_clear_cache();
?>

کش HTTP و Browser

<?php
// Cache-Control Headers
header('Cache-Control: public, max-age=3600');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT');

// ETag
$etag = md5($content);
header("ETag: $etag");

if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && 
    $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) {
    http_response_code(304);
    exit;
}

// کش صفحه HTML کامل
function cacheFullPage(int $ttl = 300): void {
    $url = $_SERVER['REQUEST_URI'];
    $cacheFile = "cache/pages/" . md5($url) . '.html';
    
    if (file_exists($cacheFile) && 
        filemtime($cacheFile) > time() - $ttl) {
        readfile($cacheFile);
        exit;
    }
    
    ob_start();
    // ... محتوای صفحه
    $content = ob_get_clean();
    
    if (!is_dir('cache/pages')) mkdir('cache/pages', 0755, true);
    file_put_contents($cacheFile, $content);
    
    echo $content;
}
?>

بهینه‌سازی Composer Autoloader

# در production
composer dump-autoload -o --classmap-authoritative

# بدون dev dependencies
composer install --no-dev --optimize-autoloader

بهینه‌سازی دیتابیس

<?php
// استفاده از JOIN به جای چند Query
$users = $db->query('
    SELECT u.*, p.title as last_post_title
    FROM users u
    LEFT JOIN posts p ON p.user_id = u.id
    WHERE u.active = 1
    GROUP BY u.id
')->fetchAll();

// Eager Loading
$posts = $db->query('SELECT * FROM posts LIMIT 50')->fetchAll();
$userIds = array_unique(array_column($posts, 'user_id'));

$users = $db->query(
    'SELECT * FROM users WHERE id IN (' . 
    implode(',', array_fill(0, count($userIds), '?')) . ')'
)->execute($userIds)->fetchAll();

// به جای N+1 Query
foreach ($posts as &$post) {
    $post['user'] = $users[$post['user_id']] ?? null;
}
?>

نکات مهم

  • Cache Invalidation: سخت‌ترین مشکل!
  • TTL مناسب: بسته به نوع داده
  • Cache Key معنادار: شامل پارامترها
  • Cache Stampede: برای داده‌های پرطرفدار
  • پاکسازی دوره‌ای: جلوگیری از رشد بی‌رویه

نتیجه‌گیری

کش کردن یکی از مؤثرترین راه‌های بهبود عملکرد است. با انتخاب استراتژی مناسب و پیاده‌سازی صحیح، می‌توانید سرعت اپلیکیشن را چندین برابر افزایش دهید.

برچسب‌های این مقاله
  • PHP cache
  • Redis
  • Memcached
  • OPcache
  • performance
  • cache aside
٪۴۱
دوره اختصاصی INZIP

دورهٔ جامع HTML از صفر

آموزش حرفه ای HTML از صفر در ۱۶ ویدیو: سند، متن، لینک، تصویر، جدول، فرم، معنایی‌سازی، دسترس‌پذیری و سئو، تا پروژهٔ کامل صفحهٔ فروشگاه محصول.

تماشای آنلاین + دانلود دسترسی آنی و همیشگی به‌روزرسانی رایگان کیفیت Full HD
۹۹۰,۰۰۰ تومان ۵۹۰,۰۰۰ تومان سود شما ۴۰۰,۰۰۰ تومان
مشاهده سریال