Exemplos
Example #1 Temporizadores simples
<?php
// Cria e inicia o disparo do cronômetro após 2 segundos
$w1 = new EvTimer(2, 0, function () {
echo "2 segundos se passaram\n";
});
// Cria e inicia o disparo do temporizador após 2 segundos, repetindo cada segundo
// até pararmos manualmente
$w2 = new EvTimer(2, 1, function ($w) {
echo "é chamado a cada segundo, é iniciado após 2 segundos\n";
echo "iteração = ", Ev::iteration(), PHP_EOL;
// Para o observador após 5 iterações
Ev::iteration() == 5 and $w->stop();
// Para o observador se outras chamadas causarem mais de 10 iterações
Ev::iteration() >= 10 and $w->stop();
});
// Cria um cronômetro parado. Ele ficará inativo até que nós mesmos o iniciemos
$w_stopped = EvTimer::createStopped(10, 5, function($w) {
echo "Retorno de chamada de um timer criado como parado\n";
// Pare o observador após 2 iterações
Ev::iteration() >= 2 and $w->stop();
});
// Faça um loop até que Ev::stop() seja chamado ou todos os observadores parem
Ev::run();
// Comece e veja se funciona
$w_stopped->start();
echo "Execute uma única iteração\n";
Ev::run(Ev::RUN_ONCE);
echo "Reinicie o segundo observador e tente lidar com os mesmos eventos, mas não bloqueie\n";
$w2->again();
Ev::run(Ev::RUN_NOWAIT);
$w = new EvTimer(10, 0, function() {});
echo "Executando um loop de bloqueio\n";
Ev::run();
echo "FIM\n";
?>
O exemplo acima produzirá algo semelhante a:
2 segundos se passaram é chamado a cada segundo, é iniciado após 2 segundos iteração = 1 é chamado a cada segundo, é iniciado após 2 segundos iteração = 2 é chamado a cada segundo, é iniciado após 2 segundos iteração = 3 é chamado a cada segundo, é iniciado após 2 segundos iteração = 4 é chamado a cada segundo, é iniciado após 2 segundos iteração = 5 Execute uma única iteração Retorno de chamada de um timer criado como parado Reinicie o segundo observador e tente lidar com os mesmos eventos, mas não bloqueie Executando um loop de bloqueio é chamado a cada segundo, é iniciado após 2 segundos iteração = 8 é chamado a cada segundo, é iniciado após 2 segundos iteração = 9 é chamado a cada segundo, é iniciado após 2 segundos iteração = 10 FIM
Example #2 Temporizador periódico. Marcação a cada 10,5 segundos
<?php
$w = new EvPeriodic(0., 10.5, NULL, function ($w, $revents) {
echo time(), PHP_EOL;
});
Ev::run();
?>
Example #3 Temporizador periódico. Usar retorno de chamada de reagendamento
<?php
// Marcação a cada 10,5 segundos
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();
?>
Example #4 Temporizador periódico. Marcação a cada 10,5 segundos a partir de agora
<?php
// Marcação a cada 10,5 segundos a partir de agora
$w = new EvPeriodic(fmod(Ev::now(), 10.5), 10.5, NULL, function ($w, $revents) {
echo time(), PHP_EOL;
});
Ev::run();
?>
Example #5 Espera até que STDIN esteja legível
<?php
// Espera até que STDIN esteja legível
$w = new EvIo(STDIN, Ev::READ, function ($watcher, $revents) {
echo "STDIN está legível\n";
});
Ev::run(Ev::RUN_ONCE);
?>
Example #6 Usa alguma E/S assíncrona para acessar um socket
<?php
/* Usa alguma E/S assíncrona para acessar um socket */
// A extensão `sockets' ainda registra avisos
// para EINPROGRESS, EAGAIN/EWOULDBLOCK etc.
error_reporting(E_ERROR);
$e_nonblocking = array (/*EAGAIN or EWOULDBLOCK*/11, /*EINPROGRESS*/115);
// Obtém a porta do serviço WWW
$service_port = getservbyname('www', 'tcp');
// Obtém o endereço IP do host alvo
$address = gethostbyname('google.co.uk');
// Cria um socket TCP/IP
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === FALSE) {
echo "socket_create() falhow: rasão: "
.socket_strerror(socket_last_error()) . "\n";
}
// Define a opção O_NONBLOCK
socket_set_nonblock($socket);
// Aborta no tempo limite
$timeout_watcher = new EvTimer(10.0, 0., function () use ($socket) {
socket_close($socket);
Ev::stop(Ev::BREAK_ALL);
});
// Faz a solicitação HEAD quando o socket é gravável
$write_watcher = new EvIo($socket, Ev::WRITE, function ($w)
use ($socket, $timeout_watcher, $e_nonblocking)
{
// Para o observador de tempo limite
$timeout_watcher->stop();
// Para de escrever o observador
$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("Falha ao escrever $in no socket", E_USER_ERROR);
}
$read_watcher = new EvIo($socket, Ev::READ, function ($w, $re)
use ($socket, $e_nonblocking)
{
// O socket é legível. recv() 20 bytes usando modo sem bloqueio
$ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);
if ($ret) {
echo $out;
} elseif ($ret === 0) {
// Tudo lido
$w->stop();
socket_close($socket);
return;
}
// Captura EINPROGRESS, EAGAIN, ou 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();
?>
O exemplo acima produzirá algo semelhante a:
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
Example #7 Incorporando um loop em outro
<?php
/*
* Tenta obter um loop de eventos incorporável e incorporá-lo ao loop de eventos padrão.
* Se for impossível, usa o loop padrão
* O loop padrão é armazenado em $loop_hi, enquanto o loop incorporável é
* armazenado em $loop_lo(que é $loop_hi no caso de nenhum loop incorporável poder ser
* usado).
*
* Amostra traduzida para PHP
* http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Examples_CONTENT-9
*/
$loop_hi = EvLoop::defaultLoop();
$loop_lo = NULL;
$embed = NULL;
/*
* Veja se há chance de conseguir um que funcione
* (o valor 0 dos sinalizadores significa autodetecção)
*/
$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;
}
?>
Example #8 Incorporando loop criado com back-end kqueue no loop padrão
<?php
/*
* Verifica se o kqueue está disponível, mas não é recomendado, e cria um backend kqueue
* para uso com sockets (que geralmente funcionam com qualquer implementação do kqueue).
* Armazena o loop de eventos kqueue/socket somente em loop_socket. (Pode-se opcionalmente
* usar EVFLAG_NOENV também)
*
* Exemplo emprestado de
* 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;
}
// Agora use $socket_loop para todos os sockets e $loop para qualquer outro
?>
Example #9 Lidar com sinal SIGTERM
<?php
$w = new EvSignal(SIGTERM, function ($watcher) {
echo "SIGTERM recebido\n";
$watcher->stop();
});
Ev::run();
?>
Example #10 Monitora alterações de /var/log/messages
<?php
// Usa intervalo de atualização de 10 segundos.
$w = new EvStat("/var/log/messages", 8, function ($w) {
echo "/var/log/messages mudou\n";
$attr = $w->attr();
if ($attr['nlink']) {
printf("Tamanho atual: %ld\n", $attr['size']);
printf("atime atual: %ld\n", $attr['atime']);
printf("mtime atual: %ld\n", $attr['mtime']);
} else {
fprintf(STDERR, "O arquivo `messages` não existe!");
$w->stop();
}
});
Ev::run();
?>
Example #11 Monitora as alterações de /var/log/messages. Evita perder atualizações com um atraso de um segundo
<?php
$timer = EvTimer::createStopped(0., 1.02, function ($w) {
$w->stop();
$stat = $w->data;
// 1 segundo após a alteração mais recente do arquivo
printf("Tamanho atual: %ld\n", $stat->attr()['size']);
});
$stat = new EvStat("/var/log/messages", 0., function () use ($timer) {
// Redefine o observador do cronômetro
$timer->again();
});
$timer->data = $stat;
Ev::run();
?>
Example #12 Mudanças de status de processo
<?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("Processo %d encerrado com status %d\n", $w->rpid, $w->rstatus);
});
Ev::run();
// Proteção contra zumbis
pcntl_wait($status);
} else {
//filho bifurcado
exit(2);
}
?>