在php中,我们偶尔会希望这样的场景:当【转载请注明来源】原创内容,盗版必究。执行某段程序的时候,需要执行某个任务,但未经授权,禁止复制转载。【原创不易,请尊重版权】是该任务并不需要立即执行,而是需要延迟几本文作者:唐霜,转载请注明出处。原创内容,盗版必究。秒再执行。这个功能正如javascrip【版权所有】唐霜 www.tangshuang.net【版权所有,侵权必究】t的setTimeout,但是php中并本文作者:唐霜,转载请注明出处。【原创内容,转载请注明出处】没有现成的异步功能,php的单线程的,所【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。以要实现这个效果,我们还需要想想其他的办转载请注明出处:www.tangshuang.net【转载请注明来源】法。
【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。不过幸运的是,php中提供了一种非阻塞的【原创不易,请尊重版权】【版权所有,侵权必究】通信方式。因此,我们创建下面这个类:
原创内容,盗版必究。【转载请注明来源】著作权归作者所有,禁止商业用途转载。【版权所有】唐霜 www.tangshu本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。ang.net<?php
class AsyncCallback {
private $auth;
public function __construct() {
$this->auth = substr(md5('iosnae23a9a~40^33fsdf.adsfie*'),8,16); // 修改内容,作为密钥
$headers = array();
foreach ($_SERVER as $key => $value) {
if('HTTP_' == substr($key,0,5)) {
$key = substr($key,5);
$key = strtolower($key);
$headers[$key] = $value;
}
}
$this->headers = $headers;
if(isset($this->headers['auth']) && $this->headers['auth'] == $this->auth) {
ignore_user_abort();
set_time_limit(0);
$event = $this->headers['event'];
$data = $this->headers['data'];
parse_str($data,$data);
call_user_func(array($this,$event.'Callback'),$data);
exit;
}
}
public function setTimeout($function,$timeout) {
$this->sock('setTimeout',array('function' => $function,'timeout' => $timeout));
}
private function setTimeoutCallback($data) {
$function = $data['function'];
$timeout = $data['timeout'];
sleep($timeout);
call_user_func($function);
}
private function sock($event,$data) {
$url = $this->current_url();
$host = parse_url($url,PHP_URL_HOST);
$path = parse_url($url,PHP_URL_PATH);
$query = parse_url($url,PHP_URL_QUERY);
if($query)
$path .= '?'.$query;
$port = parse_url($url,PHP_URL_PORT);
$port = $port ? $port : 80;
$scheme = parse_url($url,PHP_URL_SCHEME);
if($scheme == 'https')
$host = 'ssl://'.$host;
$data = http_build_query($data);
$fp = fsockopen($host,$port,$errno,$errstr,1);
if(!$fp) {
return false;
}
stream_set_blocking($fp,0);
stream_set_timeout($fp,1);
$header = "GET $path / HTTP/1.1\r";
$header .= "Host: $host\r";
$header .= "Event: $event\r";
$header .= "Data: $data\r";
$header .= "Auth: {$this->auth}\r";
$header .= "Connection: Close\r\r";
fwrite($fp,$header);
fclose($fp);
return true;
}
private function current_url() {
$url = $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
if(!isset($_SERVER['HTTPS']))
$url = 'http://'.$url;
elseif($_SERVER['HTTPS'] === 1 || $_SERVER['HTTPS'] === 'on' || $_SERVER['SERVER_PORT'] == 443)
$url = 'https://'.$url;
else
$url = 'http://'.$url;
return $url;
}
}
我们来看下具体的用法:
【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。<?php
require 'AsyncCallback.class.php';
$AsyncCallback = new AsyncCallback();
file_put_contents('./runtime/setTimeout.txt','['.date('Y-m-d H:i:s').']['.microtime().'] 我先处理一点事情',LOCK_EX);
$AsyncCallback->setTimeout('setTimeout',10);
function setTimeout() {
file_put_contents('./runtime/setTimeout.txt',"".'['.date('Y-m-d H:i:s').']['.microtime().'] 我是延时执行的结果',FILE_APPEND);
}
file_put_contents('./runtime/setTimeout.txt',"".'['.date('Y-m-d H:i:s').']['.microtime().'] 我再处理一点事情,看看是否有时间差距',FILE_APPEND);
接下来我们来解释一下这里面都做了什么。
【版权所有】唐霜 www.tangshu【关注微信公众号:wwwtangshuangnet】【关注微信公众号:wwwtangshuangnet】ang.net著作权归作者所有,禁止商业用途转载。【原创不易,请尊重版权】首先,sock()方法
【本文首发于唐霜的博客】本文版权归作者所有,未经授权不得转载。我们来具体分析一下sock方法中fsoc【访问 www.tangshuang.net 获取更多精彩内容】【原创内容,转载请注明出处】kopen的用法。fsockopen开启【版权所有】唐霜 www.tangshuang.net【原创不易,请尊重版权】了一个fsock通信,stream_se著作权归作者所有,禁止商业用途转载。【版权所有】唐霜 www.tangshuang.nett_blocking()函数的第二个参数【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。设置为0,声明这个fsock为非阻塞模式【访问 www.tangshuang.net 获取更多精彩内容】【作者:唐霜】,也就是说,下次在调用$this->【作者:唐霜】本文作者:唐霜,转载请注明出处。;sock()的时候,程序是流畅执行的,【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。fsock发出请求时,不会阻塞进程,fs【未经授权禁止转载】【转载请注明来源】ock发出请求后就继续往下执行,而无需得【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net到结果。
【未经授权禁止转载】【访问 www.tangshuang.n本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】et 获取更多精彩内容】【未经授权禁止转载】fsock使用fwrite或fput发出著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】请求,其中第二个参数需要我们自己构造ht转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。tp header信息,你需要了解htt本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。p协议的东西,构造header可以帮我们本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。实现get、post、head、put、【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。delete等多种请求方式。
【版权所有,侵权必究】【本文首发于唐霜的博客】本文作者:唐霜,转载请注明出处。总之,sock()方法,帮我们实现非阻塞原创内容,盗版必究。【转载请注明来源】的发出请求。
转载请注明出处:www.tangshua未经授权,禁止复制转载。【版权所有,侵权必究】ng.net【转载请注明来源】【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。其次,异步执行
【作者:唐霜】转载请注明出处:www.tangshua本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】ng.net【转载请注明来源】我们来看下__construct()方法著作权归作者所有,禁止商业用途转载。【转载请注明来源】中的 if(isset($this->headers['auth']) && $this->headers['auth'] == $this->auth) 的内容。
ignore_user_abort(); set_time_limit(0);
这两句可以帮助程序在后台继续执行,即使访著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。问被客户端关闭,也就是说fsock发出的【版权所有,侵权必究】未经授权,禁止复制转载。非阻塞请求虽然并没有等结果返回,但是我们著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】如此声明以后,程序仍然会继续执行,不会被【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。中断。
未经授权,禁止复制转载。原创内容,盗版必究。call_user_func(array($this,$event.'Callback'),$data);
这句则是调用当前事件的回调函数(方法),【原创不易,请尊重版权】【本文受版权保护】这里就是$this->setTim【原创内容,转载请注明出处】【访问 www.tangshuang.net 获取更多精彩内容】eoutCallback(),而在set本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】TimeoutCallback()中,使转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】用了
【原创内容,转载请注明出处】【未经授权禁止转载】【转载请注明来源】call_user_func($function);
也就是调用我们第二段代码中规定的那个se【未经授权禁止转载】原创内容,盗版必究。tTimeout()函数。
本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshua未经授权,禁止复制转载。【本文首发于唐霜的博客】ngnet】【转载请注明来源】最后,回调函数
【本文首发于唐霜的博客】【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。而这个setTimeout()函数就是回本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】调函数,它会在fsock请求的终端进行执【本文首发于唐霜的博客】【本文首发于唐霜的博客】行,而它的执行将会开启一个新的php进程著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】,不会影响当前的这个页面的程序的执行(虽著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】然它是被写在当前页面内的)。
【本文首发于唐霜的博客】本文版权归作者所有,未经授权不得转载。关于php的进程,请阅读《PHP进程分支设计》,了解php单线程的局限。
未经授权,禁止复制转载。【版权所有,侵权必究】总之,你只需要在你的程序中引入Async【原创内容,转载请注明出处】【本文首发于唐霜的博客】Callback类,并且实例化后如下操作【转载请注明来源】【转载请注明来源】即可:
未经授权,禁止复制转载。未经授权,禁止复制转载。$AsyncCallback = new AsyncCallback();
$AsyncCallback->setTimeout('setTimeout',10);
function setTimeout() { // 延时执行的代码
}
不过,本类的使用,也有一些缺陷:
【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshua【版权所有,侵权必究】【版权所有,侵权必究】ng.net- 和javascript不同,该类不能在界【访问 www.tangshuang.net 获取更多精彩内容】【关注微信公众号:wwwtangshuangnet】面展示上实现异步展示,而只能实现任务上的未经授权,禁止复制转载。【访问 www.tangshuang.net 获取更多精彩内容】异步 【未经授权禁止转载】未经授权,禁止复制转载。【作者:唐霜】本文版权归作者所有,未经授权不得转载。
- 必须在页面开头的地方实例化类,因为回调是【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.net在类的构造方法中实现的 本文版权归作者所有,未经授权不得转载。【作者:唐霜】
- 不能和主进程通信,这一点是最大的缺陷 著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。
2016-02-18 13863


