php扩展之Yar

  Yar 是一个轻量级, 高效的RPC框架, 它提供了一种简单方法来让PHP项目之间可以互相远程调用对方的本地方法. 并且Yar也提供了并行调用的能力. 可以支持同时调用多个远程服务的方法.

  情况: 有个业务场景,需要本地项目去调用一个服务层的相关方法实现相应的功能,一般情况,我可以通过普通的http的方式进行请求即可,但是如果只是这个服务是内部使用,那么可以使用rpc的方式进行替代.好处自不必多说,基于tcp传输,支持并发

  实例参考:http://hk2.php.net/manual/zh/yar.examples.php

  结合在项目中使用:

    首先介绍服务端:RpcServer.php

<?php 
namespace appindexlogic;
/**
 * rpc基类(服务端)
 */
class RpcServer
{
    private static $signs = [
        'sign1', //不同的来源Salt不同
        'sign2',
    ];

    // 验证签名
    protected function checkSign($params,$sign)
    {
        if(empty($sign)){
            return false;
        }

        ksort($params);
        $signStr = '';
        foreach($params as $key => $val)
        {
            if(empty($val) || $val == $sign) continue;
            $signStr .= $key.'='.$val.'&';
        }

        $signStr = rtrim($signStr,'&');
        foreach (self::$signs as $v){
            if(md5($signStr.$v) === $sign){
                return true;
            }
        }

    }

    // 处理结果
    protected function response($status,$data)
    {
        $response = [
            'status'    =>    $status,
            'message'    =>    '', //状态码对应的信息(从配置文件中获取)
            'data'        =>    $data,
        ];

        return $response;
    }
}

  服务端方法:

    

<?php  
namespace appindexlogic;

class User extends RpcServer
{

    // 用户扩展信息
    public function userExt($ids)
    {
        // 1.验证签名
        // 2.逻辑处理
        // 3.结果返回
        return $ids;
    }

    // 用户基础信息
    public function userBase($ids)
    {
        return $ids;
    }


}

  客户端:RpcClient.php

<?php
namespace appindexlogic;

/**
 * rpc基类(客户端)
 */
class RpcClient
{

    private static $signs = [
        'sign1', //不同来源
        'sign2'
    ];

    private $callBack;
    private $callNum = 0;


    /**
     * 取得签名
     * @param  $params 接口调用时的参数
     */
    protected function getSign($params,$type)
    {
        ksort($params);
        $signStr = '';
        foreach($params as $key => $val)
        {
            if(empty($val)) continue;
            $signStr .= $key.'='.$val.'&';
        }
        $signStr = rtrim($signStr,'&');
        return md5($signStr.self::$signs[$type]);
    }

   /**
     * 调用服务端接口
     * @param  $server      Api server
     * @param  $api         接口
     * @param  $params      参数
     * @param  $openSign    开启签名
     * @param  $callBack    回调
     */ 
    public function call($server,$api,$params,$openSign=false,$callBack=null)
    {
        if($openSign){
            $params['sign'] = $this->getSign($params);
        }
 
        if($callBack === null){
            $client = new Yar_Client($server);
            return call_user_func_array([$client,$api], $params);
        }
        $this->callNum ++;
        $this->callBack = $callBack;
        return Yar_Concurrent_Client::call($server,$api,$params,array($this, 'ApiClientCallBack'));
    }

     /**
     * 执行并发调用
     */
    public function loop()
    {
        return Yar_Concurrent_Client::loop([$this,'callback1'],[$this,'error_callback']); 
    }

     /**
     * 并发调用回调
     * @param  $retval
     * @param  $callinfo
     */
    public function ApiClientCallBack($retval,$callinfo)
    {    
        if($callinfo === null){
            return $this->callBack($retval,$callinfo);
        }

        static $data = array();
        $data[] = $retval; //并发
        if(count($data) == $this->callNum){
            $fn = $this->callBack;
            return $this->$fn($data,$callinfo);
        }
    }

    // 
    public function callback1($retval, $callinfo)
    {
             if ($callinfo == NULL) {
                echo "现在, 所有的请求都发出去了, 还没有任何请求返回
";
             } else {
                echo "这是一个远程调用的返回, 调用的服务名是", $callinfo["method"], 
                              ". 调用的sequence是 " , $callinfo["sequence"] , "
";
                var_dump($retval);
             }
    }

    // 异常回调
    public function error_callback($type, $error, $callinfo)
    {
        error_log(json_encode(func_get_args() ),3,'rpc.log' );
    }

}

  客户端调用:

<?php 
namespace appindexlogic;

// 相关测试
class Test extends RpcClient
{
    public function testRpc()
    {

        $api = 'http://thinkphp.com/index/rpc/users';

        // $this->call($api,'userExt',[1,2],false,'callback');
        $this->call($api,'userBase',[3,4],false,'callback');
        $this->call($api,'userBase',[5],false,'callback');
        $this->loop();

        return false;
        // $client = new yar_client("http://thinkphp.com/index/rpc/user");
        // $ret = $client->userInfo([1,2]);
        // var_dump($ret);
    }

    // 回调数据
    public function callback($data,$callinfo)
    {
        var_dump(func_get_args());die;
        // static $a = [];
        // $a[] = json_encode(func_get_args());
        // print_r($a);
        // error_log(json_encode(func_get_args() ),3,'rpc.log' );
    }
}

  即可实现简单的rpc调用

原文地址:https://www.cnblogs.com/xingxia/p/php_yar.html