[PHP]set_time_limit関数を完全解説!スクリプトの実行時間制限を設定する方法

PHP

こんにちは!今回は、PHPの標準関数であるset_time_limit()について詳しく解説していきます。PHPスクリプトの最大実行時間を制御できる、重要な関数です!

set_time_limit関数とは?

set_time_limit()関数は、PHPスクリプトの最大実行時間を秒単位で設定する関数です。

デフォルトでは30秒に設定されていますが、長時間実行が必要な処理(バッチ処理、データインポート、画像処理など)では、この制限を変更する必要があります!

基本的な構文

set_time_limit(int $seconds): bool
  • $seconds: 最大実行時間(秒単位)、0で無制限
  • 戻り値: 成功時はtrue、失敗時はfalse

重要な注意点

// セーフモードが有効な場合、set_time_limit()は無効
// php.iniのmax_execution_timeの設定が優先される場合がある

// set_time_limit()は実行時間をリセット
// この関数が呼ばれた時点から新たにカウント開始

// スリープ時間は含まれない
set_time_limit(30);
sleep(10);  // この10秒は実行時間にカウントされない

// 外部プログラムの実行時間は含まれる
set_time_limit(30);
exec('long-running-command');  // この時間は含まれる

基本的な使用例

シンプルな時間制限設定

// デフォルトは30秒
echo "デフォルトの制限: " . ini_get('max_execution_time') . "秒\n";

// 60秒に設定
set_time_limit(60);
echo "新しい制限: " . ini_get('max_execution_time') . "秒\n";

// 長時間の処理
for ($i = 0; $i < 1000000; $i++) {
    // 何らかの処理
}

echo "処理完了\n";

無制限の実行時間

// 制限を解除(無制限)
set_time_limit(0);

// 非常に長い処理でもタイムアウトしない
while (true) {
    // 処理
    if ($someCondition) {
        break;
    }
}

処理の途中でリセット

// 初期設定: 60秒
set_time_limit(60);

for ($i = 0; $i < 10; $i++) {
    echo "Processing batch {$i}\n";
    
    // 各バッチの処理
    processBatch($i);
    
    // 制限時間をリセット(この時点から60秒)
    set_time_limit(60);
}

エラーハンドリング

// set_time_limit()が失敗する場合がある
if (set_time_limit(300)) {
    echo "制限時間を300秒に設定しました\n";
} else {
    echo "制限時間の設定に失敗しました\n";
    echo "セーフモードまたは無効化されている可能性があります\n";
}

// または例外処理
try {
    ini_set('max_execution_time', 300);
    set_time_limit(300);
} catch (Exception $e) {
    echo "エラー: " . $e->getMessage() . "\n";
}

実践的な使用例

例1: バッチ処理マネージャー

class BatchProcessor {
    private $timeLimit;
    private $batchSize;
    private $resetInterval;
    
    /**
     * バッチ処理を初期化
     */
    public function __construct($timeLimit = 300, $batchSize = 100, $resetInterval = 10) {
        $this->timeLimit = $timeLimit;
        $this->batchSize = $batchSize;
        $this->resetInterval = $resetInterval;
        
        // 初期の制限時間を設定
        set_time_limit($this->timeLimit);
    }
    
    /**
     * データを処理
     */
    public function process($data, $callback) {
        $total = count($data);
        $processed = 0;
        $batches = array_chunk($data, $this->batchSize);
        
        foreach ($batches as $batchIndex => $batch) {
            // バッチ処理の開始
            $startTime = microtime(true);
            
            foreach ($batch as $item) {
                call_user_func($callback, $item);
                $processed++;
            }
            
            $endTime = microtime(true);
            $elapsed = $endTime - $startTime;
            
            // 進捗を表示
            $this->showProgress($processed, $total, $elapsed);
            
            // 定期的に制限時間をリセット
            if (($batchIndex + 1) % $this->resetInterval === 0) {
                set_time_limit($this->timeLimit);
                echo " [Time limit reset]";
            }
            
            echo "\n";
        }
        
        return [
            'total' => $total,
            'processed' => $processed,
            'success' => $processed === $total
        ];
    }
    
