範例 #1 簡單計時器
<?php
// Create and start timer firing after 2 seconds
$w1 = new EvTimer(2, 0, function () {
echo "2 seconds elapsed\n";
});
// Create and launch timer firing after 2 seconds repeating each second
// until we manually stop it
$w2 = new EvTimer(2, 1, function ($w) {
echo "is called every second, is launched after 2 seconds\n";
echo "iteration = ", Ev::iteration(), PHP_EOL;
// Stop the watcher after 5 iterations
Ev::iteration() == 5 and $w->stop();
// Stop the watcher if further calls cause more than 10 iterations
Ev::iteration() >= 10 and $w->stop();
});
// Create stopped timer. It will be inactive until we start it ourselves
$w_stopped = EvTimer::createStopped(10, 5, function($w) {
echo "Callback of a timer created as stopped\n";
// Stop the watcher after 2 iterations
Ev::iteration() >= 2 and $w->stop();
});
// Loop until Ev::stop() is called or all of watchers stop
Ev::run();
// Start and look if it works
$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 可讀取\n";
});
Ev::run(Ev::RUN_ONCE);
?>
範例 #6 使用一些非同步 I/O 來存取 socket
<?php
/* Use some async I/O to access a socket */
// `sockets' extension still logs warnings
// for EINPROGRESS, EAGAIN/EWOULDBLOCK etc.
error_reporting(E_ERROR);
$e_nonblocking = array (/*EAGAIN or EWOULDBLOCK*/11, /*EINPROGRESS*/115);
// Get the port for the WWW service
$service_port = getservbyname('www', 'tcp');
// Get the IP address for the target host
$address = gethostbyname('google.co.uk');
// Create a TCP/IP socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === FALSE) {
echo "socket_create() failed: reason: "
.socket_strerror(socket_last_error()) . "\n";
}
// Set O_NONBLOCK flag
socket_set_nonblock($socket);
// Abort on timeout
$timeout_watcher = new EvTimer(10.0, 0., function () use ($socket) {
socket_close($socket);
Ev::stop(Ev::BREAK_ALL);
});
// Make HEAD request when the socket is writable
$write_watcher = new EvIo($socket, Ev::WRITE, function ($w)
use ($socket, $timeout_watcher, $e_nonblocking)
{
// Stop timeout watcher
$timeout_watcher->stop();
// Stop write watcher
$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)
{
// Socket is readable. recv() 20 bytes using non-blocking mode
$ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);
if ($ret) {
echo $out;
} elseif ($ret === 0) {
// All read
$w->stop();
socket_close($socket);
return;
}
// Caught EINPROGRESS, EAGAIN, or 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_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;
/*
* 檢查是否有機會取得一個可運作的事件迴圈
* (flags 值為 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 後端
* 以用於 sockets(通常適用於任何 kqueue 實作)。
* 將僅限 kqueue/socket 的事件迴圈儲存在 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 處理所有 sockets,並使用 $loop 處理其他任何事情
?>
範例 #9 處理 SIGTERM 信號
<?php
$w = new EvSignal(SIGTERM, function ($watcher) {
echo "收到 SIGTERM\n";
$watcher->stop();
});
Ev::run();
?>
範例 #10 監控 /var/log/messages 的變更
<?php
// 使用 10 秒的更新間隔。
$w = new EvStat("/var/log/messages", 8, function ($w) {
echo "/var/log/messages 已變更\n";
$attr = $w->attr();
if ($attr['nlink']) {
printf("目前大小:%ld\n", $attr['size']);
printf("目前存取時間:%ld\n", $attr['atime']);
printf("目前修改時間:%ld\n", $attr['mtime']);
} else {
fprintf(STDERR, "`messages` 檔案不存在!");
$w->stop();
}
});
Ev::run();
?>
範例 #11 監控 /var/log/messages 的變更。透過一秒的延遲避免遺漏更新
<?php
$timer = EvTimer::createStopped(0., 1.02, function ($w) {
$w->stop();
$stat = $w->data;
// 在檔案最近一次變更後 1 秒
printf("目前大小:%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 失敗\n");
} elseif ($pid) {
$w = new EvChild($pid, FALSE, function ($w, $revents) {
$w->stop();
printf("行程 %d 已結束,狀態碼為 %d\n", $w->rpid, $w->rstatus);
});
Ev::run();
// 防止殭屍行程
pcntl_wait($status);
} else {
//子行程
exit(2);
}
?>