Php/docs/ev.examples

提供:Dev Guides
< Php
移動先:案内検索

例1 タイマーのサンプル

<?php// タイマーを作り、2 秒後に起動します$w1 = new EvTimer(2, 0, function () {    echo "2 seconds elapsed\n";});// タイマーを作って 2 秒後に起動させ、その後は// 手で止めるまで 1 秒おきに繰り返します$w2 = new EvTimer(2, 1, function ($w) {    echo "is called every second, is launched after 2 seconds\n";    echo "iteration = ", Ev::iteration(), PHP_EOL;    // 5 回繰り返したあとでウォッチャーを止めます    Ev::iteration() == 5 and $w->stop();    // Stop the watcher if further calls cause more than 10 iterations    Ev::iteration() >= 10 and $w->stop();});// 停止状態のタイマーを作ります。開始させるまでは非アクティブになります。$w_stopped = EvTimer::createStopped(10, 5, function($w) {    echo "Callback of a timer created as stopped\n";    // 2 回繰り返したあとでウォッチャーを止めます    Ev::iteration() >= 2 and $w->stop();});// Ev::stop() が呼ばれるか、すべてのウォッチャーが止まるまでループしますEv::run();// 開始させ、うまく動いているかどうかを確認します$w_stopped->start();echo "Run single iteration\n";Ev::run(Ev::RUN_ONCE);echo "Restart the second watcher and try to handle the same events, but don't block\n";$w2->again();Ev::run(Ev::RUN_NOWAIT);$w = new EvTimer(10, 0, function() {});echo "Running a blocking loop\n";Ev::run();echo "END\n";?>

上の例の出力は、 たとえば以下のようになります。


2 seconds elapsed
is called every second, is launched after 2 seconds
iteration = 1
is called every second, is launched after 2 seconds
iteration = 2
is called every second, is launched after 2 seconds
iteration = 3
is called every second, is launched after 2 seconds
iteration = 4
is called every second, is launched after 2 seconds
iteration = 5
Run single iteration
Callback of a timer created as stopped
Restart the second watcher and try to handle the same events, but don't block
Running a blocking loop
is called every second, is launched after 2 seconds
iteration = 8
is called every second, is launched after 2 seconds
iteration = 9
is called every second, is launched after 2 seconds
iteration = 10
END

例2 10.5 秒おきに繰り返すタイマー

<?php$w = new EvPeriodic(0., 10.5, NULL, function ($w, $revents) {    echo time(), PHP_EOL;});Ev::run();?>

例3 再スケジュールコールバックを使う定期タイマー

<?php// 10.5 秒おきに繰り返しますfunction reschedule_cb ($watcher, $now) {    return $now + (10.5. - fmod($now, 10.5));}$w = new EvPeriodic(0., 0., "reschedule_cb", function ($w, $revents) {    echo time(), PHP_EOL;});Ev::run();?>

例4 すぐに開始し、10.5 秒おきに繰り返すタイマー

<?php// すぐに開始し、10.5 秒おきに繰り返します$w = new EvPeriodic(fmod(Ev::now(), 10.5), 10.5, NULL, function ($w, $revents) {    echo time(), PHP_EOL;});Ev::run();?>

例5 STDIN が読み込み可能になるまで待つ例

<?php// STDIN が読み込み可能になるまで待ちます$w = new EvIo(STDIN, Ev::READ, function ($watcher, $revents) {    echo "STDIN is readable\n";});Ev::run(Ev::RUN_ONCE);?>

例6 非同期 I/O を使ったソケットへのアクセス

<?php/* 非同期 I/O を使ってソケットにアクセスします */// `sockets' 拡張モジュールは、// EINPROGRESS や EAGAIN/EWOULDBLOCK などに対して warning を発光しますerror_reporting(E_ERROR);$e_nonblocking = array (/*EAGAIN or EWOULDBLOCK*/11, /*EINPROGRESS*/115);// WWW サービス用のポートを取得します$service_port = getservbyname('www', 'tcp');// 対象ホストの IP アドレスを取得します$address = gethostbyname('google.co.uk');// TCP/IP ソケットを作ります$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);if ($socket === FALSE) {    echo "socket_create() failed: reason: "        .socket_strerror(socket_last_error()) . "\n";}// O_NONBLOCK フラグを立てますsocket_set_nonblock($socket);// タイムアウト時に終了させます$timeout_watcher = new EvTimer(10.0, 0., function () use ($socket) {    socket_close($socket);    Ev::stop(Ev::BREAK_ALL);});// ソケットが書き込み可能になったときに HEAD リクエストを作ります$write_watcher = new EvIo($socket, Ev::WRITE, function ($w)    use ($socket, $timeout_watcher, $e_nonblocking){    // タイムアウトのウォッチャーを止めます    $timeout_watcher->stop();    // 書き込みのウォッチャーを止めます    $w->stop();    $in = "HEAD / HTTP/1.1\r\n";    $in .= "Host: google.co.uk\r\n";    $in .= "Connection: Close\r\n\r\n";    if (!socket_write($socket, $in, strlen($in))) {        trigger_error("Failed writing $in to socket", E_USER_ERROR);    }    $read_watcher = new EvIo($socket, Ev::READ, function ($w, $re)        use ($socket, $e_nonblocking)    {        // ソケットが読み込み可能になりました。非ブロックモードで 20 バイト recv() します        $ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);        if ($ret) {            echo $out;        } elseif ($ret === 0) {            // すべて読み終えました            $w->stop();            socket_close($socket);            return;        }        // EINPROGRESS、EAGAIN あるいは EWOULDBLOCK を捕捉した場合        if (in_array(socket_last_error(), $e_nonblocking)) {            return;        }        $w->stop();        socket_close($socket);    });    Ev::run();});$result = socket_connect($socket, $address, $service_port);Ev::run();?>