    /**
     * 進捗を表示
     */
    private function showProgress($current, $total, $batchTime) {
        $percentage = ($current / $total) * 100;
        echo sprintf(
            "Progress: %d/%d (%.1f%%) - Batch time: %.3fs",
            $current,
            $total,
            $percentage,
            $batchTime
        );
    }
    
    /**
     * 現在の制限時間を取得
     */
    public function getTimeLimit() {
        return ini_get('max_execution_time');
    }
}

// 使用例
echo "=== バッチ処理 ===\n";

$processor = new BatchProcessor(300, 50, 5);

// テストデータを生成
$data = range(1, 500);

echo "制限時間: " . $processor->getTimeLimit() . "秒\n";
echo "総アイテム数: " . count($data) . "\n\n";

// 処理を実行
$result = $processor->process($data, function($item) {
    // 各アイテムの処理をシミュレート
    usleep(1000);  // 1ミリ秒
});

echo "\n=== 処理完了 ===\n";
echo "処理済み: {$result['processed']}/{$result['total']}\n";
echo "成功: " . ($result['success'] ? 'Yes' : 'No') . "\n";

例2: データインポートシステム

class DataImporter {
    private $maxExecutionTime;
    private $safetyMargin;
    
    /**
     * インポーターを初期化
     */
    public function __construct($maxExecutionTime = 600, $safetyMargin = 60) {
        $this->maxExecutionTime = $maxExecutionTime;
        $this->safetyMargin = $safetyMargin;
        
        // 制限時間を設定
        set_time_limit($this->maxExecutionTime);
    }
    
    /**
     * CSVファイルをインポート
     */
    public function importCsv($filename, $processor) {
        if (!file_exists($filename)) {
            throw new Exception("File not found: {$filename}");
        }
        
        $fp = fopen($filename, 'r');
        if ($fp === false) {
            throw new Exception("Failed to open file");
        }
        
        $startTime = time();
        $imported = 0;
        $errors = [];
        
        // ヘッダー行を読む
        $headers = fgetcsv($fp);
        
        while (($row = fgetcsv($fp)) !== false) {
            // 残り時間をチェック
            $elapsed = time() - $startTime;
            $remaining = $this->maxExecutionTime - $elapsed - $this->safetyMargin;
            
            if ($remaining < 0) {
                echo "\nTime limit approaching, stopping import\n";
                break;
            }
            
            try {
                // データを処理
                $data = array_combine($headers, $row);
                call_user_func($processor, $data);
                $imported++;
                
                // 100件ごとに進捗表示と制限時間リセット
                if ($imported % 100 === 0) {
                    echo "Imported: {$imported} records (Remaining: {$remaining}s)\n";
                    set_time_limit($this->maxExecutionTime);
                }
                
            } catch (Exception $e) {
                $errors[] = [
                    'row' => $imported + 1,
                    'error' => $e->getMessage()
                ];
            }
        }
        
        fclose($fp);
        
        return [
            'imported' => $imported,
            'errors' => $errors,
            'execution_time' => time() - $startTime
        ];
    }
    
