【PHP8.x】curl_multi_remove_handle関数の使い方

作成日: 更新日:

curl_multi_remove_handle関数は、cURLのマルチハンドルから特定のcURLハンドルを削除する関数です。

PHPのcURL拡張機能は、ウェブサイトへのデータ取得(HTTPリクエストなど)をプログラムから実行するための機能を提供します。特に、複数のウェブサイトから同時にデータを取得したい場合など、並行処理が必要な際には「cURLマルチハンドル」という特別な機能が利用されます。

このcurl_multi_remove_handle関数は、そうしたcURLマルチハンドルに一度登録された個々のcURLハンドル(これは特定のウェブサイトへの単一のリクエストを表します)を、そこから削除する役割を持っています。例えば、複数の並行リクエストのうち、どれか一つのリクエストの処理が完了した際や、途中でそのリクエストが不要になった場合に、この関数を使ってそのハンドルをマルチハンドルから切り離します。

関数は二つの主要な引数を取ります。一つ目は、削除対象のcURLハンドルが登録されている「cURLマルチハンドル」です。二つ目は、実際に削除したい「個々のcURLハンドル」です。処理が成功した場合はtrueを、失敗した場合はfalseを返します。

不要になったcURLハンドルをマルチハンドルから適切に削除することで、メモリやネットワーク接続などのシステムリソースを効率的に解放し、アプリケーションの安定性とパフォーマンスを維持することができます。処理が完了したcURLハンドルは、忘れずにこの関数で削除することが推奨されます。

基本的な使い方

構文(syntax)

<?php

$multi_handle = curl_multi_init();
$curl_handle = curl_init();

// $curl_handle を $multi_handle に追加します
curl_multi_add_handle($multi_handle, $curl_handle);

// $curl_handle を $multi_handle から削除します
curl_multi_remove_handle($multi_handle, $curl_handle);

// リソースを解放します
curl_close($curl_handle);
curl_multi_close($multi_handle);

?>

引数(parameters)

CurlMultiHandle $multi_handle, CurlHandle $handle

  • CurlMultiHandle $multi_handle: 複数のCurlセッションを管理するCurlMultiHandleオブジェクト
  • CurlHandle $handle: 削除するCurlセッションを管理するCurlHandleオブジェクト

戻り値(return)

int

処理されたハンドルの数を示す整数を返します。エラーが発生した場合は -1 を返します。

サンプルコード

PHP curl_multi_remove_handle でハンドルを削除する

<?php

/**
 * このスクリプトは、PHPのcURL拡張機能を使って複数のHTTPリクエストを並行して処理し、
 * 途中で特定のCURLハンドルをマルチCURLハンドルから削除する (`curl_multi_remove_handle`)
 * 方法を示します。システムエンジニアを目指す初心者にも理解しやすいように、
 * 各ステップにコメントを追加しています。
 */
