1. php
  2. /advanced
  3. /performance

Performance Optimization in PHP

Introduction to PHP Performance

Performance optimization is crucial for creating fast, scalable PHP applications. This guide covers profiling techniques, caching strategies, database optimization, memory management, and best practices for high-performance PHP applications.

Performance Fundamentals

Understanding Performance Metrics

  1. Response Time: Time to complete a request
  2. Throughput: Requests handled per second
  3. Memory Usage: RAM consumption
  4. CPU Usage: Processing power utilization
  5. I/O Operations: File and database access

Common Performance Bottlenecks

  1. Database Queries: Slow or excessive queries
  2. File I/O: Disk read/write operations
  3. Memory Leaks: Inefficient memory usage
  4. CPU-Intensive Operations: Complex calculations
  5. Network Latency: External API calls

Profiling and Benchmarking

Built-in PHP Profiling

<?php
class PerformanceProfiler
{
    private static $timers = [];
    private static $memorySnapshots = [];
    
    public static function start(string $name): void
    {
        self::$timers[$name] = [
            'start_time' => microtime(true),
            'start_memory' => memory_get_usage(true)
        ];
    }
    
    public static function end(string $name): array
    {
        if (!isset(self::$timers[$name])) {
            throw new InvalidArgumentException("Timer '{$name}' not found");
        }
        
        $timer = self::$timers[$name];
        $endTime = microtime(true);
        $endMemory = memory_get_usage(true);
        
        $result = [
            'name' => $name,
            'duration' => $endTime - $timer['start_time'],
            'memory_used' => $endMemory - $timer['start_memory'],
            'peak_memory' => memory_get_peak_usage(true)
        ];
        
        unset(self::$timers[$name]);
        return $result;
    }
    
    public static function measure(callable $callback, string $name = 'anonymous'): array
    {
        self::start($name);
        $result = $callback();
        $metrics = self::end($name);
        $metrics['result'] = $result;
        
        return $metrics;
    }
    
    public static function memorySnapshot(string $label): void
    {
        self::$memorySnapshots[$label] = [
            'usage' => memory_get_usage(true),
            'peak' => memory_get_peak_usage(true),
            'timestamp' => microtime(true)
        ];
    }
    
    public static function getMemoryReport(): array
    {
        return self::$memorySnapshots;
    }
    
    public static function formatBytes(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB'];
        $i = 0;
        
        while ($bytes >= 1024 && $i < count($units) - 1) {
            $bytes /= 1024;
            $i++;
        }
        
        return round($bytes, 2) . ' ' . $units[$i];
    }
}

// Usage example
PerformanceProfiler::start('database_query');
// Simulate database operation
usleep(100000); // 100ms
$dbMetrics = PerformanceProfiler::end('database_query');

echo "Database Query Performance:\n";
echo "Duration: " . round($dbMetrics['duration'] * 1000, 2) . "ms\n";
echo "Memory: " . PerformanceProfiler::formatBytes($dbMetrics['memory_used']) . "\n";

// Measure function performance
$result = PerformanceProfiler::measure(function() {
    return array_sum(range(1, 100000));
}, 'array_sum_operation');

echo "Array Sum Performance:\n";
echo "Duration: " . round($result['duration'] * 1000, 2) . "ms\n";
echo "Result: " . $result['result'] . "\n";
?>

Advanced Profiling with Xdebug

<?php
class XdebugProfiler
{
    public static function startProfiling(): void
    {
        if (extension_loaded('xdebug')) {
            xdebug_start_trace();
        }
    }
    
    public static function stopProfiling(): void
    {
        if (extension_loaded('xdebug')) {
            xdebug_stop_trace();
        }
    }
    
    public static function getMemoryUsage(): array
    {
        if (!extension_loaded('xdebug')) {
            return [];
        }
        
        return [
            'current' => xdebug_memory_usage(),
            'peak' => xdebug_peak_memory_usage(),
            'time' => xdebug_time_index()
        ];
    }
    
    public static function analyzeFunction(callable $function, array $args = []): array
    {
        $startTime = microtime(true);
        $startMemory = memory_get_usage();
        
        $result = call_user_func_array($function, $args);
        
        $endTime = microtime(true);
        $endMemory = memory_get_usage();
        
        return [
            'result' => $result,
            'execution_time' => $endTime - $startTime,
            'memory_delta' => $endMemory - $startMemory,
            'peak_memory' => memory_get_peak_usage()
        ];
    }
}