    /**
     * JSONファイルをインポート
     */
    public function importJson($filename, $processor) {
        if (!file_exists($filename)) {
            throw new Exception("File not found: {$filename}");
        }
        
        $startTime = time();
        $data = json_decode(file_get_contents($filename), true);
        
        if ($data === null) {
            throw new Exception("Invalid JSON");
        }
        
        $imported = 0;
        $errors = [];
        
        foreach ($data as $index => $record) {
            // 残り時間をチェック
            $elapsed = time() - $startTime;
            $remaining = $this->maxExecutionTime - $elapsed - $this->safetyMargin;
            
            if ($remaining < 0) {
                echo "\nTime limit approaching, stopping import\n";
                break;
            }
            
            try {
                call_user_func($processor, $record);
                $imported++;
                
                if ($imported % 100 === 0) {
                    echo "Imported: {$imported} records (Remaining: {$remaining}s)\n";
                    set_time_limit($this->maxExecutionTime);
                }
                
            } catch (Exception $e) {
                $errors[] = [
                    'index' => $index,
                    'error' => $e->getMessage()
                ];
            }
        }
        
        return [
            'imported' => $imported,
            'errors' => $errors,
            'execution_time' => time() - $startTime
        ];
    }
}

// 使用例
echo "=== データインポート ===\n";

// テストCSVを作成
$csvFile = '/tmp/import_test.csv';
$fp = fopen($csvFile, 'w');
fputcsv($fp, ['id', 'name', 'email', 'age']);
for ($i = 1; $i <= 1000; $i++) {
    fputcsv($fp, [$i, "User {$i}", "user{$i}@example.com", rand(18, 80)]);
}
fclose($fp);

$importer = new DataImporter(300, 30);

$result = $importer->importCsv($csvFile, function($data) {
    // データ処理をシミュレート
    usleep(1000);  // 1ミリ秒
    
    // 検証
    if (empty($data['email'])) {
        throw new Exception("Email is required");
    }
});

echo "\n=== インポート結果 ===\n";
echo "インポート済み: {$result['imported']}件\n";
echo "エラー: " . count($result['errors']) . "件\n";
echo "実行時間: {$result['execution_time']}秒\n";

// クリーンアップ
unlink($csvFile);

例3: 画像処理システム

class ImageProcessor {
    private $timeLimit;
    private $outputDir;
    
    /**
     * 画像処理を初期化
     */
    public function __construct($outputDir, $timeLimit = 300) {
        $this->outputDir = $outputDir;
        $this->timeLimit = $timeLimit;
        
        if (!is_dir($outputDir)) {
            mkdir($outputDir, 0755, true);
        }
        
        set_time_limit($timeLimit);
    }
    
    /**
     * 複数の画像をリサイズ
     */
    public function resizeImages($images, $width, $height) {
        $startTime = time();
        $processed = 0;
        $errors = [];
        
        foreach ($images as $index => $imagePath) {
            try {
                // 残り時間をチェック
                $elapsed = time() - $startTime;
                if ($elapsed > $this->timeLimit - 30) {
                    echo "Time limit approaching, stopping processing\n";
                    break;
                }
                
                $this->resizeImage($imagePath, $width, $height);
                $processed++;
                
                echo "Processed: {$processed}/" . count($images) . "\n";
                
                // 10枚ごとに制限時間をリセット
                if ($processed % 10 === 0) {
                    set_time_limit($this->timeLimit);
                }
                
            } catch (Exception $e) {
                $errors[] = [
                    'image' => $imagePath,
                    'error' => $e->getMessage()
                ];
            }
        }
        
        return [
            'processed' => $processed,
            'total' => count($images),
            'errors' => $errors,
            'execution_time' => time() - $startTime
        ];
    }
    
    /**
     * 画像を生成してリサイズ(テスト用)
     */
    private function resizeImage($imagePath, $width, $height) {
        if (!file_exists($imagePath)) {
            throw new Exception("Image not found: {$imagePath}");
        }
        
        // 画像処理をシミュレート(実際にはGDやImagickを使用)
        usleep(50000);  // 50ミリ秒(画像処理をシミュレート)
        
        $outputPath = $this->outputDir . '/' . basename($imagePath);
        copy($imagePath, $outputPath);
    }
    
