PHP实现类似javascript的setTimeout异步回调

广告位招租
扫码页面底部二维码联系

在php中,我们偶尔会希望这样的场景:当【原创不易,请尊重版权】【原创内容,转载请注明出处】执行某段程序的时候,需要执行某个任务,但【未经授权禁止转载】【作者:唐霜】是该任务并不需要立即执行,而是需要延迟几【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net秒再执行。这个功能正如javascrip【原创不易,请尊重版权】原创内容,盗版必究。t的setTimeout,但是php中并【本文受版权保护】本文版权归作者所有,未经授权不得转载。没有现成的异步功能,php的单线程的,所转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。以要实现这个效果,我们还需要想想其他的办【转载请注明来源】【关注微信公众号:wwwtangshuangnet】法。

【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】【本文受版权保护】

不过幸运的是,php中提供了一种非阻塞的原创内容,盗版必究。【本文首发于唐霜的博客】通信方式。因此,我们创建下面这个类:

【访问 www.tangshuang.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;
    }
}

我们来看下具体的用法:原创内容,盗版必究。

原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。转载请注明出处:www.tangshuang.net
<?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);

接下来我们来解释一下这里面都做了什么。【作者:唐霜】

原创内容,盗版必究。【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。

首先,sock()方法【关注微信公众号:wwwtangshuangnet】

著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】【作者:唐霜】【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。

我们来具体分析一下sock方法中fsoc【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.netkopen的用法。fsockopen开启【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。了一个fsock通信,stream_se本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】t_blocking()函数的第二个参数著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。设置为0,声明这个fsock为非阻塞模式本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。,也就是说,下次在调用$this->【本文首发于唐霜的博客】【版权所有,侵权必究】;sock()的时候,程序是流畅执行的,【作者:唐霜】【原创内容,转载请注明出处】fsock发出请求时,不会阻塞进程,fs【版权所有】唐霜 www.tangshuang.net【本文受版权保护】ock发出请求后就继续往下执行,而无需得原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。到结果。

【原创不易,请尊重版权】【原创不易,请尊重版权】【转载请注明来源】转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】

fsock使用fwrite或fput发出【原创内容,转载请注明出处】【原创不易,请尊重版权】请求,其中第二个参数需要我们自己构造ht【作者:唐霜】【版权所有,侵权必究】tp header信息,你需要了解htt本文作者:唐霜,转载请注明出处。【未经授权禁止转载】p协议的东西,构造header可以帮我们【原创不易,请尊重版权】【本文首发于唐霜的博客】实现get、post、head、put、【本文首发于唐霜的博客】转载请注明出处:www.tangshuang.netdelete等多种请求方式。

【原创内容,转载请注明出处】【转载请注明来源】【原创不易,请尊重版权】【未经授权禁止转载】

总之,sock()方法,帮我们实现非阻塞【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】的发出请求。

【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net

其次,异步执行【原创内容,转载请注明出处】

原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】【原创不易,请尊重版权】【原创内容,转载请注明出处】

我们来看下__construct()方法本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net中的 if(isset($this->headers['auth']) && $this->headers['auth'] == $this->auth) 的内容。【原创不易,请尊重版权】

【版权所有,侵权必究】转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。
ignore_user_abort();
set_time_limit(0);

这两句可以帮助程序在后台继续执行,即使访本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】问被客户端关闭,也就是说fsock发出的原创内容,盗版必究。未经授权,禁止复制转载。非阻塞请求虽然并没有等结果返回,但是我们【作者:唐霜】【本文受版权保护】如此声明以后,程序仍然会继续执行,不会被未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。中断。

【版权所有,侵权必究】【转载请注明来源】【版权所有,侵权必究】【访问 www.tangshuang.net 获取更多精彩内容】【版权所有,侵权必究】
call_user_func(array($this,$event.'Callback'),$data);

这句则是调用当前事件的回调函数(方法),本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】这里就是$this->setTim本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。eoutCallback(),而在set【作者:唐霜】本文版权归作者所有,未经授权不得转载。TimeoutCallback()中,使著作权归作者所有,禁止商业用途转载。【作者:唐霜】用了

未经授权,禁止复制转载。【访问 www.tangshuang.net 获取更多精彩内容】【本文首发于唐霜的博客】【未经授权禁止转载】【访问 www.tangshuang.net 获取更多精彩内容】
call_user_func($function);

也就是调用我们第二段代码中规定的那个se【版权所有】唐霜 www.tangshuang.net【作者:唐霜】tTimeout()函数。

原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net【原创内容,转载请注明出处】

最后,回调函数【本文受版权保护】

【作者:唐霜】本文版权归作者所有,未经授权不得转载。【转载请注明来源】【本文首发于唐霜的博客】原创内容,盗版必究。

而这个setTimeout()函数就是回【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】调函数,它会在fsock请求的终端进行执原创内容,盗版必究。本文作者:唐霜,转载请注明出处。行,而它的执行将会开启一个新的php进程【作者:唐霜】【版权所有,侵权必究】,不会影响当前的这个页面的程序的执行(虽【访问 www.tangshuang.net 获取更多精彩内容】著作权归作者所有,禁止商业用途转载。然它是被写在当前页面内的)。

原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。【作者:唐霜】

关于php的进程,请阅读《【版权所有】唐霜 www.tangshuang.netPHP进程分支设计著作权归作者所有,禁止商业用途转载。》,了解php单线程的局限。【版权所有】唐霜 www.tangshuang.net

【访问 www.tangshuang.net 获取更多精彩内容】【作者:唐霜】原创内容,盗版必究。

总之,你只需要在你的程序中引入Async转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】Callback类,并且实例化后如下操作【转载请注明来源】转载请注明出处:www.tangshuang.net即可:

【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】原创内容,盗版必究。
$AsyncCallback = new AsyncCallback();
$AsyncCallback->setTimeout('setTimeout',10);
function setTimeout() {    // 延时执行的代码
}

不过,本类的使用,也有一些缺陷:本文版权归作者所有,未经授权不得转载。

转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】
  • 和javascript不同,该类不能在界【关注微信公众号:wwwtangshuangnet】【作者:唐霜】面展示上实现异步展示,而只能实现任务上的转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。异步
  • 本文作者:唐霜,转载请注明出处。【本文首发于唐霜的博客】【本文受版权保护】
  • 必须在页面开头的地方实例化类,因为回调是未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。在类的构造方法中实现的
  • 著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。【本文首发于唐霜的博客】【原创不易,请尊重版权】
  • 不能和主进程通信,这一点是最大的缺陷【原创不易,请尊重版权】
  • 著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。【转载请注明来源】【原创不易,请尊重版权】

2016-02-18 13654

为价值买单,打赏一杯咖啡

本文价值136.54RMB