// Benchmark different approaches
function benchmarkArrayOperations(): void
{
    $data = range(1, 10000);
    
    // Method 1: foreach
    $foreach = XdebugProfiler::analyzeFunction(function() use ($data) {
        $sum = 0;
        foreach ($data as $value) {
            $sum += $value;
        }
        return $sum;
    });
    
    // Method 2: array_sum
    $arraySum = XdebugProfiler::analyzeFunction(function() use ($data) {
        return array_sum($data);
    });
    
    // Method 3: array_reduce
    $arrayReduce = XdebugProfiler::analyzeFunction(function() use ($data) {
        return array_reduce($data, function($carry, $item) {
            return $carry + $item;
        }, 0);
    });
    
    echo "Performance Comparison:\n";
    echo "Foreach: " . round($foreach['execution_time'] * 1000, 2) . "ms\n";
    echo "Array Sum: " . round($arraySum['execution_time'] * 1000, 2) . "ms\n";
    echo "Array Reduce: " . round($arrayReduce['execution_time'] * 1000, 2) . "ms\n";
}

benchmarkArrayOperations();
?>

Caching Strategies

File-Based Caching

<?php
class FileCache
{
    private string $cacheDir;
    private int $defaultTtl;
    
    public function __construct(string $cacheDir = 'cache', int $defaultTtl = 3600)
    {
        $this->cacheDir = rtrim($cacheDir, '/');
        $this->defaultTtl = $defaultTtl;
        
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0755, true);
        }
    }
    
    public function get(string $key, $default = null)
    {
        $filename = $this->getFilename($key);
        
        if (!file_exists($filename)) {
            return $default;
        }
        
        $data = unserialize(file_get_contents($filename));
        
        if ($data['expires'] < time()) {
            unlink($filename);
            return $default;
        }
        
        return $data['value'];
    }
    
    public function set(string $key, $value, int $ttl = null): bool
    {
        $ttl = $ttl ?? $this->defaultTtl;
        $filename = $this->getFilename($key);
        
        $data = [
            'value' => $value,
            'expires' => time() + $ttl,
            'created' => time()
        ];
        
        return file_put_contents($filename, serialize($data), LOCK_EX) !== false;
    }
    
    public function delete(string $key): bool
    {
        $filename = $this->getFilename($key);
        
        if (file_exists($filename)) {
            return unlink($filename);
        }
        
        return true;
    }
    
    public function clear(): int
    {
        $files = glob($this->cacheDir . '/*');
        $deleted = 0;
        
        foreach ($files as $file) {
            if (is_file($file) && unlink($file)) {
                $deleted++;
            }
        }
        
        return $deleted;
    }
    
    public function remember(string $key, callable $callback, int $ttl = null)
    {
        $value = $this->get($key);
        
        if ($value === null) {
            $value = $callback();
            $this->set($key, $value, $ttl);
        }
        
        return $value;
    }
    
    private function getFilename(string $key): string
    {
        return $this->cacheDir . '/' . md5($key) . '.cache';
    }
    
    public function getStats(): array
    {
        $files = glob($this->cacheDir . '/*');
        $totalSize = 0;
        $expiredFiles = 0;
        
        foreach ($files as $file) {
            if (is_file($file)) {
                $totalSize += filesize($file);
                
                $data = unserialize(file_get_contents($file));
                if ($data['expires'] < time()) {
                    $expiredFiles++;
                }
            }
        }
        
        return [
            'total_files' => count($files),
            'total_size' => $totalSize,
            'expired_files' => $expiredFiles,
            'cache_directory' => $this->cacheDir
        ];
    }
}

// Usage
$cache = new FileCache('storage/cache');

// Cache expensive operation
$expensiveData = $cache->remember('user_stats', function() {
    // Simulate expensive operation
    sleep(2);
    return ['users' => 1000, 'posts' => 5000];
}, 1800); // Cache for 30 minutes

print_r($expensiveData);
?>

Redis Caching

