示例

示例 #1 简单计时器

<?php
// 创建并启动计时器,在 2 秒后触发
$w1 = new EvTimer(2, 0, function () {
echo
"2 秒已过去\n";
});

// 创建并启动计时器,在 2 秒后触发,每秒重复一次
// 直到我们手动停止它
$w2 = new EvTimer(2, 1, function ($w) {
echo
"每秒被调用,在 2 秒后启动\n";
echo
"迭代 = ", Ev::iteration(), PHP_EOL;

// 在 5 次迭代后停止观察器
Ev::iteration() == 5 and $w->stop();
// 如果进一步调用导致超过 10 次迭代,则停止观察器
Ev::iteration() >= 10 and $w->stop();
});

// 创建已停止的计时器。它将处于非活动状态,直到我们自己启动它
$w_stopped = EvTimer::createStopped(10, 5, function($w) {
echo
"创建为已停止的计时器的回调\n";

// 在 2 次迭代后停止观察器
Ev::iteration() >= 2 and $w->stop();
});

// 循环,直到调用 Ev::stop() 或所有观察器停止
Ev::run();

// 启动并查看它是否有效
$w_stopped->start();
echo
"运行一次迭代\n";
Ev::run(Ev::RUN_ONCE);

echo
"重新启动第二个观察器,并尝试处理相同的事件,但不要阻塞\n";
$w2->again();
Ev::run(Ev::RUN_NOWAIT);

$w = new EvTimer(10, 0, function() {});
echo
"正在运行阻塞循环\n";
Ev::run();
echo
"结束\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 来访问套接字

<?php
/* 使用异步 I/O 访问套接字 */

// `sockets` 扩展仍然会记录警告
// 对于 EINPROGRESS、EAGAIN/EWOULDBLOCK 等。
error_reporting(E_ERROR);

$e_nonblocking = array (/*EAGAIN 或 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() 失败:原因: "
.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("写入 $in 到套接字失败", E_USER_ERROR);
}

$read_watcher = new EvIo($socket, Ev::READ, function ($w, $re)
use (
$socket, $e_nonblocking)
{
// 套接字可读。使用非阻塞模式接收() 20 字节
$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;

/*
* 查看是否有机会获取一个有效的循环
* (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 后端(通常适用于任何 kqueue 实现)。
* 将仅 kqueue/套接字的事件循环存储在 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 信号\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);
}
?>
添加注释

用户贡献的注释

此页面没有用户贡献的注释。
To Top