    /**
     * サムネイル生成
     */
    public function generateThumbnails($images, $size = 150) {
        set_time_limit($this->timeLimit);
        
        $generated = 0;
        
        foreach ($images as $image) {
            // 処理
            $this->createThumbnail($image, $size);
            $generated++;
            
            // 5枚ごとにリセット
            if ($generated % 5 === 0) {
                set_time_limit($this->timeLimit);
                echo "Generated {$generated} thumbnails\n";
            }
        }
        
        return $generated;
    }
    
    /**
     * サムネイルを作成(テスト用)
     */
    private function createThumbnail($image, $size) {
        usleep(30000);  // 30ミリ秒
    }
}

// 使用例
echo "=== 画像処理 ===\n";

// テスト用の画像ファイルを作成
$testImages = [];
for ($i = 1; $i <= 50; $i++) {
    $imagePath = "/tmp/test_image_{$i}.jpg";
    file_put_contents($imagePath, "dummy image content {$i}");
    $testImages[] = $imagePath;
}

$processor = new ImageProcessor('/tmp/resized', 180);

echo "制限時間: 180秒\n";
echo "画像数: " . count($testImages) . "\n\n";

$result = $processor->resizeImages($testImages, 800, 600);

echo "\n=== 処理結果 ===\n";
echo "処理済み: {$result['processed']}/{$result['total']}\n";
echo "エラー: " . count($result['errors']) . "件\n";
echo "実行時間: {$result['execution_time']}秒\n";

// クリーンアップ
foreach ($testImages as $image) {
    @unlink($image);
}

例4: API呼び出しマネージャー

class ApiCallManager {
    private $baseUrl;
    private $timeout;
    private $maxRetries;
    
    /**
     * API呼び出しマネージャーを初期化
     */
    public function __construct($baseUrl, $timeout = 300, $maxRetries = 3) {
        $this->baseUrl = $baseUrl;
        $this->timeout = $timeout;
        $this->maxRetries = $maxRetries;
        
        // 十分な実行時間を確保
        set_time_limit($timeout + 60);
    }
    
    /**
     * 複数のAPIエンドポイントを呼び出し
     */
    public function batchCall($endpoints) {
        $startTime = time();
        $results = [];
        $errors = [];
        
        foreach ($endpoints as $index => $endpoint) {
            // 残り時間をチェック
            $elapsed = time() - $startTime;
            if ($elapsed > $this->timeout - 30) {
                echo "Time limit approaching, stopping API calls\n";
                break;
            }
            
            try {
                $result = $this->callWithRetry($endpoint);
                $results[$endpoint] = $result;
                
                echo "Called: {$endpoint} (" . ($index + 1) . "/" . count($endpoints) . ")\n";
                
                // 10回ごとに制限時間をリセット
                if (($index + 1) % 10 === 0) {
                    set_time_limit($this->timeout + 60);
                }
                
            } catch (Exception $e) {
                $errors[$endpoint] = $e->getMessage();
            }
        }
        
        return [
            'results' => $results,
            'errors' => $errors,
            'execution_time' => time() - $startTime
        ];
    }
    
    /**
     * リトライ付きでAPIを呼び出し
     */
    private function callWithRetry($endpoint, $attempt = 1) {
        try {
            return $this->makeApiCall($endpoint);
        } catch (Exception $e) {
            if ($attempt < $this->maxRetries) {
                echo "Retry {$attempt}/{$this->maxRetries} for {$endpoint}\n";
                sleep(1);  // 待機
                return $this->callWithRetry($endpoint, $attempt + 1);
            }
            throw $e;
        }
    }
    
    /**
     * 実際のAPI呼び出し(テスト用)
     */
    private function makeApiCall($endpoint) {
        // API呼び出しをシミュレート
        usleep(rand(100000, 500000));  // 100-500ミリ秒
        
        // ランダムに失敗させる
        if (rand(1, 10) > 8) {
            throw new Exception("API call failed");
        }
        
        return [
            'status' => 'success',
            'data' => ['key' => 'value'],
            'endpoint' => $endpoint
        ];
    }
    