<?php
class RedisCache
{
    private Redis $redis;
    private string $prefix;
    
    public function __construct(string $host = '127.0.0.1', int $port = 6379, string $prefix = 'app:')
    {
        $this->redis = new Redis();
        $this->redis->connect($host, $port);
        $this->prefix = $prefix;
    }
    
    public function get(string $key, $default = null)
    {
        $value = $this->redis->get($this->prefix . $key);
        
        if ($value === false) {
            return $default;
        }
        
        return unserialize($value);
    }
    
    public function set(string $key, $value, int $ttl = 3600): bool
    {
        return $this->redis->setex($this->prefix . $key, $ttl, serialize($value));
    }
    
    public function delete(string $key): bool
    {
        return $this->redis->del($this->prefix . $key) > 0;
    }
    
    public function flush(): bool
    {
        return $this->redis->flushAll();
    }
    
    public function increment(string $key, int $value = 1): int
    {
        return $this->redis->incrBy($this->prefix . $key, $value);
    }
    
    public function decrement(string $key, int $value = 1): int
    {
        return $this->redis->decrBy($this->prefix . $key, $value);
    }
    
    public function remember(string $key, callable $callback, int $ttl = 3600)
    {
        $value = $this->get($key);
        
        if ($value === null) {
            $value = $callback();
            $this->set($key, $value, $ttl);
        }
        
        return $value;
    }
    
    public function tags(array $tags): self
    {
        // Implementation for tag-based cache invalidation
        return $this;
    }
    
    public function getStats(): array
    {
        $info = $this->redis->info();
        
        return [
            'used_memory' => $info['used_memory_human'] ?? 'N/A',
            'total_commands_processed' => $info['total_commands_processed'] ?? 'N/A',
            'connected_clients' => $info['connected_clients'] ?? 'N/A',
            'uptime_in_seconds' => $info['uptime_in_seconds'] ?? 'N/A'
        ];
    }
}

// Advanced caching patterns
class CacheManager
{
    private $cache;
    
    public function __construct($cache)
    {
        $this->cache = $cache;
    }
    
    public function cacheAside(string $key, callable $loader, int $ttl = 3600)
    {
        // Cache-aside pattern
        $data = $this->cache->get($key);
        
        if ($data === null) {
            $data = $loader();
            $this->cache->set($key, $data, $ttl);
        }
        
        return $data;
    }
    
    public function writeThrough(string $key, $data, callable $writer, int $ttl = 3600)
    {
        // Write-through pattern
        $result = $writer($data);
        
        if ($result) {
            $this->cache->set($key, $data, $ttl);
        }
        
        return $result;
    }
    
    public function writeBehind(string $key, $data, int $ttl = 3600): void
    {
        // Write-behind pattern (simplified)
        $this->cache->set($key, $data, $ttl);
        
        // Queue for later persistence
        $this->queueForPersistence($key, $data);
    }
    
    private function queueForPersistence(string $key, $data): void
    {
        // Add to background job queue
        // Implementation depends on your queue system
    }
}
?>

OpCode Caching (OPcache)

<?php
class OPcacheManager
{
    public static function getStatus(): array
    {
        if (!extension_loaded('Zend OPcache')) {
            return ['status' => 'OPcache not available'];
        }
        
        $status = opcache_get_status();
        $config = opcache_get_configuration();
        
        return [
            'enabled' => $status['opcache_enabled'],
            'cache_full' => $status['cache_full'],
            'restart_pending' => $status['restart_pending'],
            'restart_in_progress' => $status['restart_in_progress'],
            'memory_usage' => $status['memory_usage'],
            'opcache_statistics' => $status['opcache_statistics'],
            'configuration' => $config['directives']
        ];
    }
    
    public static function reset(): bool
    {
        if (function_exists('opcache_reset')) {
            return opcache_reset();
        }
        
        return false;
    }
    
    public static function invalidate(string $script, bool $force = false): bool
    {
        if (function_exists('opcache_invalidate')) {
            return opcache_invalidate($script, $force);
        }
        
        return false;
    }
    