function demonstrateCurlMultiRemoveHandle(): void
{
    echo "--- cURLマルチリクエストとハンドル削除のデモンストレーション ---" . PHP_EOL;

    // 1. マルチCURLハンドルを初期化します。
    //    これは複数のCURLリクエストを同時に管理するためのコンテナです。
    //    PHP 8.1以降では CurlMultiHandle 型のオブジェクトを返します。
    $multiHandle = curl_multi_init();
    if ($multiHandle === false) {
        echo "エラー: マルチCURLハンドルを初期化できませんでした。" . PHP_EOL;
        return;
    }
    echo "マルチCURLハンドルを初期化しました。" . PHP_EOL;

    // 2. 個別のCURLハンドルを初期化します。
    //    それぞれのハンドルが1つのHTTPリクエストを表します。
    //    PHP 8.1以降では CurlHandle 型のオブジェクトを返します。
    $ch1 = curl_init("https://httpbin.org/delay/2"); // 2秒遅延するテストURL
    $ch2 = curl_init("https://httpbin.org/get");     // 即座に応答するテストURL

    if ($ch1 === false || $ch2 === false) {
        echo "エラー: 個別のCURLハンドルを初期化できませんでした。" . PHP_EOL;
        // 初期化に失敗した場合、既に初期化されたハンドルとマルチハンドルをクローズします。
        if ($ch1 !== false) curl_close($ch1);
        if ($ch2 !== false) curl_close($ch2);
        curl_multi_close($multiHandle);
        return;
    }
    echo "個別のCURLハンドル (ch1, ch2) を初期化しました。" . PHP_EOL;

    // 3. 各ハンドルにオプションを設定します。
    //    CURLOPT_RETURNTRANSFER を true にすると、curl_exec() が結果を文字列として返します。
    curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
    echo "各ハンドルにオプションを設定しました。" . PHP_EOL;

    echo PHP_EOL . "--- 個別のCURLハンドルをマルチハンドルに追加 ---" . PHP_EOL;
    // 4. 個別のCURLハンドルをマルチCURLハンドルに追加します。
    //    これにより、これらのリクエストが並行して処理される準備ができます。
    curl_multi_add_handle($multiHandle, $ch1);
    curl_multi_add_handle($multiHandle, $ch2);
    echo "Handle ch1 (delay/2) と Handle ch2 (get) をマルチハンドルに追加しました。" . PHP_EOL;

    $running = null; // 現在アクティブなハンドルの数を追跡するための変数
    $execStatus = null; // curl_multi_exec() の戻り値を保持

    echo PHP_EOL . "--- 並行リクエストを実行し、途中でハンドルを削除 ---" . PHP_EOL;

    // 5. 並行してCURLリクエストを実行し、進行状況を監視します。
    //    $running が 0 になるまで(全てのリクエストが完了するまで)ループします。
    do {
        // リクエストの実行状況を更新します。
        // リクエストが完了したり、何かイベントが発生すると $running の値が変わります。
        $execStatus = curl_multi_exec($multiHandle, $running);

        // まだ実行中のリクエストがあり、エラーがない場合、次のイベントを待ちます。
        if ($execStatus === CURLM_OK && $running > 0) {
            // アクティビティがあるまで短時間(例: 0.1秒)待機します。
            // これによりCPU使用率を抑え、効率的にイベントを待ちます。
            curl_multi_select($multiHandle, 0.1);
        }

        // ここで、特定の条件に基づいてハンドルを削除する例を示します。
        // Handle ch2 は即座に応答するため、そのコンテンツが利用可能になったら削除します。
        // (より厳密には curl_multi_info_read を使うべきですが、簡潔な例として)
        if ($ch2 !== null && curl_multi_getcontent($ch2) !== '') {
            echo "Handle ch2 のコンテンツが利用可能になったため、マルチハンドルから削除します。" . PHP_EOL;

            // 6. 特定のハンドルをマルチハンドルから削除します。
            //    この関数は、指定された個別のCURLハンドルをマルチCURLハンドルから切り離します。
            //    戻り値は通常 CURLM_OK (0) です。
            $removeResult = curl_multi_remove_handle($multiHandle, $ch2);

            if ($removeResult === CURLM_OK) {
                echo "Handle ch2 は正常に削除されました。" . PHP_EOL;
                // 削除後、不要になったハンドルはすぐにクローズするのが一般的です。
                curl_close($ch2);
                $ch2 = null; // 削除されたハンドルはnullにして、以降利用しないことを明確にします。
            } else {
                echo "エラー: Handle ch2 の削除に失敗しました。エラーコード: " . $removeResult . PHP_EOL;
            }
        }

    } while ($running > 0 && $execStatus === CURLM_OK);

    echo PHP_EOL . "--- リクエスト処理完了 ---" . PHP_EOL;

    // 7. 残りのハンドルの結果を取得し、クローズします。
    //    削除された Handle ch2 は、もはやマルチハンドルの一部ではないため、結果は取得できません。
    if ($ch1 !== null) {
        $result1 = curl_multi_getcontent($ch1);
        echo "Handle ch1 の結果の長さ: " . strlen($result1) . "バイト" . PHP_EOL;
        curl_close($ch1); // 残りのハンドルをクローズします。
    } else {
        echo "Handle ch1 は存在しませんでした (予期しないエラー)。" . PHP_EOL;
    }

    if ($ch2 === null) {
        echo "Handle ch2 は削除され、既にクローズされています。" . PHP_EOL;
    } else {
        // この部分は、もし curl_multi_remove_handle が失敗した場合のみ実行されます。
        $result2 = curl_multi_getcontent($ch2);
        echo "Handle ch2 の結果の長さ: " . strlen($result2) . "バイト" . PHP_EOL;
        curl_close($ch2);
    }

    // 8. マルチCURLハンドルをクローズします。
    //    これにより、関連するリソースが解放されます。
    curl_multi_close($multiHandle);
    echo "マルチCURLハンドルをクローズしました。" . PHP_EOL;

    echo PHP_EOL . "--- デモンストレーション終了 ---" . PHP_EOL;
}

// 関数を実行してデモンストレーションを開始します。
demonstrateCurlMultiRemoveHandle();

curl_multi_remove_handle関数は、PHPのcURL拡張機能において、複数のHTTPリクエストを並行して管理する「マルチCURLハンドル」から、特定の「個別のCURLハンドル」を削除するために使用されます。この関数を利用することで、並行処理中のリクエストの中から、特定の処理のみを途中で切り離したり、不要になったリクエストのリソースを早期に解放したりすることが可能になります。

この関数は二つの引数を取ります。最初の引数$multi_handleには、削除したい個別のCURLハンドルが現在追加されているCurlMultiHandleオブジェクトを指定します。二番目の引数$handleには、マルチCURLハンドルから削除したいCurlHandleオブジェクトを指定します。

関数の実行に成功すると、整数値のCURLM_OK(0)を返します。これは、指定された個別のハンドルがマルチハンドルから正常に削除されたことを意味します。もしエラーが発生した場合は、CURLM_OK以外の整数値(エラーコード)が戻り値として返されます。

サンプルコードでは、複数のHTTPリクエストを並行実行する中で、応答が早いリクエスト(ch2)の処理が完了した段階で、curl_multi_remove_handleを使ってそのハンドルをマルチハンドルから削除しています。削除されたハンドルは、もはやマルチハンドルの管理下にはなくなり、個別にクローズしてリソースを解放する必要があります。この機能は、複雑な並行リクエスト処理において、動的なリクエスト管理を行う際に役立ちます。

この関数は、並行処理中のマルチCURLハンドルから特定のCURLハンドルを削除する際に利用します。最も重要な点として、削除後は必ずcurl_close()でその個別のCURLハンドルを閉じる必要があります。これを忘れるとリソースリークの原因となりますので注意してください。関数の戻り値がCURLM_OK (0) であるかを確認し、正常に削除されたかを常に確認する習慣をつけましょう。一度削除されたハンドルは、それ以降マルチハンドルの管理対象外となり、マルチ関連の関数で操作しても効果がありません。そのため、不要になったタイミングで適切に削除し、すぐにクローズすることが安全な利用の鍵です。

【PHP8.x】curl_multi_remove_handle関数の使い方 | いっしー@Webエンジニア