上の例の出力は、 たとえば以下のようになります。


HTTP/1.1 301 Moved Permanently
Location: http://www.google.co.uk/
Content-Type: text/html; charset=UTF-8
Date: Sun, 23 Dec 2012 16:08:27 GMT
Expires: Tue, 22 Jan 2013 16:08:27 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 221
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Connection: close

例7 ループの中に別のループを埋め込む例

<?php/** 埋め込み可能なイベントループをデフォルトのイベントループに組み込みます。* できなかった場合はデフォルトのループを使います。* デフォルトのループは $loop_hi に、そして埋め込み可能なループは $loop_lo* に格納されます (埋め込み可能なループが使えなかった場合は $loop_hi* を使います)。** このサンプルを PHP に移植したものです。* http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Examples_CONTENT-9*/$loop_hi = EvLoop::defaultLoop();$loop_lo = NULL;$embed   = NULL;/** 使えるループを取得できるかどうかを調べます* (フラグの値が 0 の場合は自動検出を意味します)*/$loop_lo = Ev::embeddableBackends() & Ev::recommendedBackends()    ? new EvLoop(Ev::embeddableBackends() & Ev::recommendedBackends())    : 0;if ($loop_lo) {    $embed = new EvEmbed($loop_lo, function () {});} else {    $loop_lo = $loop_hi;}?>

例8 kqueue バックエンドで作ったループをデフォルトのループに埋め込む例

<?php/** kqueue が使えるかどうかを調べ、ソケットで使う kqueue バックエンドを作ります* (通常は、どんな kqueue 実装でも動きます)。* kqueue/socket-only イベントループを loop_socket に格納します* (EVFLAG_NOENV も使えます)。** この例を流用しました* http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Examples_CONTENT-9*/$loop        = EvLoop::defaultLoop();$socket_loop = NULL;$embed       = NULL;if (Ev::supportedBackends() & ~Ev::recommendedBackends() & Ev::BACKEND_KQUEUE) {    if (($socket_loop = new EvLoop(Ev::BACKEND_KQUEUE))) {        $embed = new EvEmbed($loop);    }}if (!$socket_loop) {    $socket_loop = $loop;}// これで、すべてのソケットに対して $socket_loop を使い、それ以外については $loop を使うようになりました?>

例9 SIGTERM の処理

<?php$w = new EvSignal(SIGTERM, function ($watcher) {    echo "SIGTERM received\n";    $watcher->stop();});Ev::run();?>

例10 /var/log/messages の変更の監視

<?php// 更新間隔を 10 秒にします$w = new EvStat("/var/log/messages", 8, function ($w) {    echo "/var/log/messages changed\n";    $attr = $w->attr();    if ($attr['nlink']) {        printf("Current size: %ld\n", $attr['size']);        printf("Current atime: %ld\n", $attr['atime']);        printf("Current mtime: %ld\n", $attr['mtime']);    } else {        fprintf(STDERR, "`messages` file is not there!");        $w->stop();    }});Ev::run();?>

例11 /var/log/messages の変更の監視 (1 秒の遅延を使って、更新を見落とさないようにする)

<?php$timer = EvTimer::createStopped(0., 1.02, function ($w) {    $w->stop();    $stat = $w->data;    // ファイルへの直近の変更から 1 秒後    printf("Current size: %ld\n", $stat->attr()['size']);});$stat = new EvStat("/var/log/messages", 0., function () use ($timer) {    // タイマーウォッチャーをリセットします    $timer->again();});$timer->data = $stat;Ev::run();?>

例12 ステータスの変更の処理

<?php$pid = pcntl_fork();if ($pid == -1) {    fprintf(STDERR, "pcntl_fork failed\n");} elseif ($pid) {    $w = new EvChild($pid, FALSE, function ($w, $revents) {        $w->stop();        printf("Process %d exited with status %d\n", $w->rpid, $w->rstatus);    });    Ev::run();    // ゾンビ対策    pcntl_wait($status);} else {    // フォークした子プロセス    exit(2);}?>