    public static function getOptimizationReport(): array
    {
        $status = self::getStatus();
        
        if (!isset($status['memory_usage'])) {
            return [];
        }
        
        $memory = $status['memory_usage'];
        $stats = $status['opcache_statistics'];
        
        return [
            'hit_rate' => round(($stats['hits'] / ($stats['hits'] + $stats['misses'])) * 100, 2),
            'memory_utilization' => round(($memory['used_memory'] / $memory['free_memory']) * 100, 2),
            'cached_scripts' => $stats['num_cached_scripts'],
            'cached_keys' => $stats['num_cached_keys'],
            'max_cached_keys' => $stats['max_cached_keys']
        ];
    }
}

// Display OPcache statistics
$opcacheStats = OPcacheManager::getOptimizationReport();
if (!empty($opcacheStats)) {
    echo "OPcache Performance:\n";
    echo "Hit Rate: {$opcacheStats['hit_rate']}%\n";
    echo "Memory Utilization: {$opcacheStats['memory_utilization']}%\n";
    echo "Cached Scripts: {$opcacheStats['cached_scripts']}\n";
}
?>

Database Optimization

Query Optimization

<?php
class DatabaseOptimizer
{
    private PDO $pdo;
    private array $queryLog = [];
    
    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }
    
    public function executeWithProfiling(string $sql, array $params = []): array
    {
        $startTime = microtime(true);
        $startMemory = memory_get_usage();
        
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $endTime = microtime(true);
        $endMemory = memory_get_usage();
        
        $this->queryLog[] = [
            'sql' => $sql,
            'params' => $params,
            'execution_time' => $endTime - $startTime,
            'memory_used' => $endMemory - $startMemory,
            'row_count' => count($result),
            'timestamp' => date('Y-m-d H:i:s')
        ];
        
        return $result;
    }
    
    public function explain(string $sql, array $params = []): array
    {
        $explainSql = "EXPLAIN " . $sql;
        $stmt = $this->pdo->prepare($explainSql);
        $stmt->execute($params);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    public function analyzeSlowQueries(float $threshold = 0.1): array
    {
        return array_filter($this->queryLog, function($query) use ($threshold) {
            return $query['execution_time'] > $threshold;
        });
    }
    
    public function suggestIndexes(string $sql): array
    {
        $suggestions = [];
        
        // Simple pattern matching for common optimization opportunities
        if (preg_match('/WHERE\s+(\w+)\s*=/', $sql, $matches)) {
            $suggestions[] = "Consider adding an index on column: {$matches[1]}";
        }
        
        if (preg_match('/ORDER\s+BY\s+(\w+)/', $sql, $matches)) {
            $suggestions[] = "Consider adding an index on column: {$matches[1]} for sorting";
        }
        
        if (preg_match('/JOIN\s+\w+\s+ON\s+\w+\.(\w+)\s*=\s*\w+\.(\w+)/', $sql, $matches)) {
            $suggestions[] = "Ensure indexes exist on join columns: {$matches[1]}, {$matches[2]}";
        }
        
        return $suggestions;
    }
    
    public function getQueryStats(): array
    {
        if (empty($this->queryLog)) {
            return [];
        }
        
        $totalTime = array_sum(array_column($this->queryLog, 'execution_time'));
        $totalMemory = array_sum(array_column($this->queryLog, 'memory_used'));
        $totalQueries = count($this->queryLog);
        
        return [
            'total_queries' => $totalQueries,
            'total_time' => $totalTime,
            'average_time' => $totalTime / $totalQueries,
            'total_memory' => $totalMemory,
            'average_memory' => $totalMemory / $totalQueries,
            'slowest_query' => max($this->queryLog)
        ];
    }
}

// Connection pooling simulation
class ConnectionPool
{
    private array $connections = [];
    private array $config;
    private int $maxConnections;
    
    public function __construct(array $config, int $maxConnections = 10)
    {
        $this->config = $config;
        $this->maxConnections = $maxConnections;
    }
    
    public function getConnection(): PDO
    {
        // Return existing connection if available
        if (!empty($this->connections)) {
            return array_pop($this->connections);
        }
        
        // Create new connection if under limit
        if (count($this->connections) < $this->maxConnections) {
            return new PDO(
                $this->config['dsn'],
                $this->config['username'],
                $this->config['password'],
                [
                    PDO::ATTR_PERSISTENT => true,
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
                ]
            );
        }
        
        throw new Exception('Connection pool exhausted');
    }
    
