PHPで非同期的なことをやってみる

非同期といっても、イベントを投げるだけなので、
非同期で行った結果を取得できないので、使いどころは少ないという。。

まあ一応こんなやり方もできましたってことで。

やり方としてはキックする側とキックされる側を少し弄ればOK

キックする側

こんな感じの関数を書いてみました。
単純にURIにアクセスして、fgetせずに即コネクションを落とすというだけ。

function async_access($uri){
    if ($parsed = parse_url($uri)) {
        $host = $parsed['host'];
        $path = ($parsed['query'])?$parsed['path'].'?'.$parsed['query']:$parsed['path'];
        if (isset($host) && isset($path)) {
            $fp = fsockopen($host,80,$errNumber,$errMessage,3);
            if ($fp) {
                $request = "GET {$path} HTTP/1.1\r\n";
                $request .= "Host: {$host}\r\n";
                $request .= "Connection: close\r\n\r\n";
                fputs($fp,$request);
                fclose($fp);
                return true;
            }
        }
    }
    return false;
}

ただ普通にやるとこれだけだと、キックされる側によって、
PHPが最後まで実行される or されない というのが変わってしまうので、
キックされる側のPHPをチェックします。

キックされる側

ここらへんPHPの接続処理関係
をみればわかるように、PHPのステータスは3つあるわけですが、
今回のように即コネクションを閉じてしまうと基本的にはABORTEDになるわけです。
で、このABORTEDになったときにPHPの処理をとめるorとめないというのを制御してあげれば
上の関数でキックしたあと、きちんと処理をして終わってくれるというわけです。

で、調べた限りでPHPが最後まで実行してくれるようにするには2パターンありました。

●1個目
PHP側で一切出力処理をしない。
⇒単純にheader()とか echo,print などを削除&バッファ関連の ob_~ も削除する。

●2個目
どうしてもprintなどの処理が必要な場合は
ignore_user_abort(true)を最初にかき、 ob_startにてバッファ処理をさせて、
出力時は ob_flush() などで対応する。

これのどちらかをやれば問題なく動きました。

まあいずれにせよ、キックされた側のPHPの終了を読み取るには register_shutdown_function などを使って
再度こっちにキックしなおさないといけなかったりするので、
基本的には片道切符として使ったほうがいいと思います。

参考文献
ignore_user_abort(false)でPHPが処理を中断しない件
ignore_user_abort=falseなのにスクリプトが止まらない
ignore_user_abort
PHPの接続処理関係

Leave a Reply