تحسين أداء تطبيقات PHP: استراتيجيات متقدمة
تحسين أداء تطبيقات PHP: استراتيجيات متقدمة
دليل متخصص من علاء عامر - مطور ومصمم مواقع وتطبيقات احترافية
تحسين الأداء هو جانب حاسم في تطوير تطبيقات PHP الناجحة. سرعة التطبيق تؤثر مباشرة على تجربة المستخدم وترتيب محركات البحث.
2️⃣ تحسين إعدادات PHP
أهم إعدادات php.ini للأداء:
; php.ini للإنتاج
; الذاكرة
memory_limit = 512M
max_execution_time = 30
max_input_time = 60
; OPcache (أهم شيء لتحسين الأداء)
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 12
opcache.max_accelerated_files = 60000
opcache.revalidate_freq = 0
opcache.validate_timestamps = 0 ; للإنتاج فقط
opcache.save_comments = 0
opcache.fast_shutdown = 1
; تحسين Session
session.save_handler = redis
session.save_path = "tcp://localhost:6379"
; إيقاف الأخطاء في الإنتاج
display_errors = 0
error_reporting = E_ALL & ~E_NOTICE & ~E_WARNING
log_errors = 1
error_log = /var/log/php_errors.log
; تحسين رفع الملفات
post_max_size = 50M
upload_max_filesize = 50M
max_file_uploads = 20
; تحسين الشبكة
default_socket_timeout = 5
فئة لمراقبة الأداء:
<?php
// classes/PerformanceMonitor.php
class PerformanceMonitor
{
private static $startTime;
private static $startMemory;
private static $queries = [];
private static $checkpoints = [];
public static function start()
{
self::$startTime = microtime(true);
self::$startMemory = memory_get_usage(true);
}
public static function checkpoint($name)
{
self::$checkpoints[$name] = [
'time' => microtime(true) - self::$startTime,
'memory' => memory_get_usage(true) - self::$startMemory,
'peak_memory' => memory_get_peak_usage(true)
];
}
public static function logQuery($sql, $executionTime)
{
self::$queries[] = [
'sql' => $sql,
'time' => $executionTime,
'timestamp' => microtime(true)
];
}
public static function getReport()
{
$totalTime = microtime(true) - self::$startTime;
$totalMemory = memory_get_usage(true) - self::$startMemory;
$peakMemory = memory_get_peak_usage(true);
return [
'total_execution_time' => round($totalTime * 1000, 2) . 'ms',
'memory_usage' => self::formatBytes($totalMemory),
'peak_memory' => self::formatBytes($peakMemory),
'query_count' => count(self::$queries),
'queries' => self::$queries,
'checkpoints' => self::$checkpoints,
'opcache_status' => function_exists('opcache_get_status') ? opcache_get_status() : null
];
}
private static function formatBytes($bytes)
{
$units = ['B', 'KB', 'MB', 'GB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
return round($bytes / (1024 ** $pow), 2) . ' ' . $units[$pow];
}
public static function profileFunction($callback, $name = 'anonymous')
{
$startTime = microtime(true);
$startMemory = memory_get_usage(true);
$result = call_user_func($callback);
$endTime = microtime(true);
$endMemory = memory_get_usage(true);
error_log(sprintf(
"Profile [%s]: Time: %.2fms, Memory: %s",
$name,
($endTime - $startTime) * 1000,
self::formatBytes($endMemory - $startMemory)
));
return $result;
}
}
// الاستخدام
PerformanceMonitor::start();
// في بداية العملية
PerformanceMonitor::checkpoint('after_bootstrap');
// عند الانتهاء
PerformanceMonitor::checkpoint('before_response');
$report = PerformanceMonitor::getReport();
4️⃣ نظام Caching متقدم
Redis Cache Implementation:
<?php
// classes/CacheManager.php
class CacheManager
{
private $redis;
private $defaultTtl = 3600; // ساعة واحدة
private $keyPrefix = 'app:';
public function __construct($redisHost = 'localhost', $redisPort = 6379)
{
$this->redis = new Redis();
$this->redis->connect($redisHost, $redisPort);
}
public function get($key, $default = null)
{
$value = $this->redis->get($this->keyPrefix . $key);
if ($value === false) {
return $default;
}
return json_decode($value, true);
}
public function set($key, $value, $ttl = null)
{
$ttl = $ttl ?? $this->defaultTtl;
$encodedValue = json_encode($value);
return $this->redis->setex($this->keyPrefix . $key, $ttl, $encodedValue);
}
public function remember($key, $callback, $ttl = null)
{
$value = $this->get($key);
if ($value !== null) {
return $value;
}
$value = call_user_func($callback);
$this->set($key, $value, $ttl);
return $value;
}
public function forget($key)
{
return $this->redis->del($this->keyPrefix . $key);
}
public function flush()
{
$keys = $this->redis->keys($this->keyPrefix . '*');
if (!empty($keys)) {
return $this->redis->del($keys);
}
return true;
}
// Cache Tags للتجميع
public function tags($tags)
{
return new TaggedCache($this, (array)$tags);
}
// Cache بناءً على العمليات
public function cacheQuery($sql, $params, $callback, $ttl = 600)
{
$key = 'query:' . md5($sql . serialize($params));
return $this->remember($key, $callback, $ttl);
}
// Cache للصفحات الكاملة
public function cachePage($uri, $callback, $ttl = 1800)
{
$key = 'page:' . md5($uri);
return $this->remember($key, $callback, $ttl);
}
}
class TaggedCache
{
private $cache;
private $tags;
public function __construct(CacheManager $cache, array $tags)
{
$this->cache = $cache;
$this->tags = $tags;
}
public function get($key, $default = null)
{
return $this->cache->get($this->taggedKey($key), $default);
}
public function set($key, $value, $ttl = null)
{
$taggedKey = $this->taggedKey($key);
// إضافة المفتاح لكل tag
foreach ($this->tags as $tag) {
$this->cache->redis->sadd("tag:{$tag}", $taggedKey);
}
return $this->cache->set($taggedKey, $value, $ttl);
}
public function flush()
{
foreach ($this->tags as $tag) {
$keys = $this->cache->redis->smembers("tag:{$tag}");
if (!empty($keys)) {
$this->cache->redis->del($keys);
$this->cache->redis->del("tag:{$tag}");
}
}
}
private function taggedKey($key)
{
return 'tagged:' . implode(':', $this->tags) . ':' . $key;
}
}
نظام File Cache للبيانات الثقيلة:
<?php
// classes/FileCache.php
class FileCache
{
private $cacheDir;
private $defaultTtl = 3600;
public function __construct($cacheDir = 'cache')
{
$this->cacheDir = rtrim($cacheDir, '/');
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0755, true);
}
}
public function get($key, $default = null)
{
$filename = $this->getFilename($key);
if (!file_exists($filename)) {
return $default;
}
$data = file_get_contents($filename);
$cached = unserialize($data);
// التحقق من انتهاء الصلاحية
if ($cached['expires'] > 0 && $cached['expires'] < time()) {
unlink($filename);
return $default;
}
return $cached['value'];
}
public function set($key, $value, $ttl = null)
{
$ttl = $ttl ?? $this->defaultTtl;
$expires = $ttl > 0 ? time() + $ttl : 0;
$cached = [
'value' => $value,
'expires' => $expires,
'created' => time()
];
$filename = $this->getFilename($key);
$this->ensureDirectoryExists(dirname($filename));
return file_put_contents($filename, serialize($cached), LOCK_EX) !== false;
}
public function delete($key)
{
$filename = $this->getFilename($key);
if (file_exists($filename)) {
return unlink($filename);
}
return true;
}
public function clear()
{
$this->deleteDirectory($this->cacheDir);
mkdir($this->cacheDir, 0755, true);
return true;
}
// Cache للصور المصغرة
public function cacheImage($originalPath, $width, $height, $quality = 80)
{
$key = "image:" . md5($originalPath . $width . $height . $quality);
$filename = $this->getFilename($key, 'jpg');
if (file_exists($filename) && filemtime($filename) > filemtime($originalPath)) {
return $filename;
}
// إنشاء صورة مصغرة
$this->createThumbnail($originalPath, $filename, $width, $height, $quality);
return $filename;
}
private function getFilename($key, $extension = 'cache')
{
$hash = md5($key);
$dir1 = substr($hash, 0, 2);
$dir2 = substr($hash, 2, 2);
return "{$this->cacheDir}/{$dir1}/{$dir2}/{$hash}.{$extension}";
}
private function ensureDirectoryExists($dir)
{
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
}
private function deleteDirectory($dir)
{
if (!is_dir($dir)) {
return true;
}
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . '/' . $file;
is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
}
return rmdir($dir);
}
private function createThumbnail($source, $destination, $width, $height, $quality)
{
$imageInfo = getimagesize($source);
$srcWidth = $imageInfo[0];
$srcHeight = $imageInfo[1];
$mimeType = $imageInfo['mime'];
// إنشاء resource حسب نوع الصورة
switch ($mimeType) {
case 'image/jpeg':
$srcImage = imagecreatefromjpeg($source);
break;
case 'image/png':
$srcImage = imagecreatefrompng($source);
break;
case 'image/gif':
$srcImage = imagecreatefromgif($source);
break;
default:
return false;
}
// حساب الأبعاد الجديدة مع الحفاظ على النسب
$aspectRatio = $srcWidth / $srcHeight;
if ($width / $height > $aspectRatio) {
$width = $height * $aspectRatio;
} else {
$height = $width / $aspectRatio;
}
// إنشاء الصورة الجديدة
$destImage = imagecreatetruecolor($width, $height);
imagecopyresampled($destImage, $srcImage, 0, 0, 0, 0, $width, $height, $srcWidth, $srcHeight);
// حفظ الصورة
$this->ensureDirectoryExists(dirname($destination));
imagejpeg($destImage, $destination, $quality);
// تحرير الذاكرة
imagedestroy($srcImage);
imagedestroy($destImage);
return true;
}
}
6️⃣ HTTP Response Optimization
<?php
// classes/ResponseOptimizer.php
class ResponseOptimizer
{
public static function enableGzipCompression()
{
if (!headers_sent() && extension_loaded('zlib') && !ob_get_length()) {
ini_set('zlib.output_compression', 'On');
ini_set('zlib.output_compression_level', 6);
}
}
public static function setCacheHeaders($maxAge = 3600, $etag = null)
{
if (headers_sent()) return;
// Cache Control
header("Cache-Control: public, max-age={$maxAge}");
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $maxAge) . ' GMT');
// ETag
if ($etag) {
header("ETag: \"{$etag}\"");
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
$_SERVER['HTTP_IF_NONE_MATCH'] === "\"{$etag}\"") {
http_response_code(304);
exit;
}
}
// Last Modified
$lastModified = gmdate('D, d M Y H:i:s', time()) . ' GMT';
header("Last-Modified: {$lastModified}");
}
public static function optimizeImages($imagePath, $quality = 80)
{
if (!file_exists($imagePath)) {
return false;
}
$imageInfo = getimagesize($imagePath);
$mimeType = $imageInfo['mime'];
// تحقق من دعم المتصفح لـ WebP
$supportsWebP = strpos($_SERVER['HTTP_ACCEPT'] ?? '', 'image/webp') !== false;
if ($supportsWebP && $mimeType !== 'image/webp') {
$webpPath = preg_replace('/\.[^.]+$/', '.webp', $imagePath);
if (!file_exists($webpPath) || filemtime($imagePath) > filemtime($webpPath)) {
self::convertToWebP($imagePath, $webpPath, $quality);
}
if (file_exists($webpPath)) {
return $webpPath;
}
}
return $imagePath;
}
private static function convertToWebP($source, $destination, $quality)
{
$imageInfo = getimagesize($source);
$mimeType = $imageInfo['mime'];
switch ($mimeType) {
case 'image/jpeg':
$image = imagecreatefromjpeg($source);
break;
case 'image/png':
$image = imagecreatefrompng($source);
break;
default:
return false;
}
if ($image) {
imagewebp($image, $destination, $quality);
imagedestroy($image);
return true;
}
return false;
}
public static function sendOptimizedResponse($content, $contentType = 'text/html')
{
self::enableGzipCompression();
$etag = md5($content);
self::setCacheHeaders(3600, $etag);
header("Content-Type: {$contentType}; charset=utf-8");
header('Content-Length: ' . strlen($content));
echo $content;
}
}
💡 نصائح سريعة لتحسين الأداء
- استخدم OPcache دائماً - يحسن الأداء بنسبة 50-80%
- قم بالـ Profiling المنتظم - استخدم Xdebug أو Blackfire
- حسن استعلامات قاعدة البيانات - استخدم EXPLAIN لفهم الاستعلامات
- طبق Lazy Loading - لا تحمل البيانات إلا عند الحاجة
- استخدم CDN للملفات الثابتة
- فعل HTTP/2 لتحسين تحميل الأصول المتعددة
الخطوة التالية
تعلم Load Balancing و Microservices Architecture للتطبيقات الكبيرة.
📩 تحتاج مساعدة في تحسين أداء تطبيقك؟
قسم المقالة
تحسين أداء تطبيقات PHP: استراتيجيات متقدمة
دليل شامل لتحسين أداء تطبيقات PHP مع تقنيات الـ caching، تحسين قواعد البيانات، وأفضل الممارسات.
التواصل والاستشارة
تواصل مباشر عبر الواتساب أو الهاتف لفهم احتياجات مشروعك بدقة.
التخطيط والجدولة
وضع خطة عمل واضحة مع جدول زمني محدد لكل مرحلة من المشروع.
البرمجة والتطوير
تطوير المشروع بأحدث التقنيات لضمان الأداء والأمان العاليين.
المراجعة والتسليم
ختبار شامل ومراجعة دقيقة قبل التسليم النهائي للمشروع.