    public function releaseConnection(PDO $connection): void
    {
        $this->connections[] = $connection;
    }
}
?>

Database Query Optimization Patterns

<?php
class OptimizedRepository
{
    private PDO $pdo;
    private $cache;
    
    public function __construct(PDO $pdo, $cache)
    {
        $this->pdo = $pdo;
        $this->cache = $cache;
    }
    
    // N+1 Query Problem Solution
    public function getUsersWithPosts(): array
    {
        // Bad: N+1 queries
        // $users = $this->getUsers();
        // foreach ($users as &$user) {
        //     $user['posts'] = $this->getPostsByUserId($user['id']);
        // }
        
        // Good: Single query with JOIN
        $sql = "
            SELECT 
                u.id, u.name, u.email,
                p.id as post_id, p.title, p.content
            FROM users u
            LEFT JOIN posts p ON u.id = p.user_id
            ORDER BY u.id, p.id
        ";
        
        $stmt = $this->pdo->query($sql);
        $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // Group results by user
        $users = [];
        foreach ($results as $row) {
            $userId = $row['id'];
            
            if (!isset($users[$userId])) {
                $users[$userId] = [
                    'id' => $row['id'],
                    'name' => $row['name'],
                    'email' => $row['email'],
                    'posts' => []
                ];
            }
            
            if ($row['post_id']) {
                $users[$userId]['posts'][] = [
                    'id' => $row['post_id'],
                    'title' => $row['title'],
                    'content' => $row['content']
                ];
            }
        }
        
        return array_values($users);
    }
    
    // Pagination with efficient counting
    public function getPaginatedUsers(int $page = 1, int $perPage = 20): array
    {
        $offset = ($page - 1) * $perPage;
        
        // Use SQL_CALC_FOUND_ROWS for efficient counting
        $sql = "
            SELECT SQL_CALC_FOUND_ROWS 
                id, name, email, created_at
            FROM users 
            ORDER BY created_at DESC 
            LIMIT :limit OFFSET :offset
        ";
        
        $stmt = $this->pdo->prepare($sql);
        $stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
        $stmt->execute();
        
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // Get total count
        $countStmt = $this->pdo->query("SELECT FOUND_ROWS() as total");
        $total = $countStmt->fetch(PDO::FETCH_ASSOC)['total'];
        
        return [
            'data' => $users,
            'total' => $total,
            'page' => $page,
            'per_page' => $perPage,
            'total_pages' => ceil($total / $perPage)
        ];
    }
    
    // Cached queries
    public function getCachedUserStats(): array
    {
        return $this->cache->remember('user_stats', function() {
            $sql = "
                SELECT 
                    COUNT(*) as total_users,
                    COUNT(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 1 END) as new_users_30_days,
                    COUNT(CASE WHEN last_login >= DATE_SUB(NOW(), INTERVAL 7 DAY) THEN 1 END) as active_users_7_days
                FROM users
            ";
            
            $stmt = $this->pdo->query($sql);
            return $stmt->fetch(PDO::FETCH_ASSOC);
        }, 300); // Cache for 5 minutes
    }
    
    // Batch operations
    public function batchInsertUsers(array $users): bool
    {
        $sql = "INSERT INTO users (name, email, created_at) VALUES ";
        $values = [];
        $params = [];
        
        foreach ($users as $index => $user) {
            $values[] = "(:name_{$index}, :email_{$index}, :created_at_{$index})";
            $params["name_{$index}"] = $user['name'];
            $params["email_{$index}"] = $user['email'];
            $params["created_at_{$index}"] = date('Y-m-d H:i:s');
        }
        
        $sql .= implode(', ', $values);
        
        $stmt = $this->pdo->prepare($sql);
        return $stmt->execute($params);
    }
}
?>

Memory Optimization

Memory Management Best Practices