    /**
     * ページネーション付きでデータを取得
     */
    public function fetchPaginatedData($endpoint, $maxPages = 10) {
        set_time_limit($this->timeout + 60);
        
        $allData = [];
        $page = 1;
        
        while ($page <= $maxPages) {
            // 残り時間をチェック
            $elapsed = time() - $_SERVER['REQUEST_TIME'];
            if ($elapsed > $this->timeout - 30) {
                echo "Time limit approaching, stopping pagination\n";
                break;
            }
            
            $data = $this->makeApiCall("{$endpoint}?page={$page}");
            $allData = array_merge($allData, $data);
            
            echo "Fetched page {$page}\n";
            
            // 5ページごとに制限時間をリセット
            if ($page % 5 === 0) {
                set_time_limit($this->timeout + 60);
            }
            
            $page++;
        }
        
        return $allData;
    }
}

// 使用例
echo "=== API呼び出し管理 ===\n";

$apiManager = new ApiCallManager('https://api.example.com', 120, 3);

// 呼び出すエンドポイント
$endpoints = [];
for ($i = 1; $i <= 30; $i++) {
    $endpoints[] = "/api/data/{$i}";
}

echo "エンドポイント数: " . count($endpoints) . "\n";
echo "制限時間: 120秒\n\n";

$result = $apiManager->batchCall($endpoints);

echo "\n=== 呼び出し結果 ===\n";
echo "成功: " . count($result['results']) . "件\n";
echo "失敗: " . count($result['errors']) . "件\n";
echo "実行時間: {$result['execution_time']}秒\n";

例5: レポート生成システム

class ReportGenerator {
    private $timeLimit;
    private $reportDir;
    
    /**
     * レポート生成を初期化
     */
    public function __construct($reportDir, $timeLimit = 600) {
        $this->reportDir = $reportDir;
        $this->timeLimit = $timeLimit;
        
        if (!is_dir($reportDir)) {
            mkdir($reportDir, 0755, true);
        }
        
        set_time_limit($timeLimit);
    }
    
    /**
     * 大量データからレポートを生成
     */
    public function generateReport($data, $reportName) {
        $startTime = time();
        $reportFile = $this->reportDir . '/' . $reportName;
        
        $fp = fopen($reportFile, 'w');
        if ($fp === false) {
            throw new Exception("Failed to create report file");
        }
        
        // ヘッダー
        fwrite($fp, "=== {$reportName} ===\n");
        fwrite($fp, "Generated: " . date('Y-m-d H:i:s') . "\n\n");
        
        $sections = [
            'summary' => function() use ($data) {
                return $this->generateSummary($data);
            },
            'details' => function() use ($data) {
                return $this->generateDetails($data);
            },
            'statistics' => function() use ($data) {
                return $this->generateStatistics($data);
            },
            'charts' => function() use ($data) {
                return $this->generateCharts($data);
            }
        ];
        
        foreach ($sections as $sectionName => $generator) {
            // 残り時間をチェック
            $elapsed = time() - $startTime;
            $remaining = $this->timeLimit - $elapsed - 30;
            
            if ($remaining < 0) {
                fwrite($fp, "\n[Report generation stopped due to time limit]\n");
                break;
            }
            
            echo "Generating section: {$sectionName} (Remaining: {$remaining}s)\n";
            
            // セクションを生成
            $content = call_user_func($generator);
            fwrite($fp, "\n## {$sectionName} ##\n");
            fwrite($fp, $content . "\n");
            
            // 制限時間をリセット
            set_time_limit($this->timeLimit);
        }
        
        fwrite($fp, "\n=== End of Report ===\n");
        fclose($fp);
        
        return [
            'file' => $reportFile,
            'size' => filesize($reportFile),
            'execution_time' => time() - $startTime
        ];
    }
    