<?php
class MemoryOptimizer
{
    public static function processLargeDataset(string $filename): array
    {
        $stats = [];
        $handle = fopen($filename, 'r');
        
        if (!$handle) {
            throw new Exception("Cannot open file: {$filename}");
        }
        
        $lineCount = 0;
        $totalSize = 0;
        
        // Process file line by line to avoid loading entire file into memory
        while (($line = fgets($handle)) !== false) {
            $lineCount++;
            $totalSize += strlen($line);
            
            // Process line here
            unset($line); // Explicitly free memory
            
            // Periodic garbage collection for long-running processes
            if ($lineCount % 1000 === 0) {
                gc_collect_cycles();
            }
        }
        
        fclose($handle);
        
        return [
            'lines_processed' => $lineCount,
            'total_size' => $totalSize,
            'memory_used' => memory_get_usage(true),
            'peak_memory' => memory_get_peak_usage(true)
        ];
    }
    
    public static function optimizedArrayProcessing(array $data): array
    {
        $result = [];
        
        // Use generators for memory-efficient processing
        foreach (self::processChunks($data, 100) as $chunk) {
            $processed = array_map('strtoupper', $chunk);
            $result = array_merge($result, $processed);
            
            // Free chunk memory
            unset($chunk, $processed);
        }
        
        return $result;
    }
    
    private static function processChunks(array $data, int $chunkSize): Generator
    {
        $chunks = array_chunk($data, $chunkSize);
        
        foreach ($chunks as $chunk) {
            yield $chunk;
        }
    }
    
    public static function memoryEfficientCSVParser(string $filename): Generator
    {
        $handle = fopen($filename, 'r');
        
        if (!$handle) {
            throw new Exception("Cannot open CSV file: {$filename}");
        }
        
        // Read header
        $header = fgetcsv($handle);
        
        while (($row = fgetcsv($handle)) !== false) {
            yield array_combine($header, $row);
        }
        
        fclose($handle);
    }
    
    public static function monitorMemoryUsage(): array
    {
        return [
            'current_usage' => memory_get_usage(true),
            'current_usage_real' => memory_get_usage(false),
            'peak_usage' => memory_get_peak_usage(true),
            'peak_usage_real' => memory_get_peak_usage(false),
            'limit' => ini_get('memory_limit')
        ];
    }
}

// Memory-efficient data streaming
class DataStreamer
{
    private $source;
    private int $bufferSize;
    
    public function __construct($source, int $bufferSize = 8192)
    {
        $this->source = $source;
        $this->bufferSize = $bufferSize;
    }
    
    public function stream(): Generator
    {
        while (!feof($this->source)) {
            $chunk = fread($this->source, $this->bufferSize);
            if ($chunk !== false) {
                yield $chunk;
            }
        }
    }
    
    public function processLargeFile(string $filename, callable $processor): void
    {
        $handle = fopen($filename, 'r');
        $streamer = new self($handle);
        
        foreach ($streamer->stream() as $chunk) {
            $processor($chunk);
            
            // Allow garbage collection
            if (random_int(1, 100) === 1) {
                gc_collect_cycles();
            }
        }
        
        fclose($handle);
    }
}

// Example usage
$memoryBefore = memory_get_usage(true);

// Process large dataset efficiently
$csvData = MemoryOptimizer::memoryEfficientCSVParser('large_file.csv');
$processedCount = 0;

foreach ($csvData as $row) {
    // Process each row
    $processedCount++;
    
    if ($processedCount % 1000 === 0) {
        echo "Processed: {$processedCount} rows, Memory: " . 
             PerformanceProfiler::formatBytes(memory_get_usage(true)) . "\n";
    }
}

$memoryAfter = memory_get_usage(true);
echo "Memory difference: " . PerformanceProfiler::formatBytes($memoryAfter - $memoryBefore) . "\n";
?>

Code Optimization Techniques

Efficient Algorithms and Data Structures

<?php
class AlgorithmOptimizer
{
    // Optimized string operations
    public static function efficientStringConcatenation(array $strings): string
    {
        // Bad: String concatenation in loop
        // $result = '';
        // foreach ($strings as $string) {
        //     $result .= $string;
        // }
        
        // Good: Use implode for multiple strings
        return implode('', $strings);
    }
    
    // Optimized array operations
    public static function efficientArraySearch(array $haystack, $needle): bool
    {
        // Bad: in_array for large arrays
        // return in_array($needle, $haystack);
        
        // Good: Use array_flip for frequent lookups
        static $flipped = null;
        if ($flipped === null) {
            $flipped = array_flip($haystack);
        }
        
        return isset($flipped[$needle]);
    }
    
    // Optimized loop operations
    public static function efficientArrayProcessing(array $data): array
    {
        $count = count($data); // Cache count outside loop
        $result = [];
        
        // Pre-allocate array size if known
        $result = array_fill(0, $count, null);
        
        for ($i = 0; $i < $count; $i++) {
            $result[$i] = strtoupper($data[$i]);
        }
        
        return $result;
    }
    
    // Lazy loading pattern
    public static function lazyPropertyLoader(): Closure
    {
        static $cache = [];
        
        return function(string $key) use (&$cache) {
            if (!isset($cache[$key])) {
                $cache[$key] = self::expensiveOperation($key);
            }
            
            return $cache[$key];
        };
    }
    
    private static function expensiveOperation(string $key): array
    {
        // Simulate expensive operation
        usleep(100000); // 100ms
        return ['key' => $key, 'value' => uniqid()];
    }
    
    // Optimized recursive operations with memoization
    public static function fibonacci(int $n, array &$memo = []): int
    {
        if (isset($memo[$n])) {
            return $memo[$n];
        }
        
        if ($n <= 1) {
            return $n;
        }
        
        $memo[$n] = self::fibonacci($n - 1, $memo) + self::fibonacci($n - 2, $memo);
        return $memo[$n];
    }
}

// Performance testing framework
class PerformanceTester
{
    public static function compareAlgorithms(array $algorithms, array $testData): array
    {
        $results = [];
        
        foreach ($algorithms as $name => $algorithm) {
            $startTime = microtime(true);
            $startMemory = memory_get_usage();
            
            $result = $algorithm($testData);
            
            $endTime = microtime(true);
            $endMemory = memory_get_usage();
            
            $results[$name] = [
                'execution_time' => $endTime - $startTime,
                'memory_used' => $endMemory - $startMemory,
                'result' => $result
            ];
        }
        
        return $results;
    }
    
    public static function stressTest(callable $function, array $inputs, int $iterations = 100): array
    {
        $times = [];
        $memoryUsages = [];
        
        for ($i = 0; $i < $iterations; $i++) {
            $startTime = microtime(true);
            $startMemory = memory_get_usage();
            
            $function(...$inputs);
            
            $times[] = microtime(true) - $startTime;
            $memoryUsages[] = memory_get_usage() - $startMemory;
        }
        
        return [
            'average_time' => array_sum($times) / count($times),
            'min_time' => min($times),
            'max_time' => max($times),
            'average_memory' => array_sum($memoryUsages) / count($memoryUsages),
            'min_memory' => min($memoryUsages),
            'max_memory' => max($memoryUsages)
        ];
    }
}

// Example performance comparison
$testData = range(1, 1000);

$algorithms = [
    'foreach_loop' => function($data) {
        $result = [];
        foreach ($data as $item) {
            $result[] = $item * 2;
        }
        return $result;
    },
    'array_map' => function($data) {
        return array_map(function($item) {
            return $item * 2;
        }, $data);
    },
    'for_loop' => function($data) {
        $result = [];
        $count = count($data);
        for ($i = 0; $i < $count; $i++) {
            $result[] = $data[$i] * 2;
        }
        return $result;
    }
];

$comparison = PerformanceTester::compareAlgorithms($algorithms, $testData);

foreach ($comparison as $name => $stats) {
    echo "{$name}: " . round($stats['execution_time'] * 1000, 2) . "ms, " .
         PerformanceProfiler::formatBytes($stats['memory_used']) . "\n";
}
?>

Production Optimization

Server Configuration

<?php
class ProductionOptimizer
{
    public static function getOptimalSettings(): array
    {
        return [
            'php_settings' => [
                'memory_limit' => '256M',
                'max_execution_time' => 30,
                'upload_max_filesize' => '10M',
                'post_max_size' => '10M',
                'max_input_vars' => 3000,
                'realpath_cache_size' => '4M',
                'realpath_cache_ttl' => 600,
                'opcache.enable' => 1,
                'opcache.memory_consumption' => 256,
                'opcache.interned_strings_buffer' => 16,
                'opcache.max_accelerated_files' => 20000,
                'opcache.validate_timestamps' => 0, // Production
                'opcache.save_comments' => 0,
                'opcache.fast_shutdown' => 1
            ],
            'mysql_settings' => [
                'innodb_buffer_pool_size' => '70% of RAM',
                'query_cache_size' => '256M',
                'max_connections' => 1000,
                'slow_query_log' => 1,
                'long_query_time' => 2
            ]
        ];
    }
    