    /**
     * サマリーを生成
     */
    private function generateSummary($data) {
        usleep(100000);  // 処理をシミュレート
        return "Total records: " . count($data) . "\n";
    }
    
    /**
     * 詳細を生成
     */
    private function generateDetails($data) {
        $output = '';
        foreach (array_slice($data, 0, 100) as $record) {
            $output .= json_encode($record) . "\n";
            usleep(1000);
        }
        return $output;
    }
    
    /**
     * 統計を生成
     */
    private function generateStatistics($data) {
        usleep(200000);  // 処理をシミュレート
        return "Average: 50\nMedian: 45\nStdDev: 15\n";
    }
    
    /**
     * チャートを生成
     */
    private function generateCharts($data) {
        usleep(300000);  // 処理をシミュレート
        return "[Chart data would be here]\n";
    }
}

// 使用例
echo "=== レポート生成 ===\n";

// テストデータ
$testData = [];
for ($i = 0; $i < 10000; $i++) {
    $testData[] = [
        'id' => $i,
        'value' => rand(1, 100),
        'category' => 'Category ' . (($i % 5) + 1)
    ];
}

$generator = new ReportGenerator('/tmp/reports', 300);

echo "データ件数: " . count($testData) . "\n";
echo "制限時間: 300秒\n\n";

$result = $generator->generateReport($testData, 'monthly_report.txt');

echo "\n=== 生成完了 ===\n";
echo "ファイル: {$result['file']}\n";
echo "サイズ: " . number_format($result['size']) . " bytes\n";
echo "実行時間: {$result['execution_time']}秒\n";

例6: タイムアウト監視システム

class TimeoutMonitor {
    private $maxExecutionTime;
    private $warningThreshold;
    private $startTime;
    
    /**
     * モニターを初期化
     */
    public function __construct($maxExecutionTime = 300, $warningThreshold = 0.8) {
        $this->maxExecutionTime = $maxExecutionTime;
        $this->warningThreshold = $warningThreshold;
        $this->startTime = time();
        
        set_time_limit($maxExecutionTime);
        
        // シャットダウン関数を登録
        register_shutdown_function([$this, 'handleShutdown']);
    }
    
    /**
     * 残り時間を取得
     */
    public function getRemainingTime() {
        $elapsed = time() - $this->startTime;
        return max(0, $this->maxExecutionTime - $elapsed);
    }
    
    /**
     * 使用率を取得
     */
    public function getUsagePercentage() {
        $elapsed = time() - $this->startTime;
        return ($elapsed / $this->maxExecutionTime) * 100;
    }
    
    /**
     * 警告しきい値に達したかチェック
     */
    public function isWarningThresholdReached() {
        $usage = $this->getUsagePercentage() / 100;
        return $usage >= $this->warningThreshold;
    }
    
    /**
     * 安全に処理を続行できるかチェック
     */
    public function canContinue($safetyMargin = 30) {
        return $this->getRemainingTime() > $safetyMargin;
    }
    
    /**
     * 制限時間をリセット
     */
    public function reset() {
        set_time_limit($this->maxExecutionTime);
        $this->startTime = time();
    }
    
    /**
     * シャットダウン時の処理
     */
    public function handleShutdown() {
        $error = error_get_last();
        
        if ($error !== null && $error['type'] === E_ERROR) {
            if (strpos($error['message'], 'Maximum execution time') !== false) {
                echo "\n[TIMEOUT] Script exceeded maximum execution time\n";
                echo "Elapsed: " . (time() - $this->startTime) . " seconds\n";
            }
        }
    }
    
    /**
     * ステータスを表示
     */
    public function displayStatus() {
        $remaining = $this->getRemainingTime();
        $usage = $this->getUsagePercentage();
        
        echo sprintf(
            "[TIME] Remaining: %ds (%.1f%% used)",
            $remaining,
            $usage
        );
        
        if ($this->isWarningThresholdReached()) {
            echo " [WARNING]";
        }
        
        echo "\n";
    }
}