    public static function checkEnvironment(): array
    {
        $issues = [];
        
        // Check PHP version
        if (version_compare(PHP_VERSION, '8.0.0', '<')) {
            $issues[] = 'Consider upgrading to PHP 8+ for better performance';
        }
        
        // Check OPcache
        if (!extension_loaded('Zend OPcache')) {
            $issues[] = 'OPcache extension is not loaded';
        }
        
        // Check memory limit
        $memoryLimit = ini_get('memory_limit');
        if ($memoryLimit !== '-1' && self::parseSize($memoryLimit) < 128 * 1024 * 1024) {
            $issues[] = 'Memory limit is too low for production';
        }
        
        // Check realpath cache
        if (ini_get('realpath_cache_size') < 4194304) { // 4M
            $issues[] = 'Realpath cache size should be increased';
        }
        
        return [
            'issues' => $issues,
            'recommendations' => self::getOptimalSettings()
        ];
    }
    
    private static function parseSize(string $size): int
    {
        $unit = strtoupper(substr($size, -1));
        $value = (int) $size;
        
        switch ($unit) {
            case 'G':
                $value *= 1024;
                // fallthrough
            case 'M':
                $value *= 1024;
                // fallthrough
            case 'K':
                $value *= 1024;
        }
        
        return $value;
    }
}

// Application performance monitoring
class ApplicationMonitor
{
    private static array $metrics = [];
    
    public static function startRequest(): void
    {
        self::$metrics['request_start'] = microtime(true);
        self::$metrics['memory_start'] = memory_get_usage(true);
    }
    
    public static function endRequest(): array
    {
        $requestTime = microtime(true) - self::$metrics['request_start'];
        $memoryUsed = memory_get_usage(true) - self::$metrics['memory_start'];
        $peakMemory = memory_get_peak_usage(true);
        
        return [
            'request_time' => $requestTime,
            'memory_used' => $memoryUsed,
            'peak_memory' => $peakMemory,
            'slow_request' => $requestTime > 1.0,
            'high_memory' => $memoryUsed > 50 * 1024 * 1024 // 50MB
        ];
    }
    
    public static function logSlowQueries(array $queries): void
    {
        $slowQueries = array_filter($queries, function($query) {
            return $query['execution_time'] > 0.1; // 100ms
        });
        
        if (!empty($slowQueries)) {
            error_log('Slow queries detected: ' . json_encode($slowQueries));
        }
    }
}

// Usage in application bootstrap
ApplicationMonitor::startRequest();

// Your application code here

$performanceMetrics = ApplicationMonitor::endRequest();

if ($performanceMetrics['slow_request']) {
    error_log('Slow request detected: ' . $performanceMetrics['request_time'] . 's');
}
?>

Best Practices Summary

Code-Level Optimizations

  1. Use appropriate data structures: Arrays vs. objects for data storage
  2. Minimize database queries: Use joins, batch operations, and caching
  3. Optimize loops: Cache array counts, use efficient algorithms
  4. Memory management: Unset large variables, use generators for large datasets
  5. String operations: Use built-in functions over manual implementations

Infrastructure Optimizations

  1. Enable OPcache: Significant performance improvement for production
  2. Use connection pooling: Reduce database connection overhead
  3. Implement caching: File, memory, or distributed caching
  4. Optimize database: Proper indexing, query optimization
  5. Monitor performance: Regular profiling and monitoring

Production Deployment

  1. Disable debug features: Turn off error display, debugging tools
  2. Optimize autoloader: Use optimized class maps
  3. Configure web server: Proper PHP-FPM, Nginx/Apache settings
  4. Use CDN: Distribute static assets globally
  5. Monitor and alert: Set up performance monitoring and alerting

Performance optimization is an ongoing process that requires measurement, analysis, and iterative improvement. Always profile your application to identify actual bottlenecks before optimizing.