// 使用例
echo "=== タイムアウト監視 ===\n";

$monitor = new TimeoutMonitor(60, 0.7);  // 60秒、警告70%

echo "最大実行時間: 60秒\n";
echo "警告しきい値: 70%\n\n";

for ($i = 0; $i < 100; $i++) {
    // 何らかの処理
    usleep(500000);  // 0.5秒
    
    if ($i % 5 === 0) {
        $monitor->displayStatus();
    }
    
    // 警告しきい値に達したらアラート
    if ($monitor->isWarningThresholdReached()) {
        echo "警告: 実行時間の70%を超えました\n";
    }
    
    // 続行できるかチェック
    if (!$monitor->canContinue(10)) {
        echo "安全マージン不足のため処理を中断します\n";
        break;
    }
    
    // 20回ごとにリセット
    if ($i > 0 && $i % 20 === 0) {
        echo "制限時間をリセットします\n";
        $monitor->reset();
    }
}

echo "\n処理完了\n";

php.iniとの関係

// php.iniの設定を確認
echo "max_execution_time: " . ini_get('max_execution_time') . "\n";

// ini_set()で変更
ini_set('max_execution_time', 300);

// set_time_limit()で変更
set_time_limit(300);

// 両方とも同じ効果だが、set_time_limit()は実行時間をリセット
// ini_set()は設定を変更するだけ

// .htaccessでの設定
// php_value max_execution_time 300

セーフモードと制限事項

// セーフモードが有効な場合
if (ini_get('safe_mode')) {
    echo "セーフモードが有効です\n";
    echo "set_time_limit()は無効化されている可能性があります\n";
}

// disable_functionsでset_time_limitが無効化されている場合
$disabled = ini_get('disable_functions');
if (strpos($disabled, 'set_time_limit') !== false) {
    echo "set_time_limit()は無効化されています\n";
}

// CLIモードでは通常デフォルトで0(無制限)
if (php_sapi_name() === 'cli') {
    echo "CLIモード: デフォルトで実行時間無制限\n";
    echo "現在の設定: " . ini_get('max_execution_time') . "\n";
}

まとめ

set_time_limit()関数の特徴をまとめると:

できること:

  • スクリプトの最大実行時間を設定
  • 実行時間制限のリセット
  • 長時間処理の実現

引数:

  • 秒数: 最大実行時間(秒単位)
  • 0: 無制限

推奨される使用場面:

  • バッチ処理
  • データインポート/エクスポート
  • 画像処理
  • レポート生成
  • API呼び出し
  • クローリング/スクレイピング

重要な注意点:

  • 呼び出し時点から時間をカウント開始(リセット)
  • sleep()の時間は含まれない
  • 外部プログラムの実行時間は含まれる
  • セーフモードでは無効
  • disable_functionsで無効化されている場合あり

ベストプラクティス:

// 1. 適切な制限時間を設定
set_time_limit(300);  // 5分

// 2. 定期的にリセット
foreach ($batches as $batch) {
    processBatch($batch);
    set_time_limit(300);  // リセット
}

// 3. 残り時間を監視
$startTime = time();
if (time() - $startTime > 270) {  // 30秒マージン
    break;
}

// 4. シャットダウン関数を登録
register_shutdown_function(function() {
    // タイムアウト時の処理
});

関連設定:

  • max_execution_time: php.iniの設定
  • max_input_time: 入力処理の最大時間
  • memory_limit: メモリ制限

関連関数:

  • ini_set(): PHP設定を変更
  • ini_get(): PHP設定を取得
  • register_shutdown_function(): シャットダウン関数登録
  • ignore_user_abort(): ユーザー切断時の動作制御

set_time_limit()は、長時間実行が必要な処理において非常に重要な関数です。適切に使用することで、タイムアウトエラーを防ぎ、大規模な処理を安全に実行できます!

タイトルとURLをコピーしました