当前位置: 首页 > news >正文

PHP客户端调用由Go服务端GRPC接口

一.安装和配置

1.本地windows下安装php的gprc和protobuf扩展:
gRPC扩展:(php7.4.3nts)
https://pecl.php.net/package/gRPC/1.43.0/windows

protobuf扩展:
https://pecl.php.net/package/protobuf/3.24.4/windows

将下载的dll文件放到对应php版本的ext文件下:D:\phpstudy_pro\Extensions\php\php7.4.3nts
再修改对应php版本的php.ini文件添加:
extension="D:/phpstudy_pro/Extensions/php/php7.4.3nts/php_grpc.dll"
extension=D:/phpstudy_pro/Extensions/php/php7.4.3nts/php_protobuf.dll

重启nginx然后在pathinfo()查看或者执行下面的命令看是否有grpc和protobuf扩展

2.composer安装包grpc和protobuf:
composer require google/protobuf:3.24.4 
composer require grpc/grpc:^1.42.0   (由于提示1.43.0不存在 则按照1.42.x系列最新版)


3.本地使用grpc_php_plugin插件 可以生成对应proto的php文件

可以通过git clone https://github.com/lifenglsf/grpc_for_windows.git 下载到本地,然后查看文件夹下对应系统的grpc_php_plugin.exe文件

或者在https://github.com/protocolbuffers/protobuf/releases/tag/v3.9.0下面下载对应的版本
(我的是在grpc_for_windows/x64/grpc_php_plugin.exe)

二.指定proto文件生成对应的php文件

1.将go的grpc文件复制到laravel框架:

/protos/food :里面有common.proto和user.proto如下,新增命名空间

2.执行命令将proto文件生成对应php文件(project下有generator和generate_grpc.sh文件)

(1)这里使用了swoole/grpc里面的./generator 可以自动生成所有proto文件对应的php文件,不用单个proto文件去生成

./generator文件内容如下:

#!/usr/bin/env php
<?php
/*+----------------------------------------------------------------------+| Swoole-gRPC                                                   |+----------------------------------------------------------------------+| This source file is subject to version 2.0 of the Apache license,    || that is bundled with this package in the file LICENSE, and is        || available through the world-wide-web at the following url:           || http://www.apache.org/licenses/LICENSE-2.0.html                      || If you did not receive a copy of the Apache2.0 license and are unable|| to obtain it through the world-wide-web, please send a note to       || license@swoole.com so we can mail you a copy immediately.            |+----------------------------------------------------------------------+| Author: Twosee <twose@qq.com>                                        |+----------------------------------------------------------------------+
*/function scan_dir(string $dir, callable $filter = null): array
{$files = scandir($dir);$files = array_filter($files, function (string $f) {return $f[0] !== '.';});array_walk($files, function (string &$value) use ($dir) {$value = rtrim($dir, '/') . '/' . $value;});return array_values($filter ? array_filter($files, $filter) : $files);
}function generateClient(string $proto_dir)
{#下面的文件名需要修改!!!!!!!!!!!$proto_dir = 'D:\project\udc\app\Grpc\Protos\Food';echo $proto_dir;$source_dirs = scan_dir($proto_dir, function (string $f) use ($proto_dir) {return is_dir($f);});$php_files = [];foreach ($source_dirs as $source_dir) {$php_files[] = scan_dir($source_dir, function (string $f) {return substr($f, -4, 4) === '.php';});}$php_files = array_merge(...$php_files);foreach ($php_files as $php_file) {$file_content = file_get_contents($php_file);$extends_keyword = ' extends \Grpc\BaseStub';if (strpos($file_content, $extends_keyword) !== false) {// $filename = explode('/', $php_file);// $filename = end($filename);// use swoole construct$file_content = str_replace('__construct($hostname, $opts, $channel','__construct($hostname, $opts',$file_content);// fit swoole arguments$file_content = str_replace('$opts = null', '$opts = []', $file_content);// use correct return value$file_content = preg_replace_callback('/(call options)(\n([ ]+?)\*\/\n[ ]+?public function[\s\S]+?(_\w+Request)[\s\S]+?\[\'([^\']+)\', ?\'\w+\'\],)/',function (array $match) {switch ($match[4]) {case '_simpleRequest':return "{$match[1]}\n{$match[3]}* @return {$match[5]}[]|\\Grpc\\StringifyAble[]{$match[2]}";case '_bidiRequest':return "{$match[1]}\n{$match[3]}* @return bool|\\Grpc\\BidiStreamingCall{$match[2]}";case '_serverStreamRequest':return "{$match[1]}\n{$match[3]}* @return bool|\\Grpc\\ServerStreamingCall{$match[2]}";case '_clientStreamRequest':return "{$match[1]}\n{$match[3]}* @return bool|\\Grpc\\ClientStreamingCall{$match[2]}";}return $match[0];},$file_content);file_put_contents($php_file, $file_content);}}
}function generateFromProto(string $proto_path, string $php_out, string $grpc_out, string $plugin, array $proto_list)
{$plugin_file = explode('=', $plugin)[1] ?? null;if (!$plugin_file) {$plugin = "protoc-gen-grpc={$plugin}";}if (!file_exists($plugin_file)) {exit("Can't find the plugin generator file [{$plugin_file}]");}function realGenerate($proto_path, $php_out, $grpc_out, $plugin, array $proto_list){foreach ($proto_list as $key => $proto_file) {if (is_dir($proto_file)) {$proto_deep_list = scan_dir($proto_file, function (string $f) {return substr($f, -6, 6) === '.proto';});realGenerate($proto_path, $php_out, $grpc_out, $plugin, $proto_deep_list);} else {`protoc --proto_path={$proto_path} --php_out={$php_out} --grpc_out={$grpc_out} --plugin={$plugin} {$proto_file}`;}}}realGenerate($proto_path, $php_out, $grpc_out, $plugin, $proto_list);
}function get_command(&$command, &$options, &$params): void
{global $argv;$arguments = $argv;$command = '';//命令$options = [];//选项$params = []; //参数array_shift($arguments);if (isset($arguments[0]) && substr($arguments[0], 0, 1) !== '-') {$command = array_shift($arguments); //指定第一个参数为命令}foreach ($arguments as $i => $v) {if (empty($v)) {continue;} elseif (substr($v, 0, 2) === '--') {$now = substr($v, 2);$now = explode('=', $now);$options[trim(array_shift($now))] = trim(implode('=', $now));} else {$params[] = $v;}}
}(function () {get_command($command, $options, $params);if (empty($command)) {$needle_params = ['proto_path' => null,'php_out' => null,'grpc_out' => null,'plugin' => __DIR__ . './../../grpc/bins/opt/grpc_php_plugin'];$proto_path = $php_out = $grpc_out = $plugin = '';foreach ($needle_params as $param_name => $param_default_value) {if (empty($options[$param_name])) {if ($param_default_value === null) {exit("{$param_name} is missing!");} else {$options[$param_name] = $param_default_value;}} else {if ($param_name === 'php_out') {$needle_params['grpc_out'] = $options[$param_name];}}$$param_name = $options[$param_name];}generateFromProto($proto_path, $php_out, $grpc_out, $plugin, $params);
//        generateClient($php_out);}
})();

(2)generate_grpc.sh文件内容如下:

#!/usr/bin/env bash# 指定food的proto文件生成php文件# 生成代码
# 1.protoc-gen-grpc需要指向本地grpc_php_plugin.exe所在位置
# 2.指定要生成的proto文件
./generator \
--proto_path=./protos \
--php_out=./ \
--grpc_out=./ \
--plugin=protoc-gen-grpc=../grpc_for_windows/x64/grpc_php_plugin.exe \
./protos/food
#上述文件名(/protos/food)需要对应修改!!!!!!!!!!!
echo "gRPC 代码已重新生成到 app/Grpc下"
sleep(2)#双击该文件执行或执行 ./generate_grpc.sh ../grpc_for_windows/x64/grpc_php_plugin.exe
#即可生成对应proto的php文件

(3)生成:

双击generate_grpc.sh文件

或执行 ./generate_grpc.sh ../grpc_for_windows/x64/grpc_php_plugin.exe

即可生成对应proto的php文件

# 这里是在laravel框架.env同级目录下执行
# --php_out php代码输出路径,里面包含request,response,client代码
# --grpc_out GPBMetadata输出路径,用于保存.proto的二进制元数据
# --plugin 生成代码插件的类型与插件的绝对路径路径

三.调用go服务端接口

            $metaData = ['Sign' => [$sign],'TimeStamp' => [(string)$requestTime],];$request = new CommonRequest();$request->setData($paramData);$hostname =  '127.0.0.1:8081';$opts = ['credentials' => ChannelCredentials::createInsecure()];$client = new UserClient($hostname,$opts);list($response, $status) = $client->UserInfo($request, $metaData)->wait();if ($status->code !== \Grpc\STATUS_OK) {Log::error("gRPC调用失败: 状态码={$status->code}, 错误详情={$status->details}");}if($response!=null){$responseData = json_decode($response->serializeToJsonString(), true);}

四.go配置详见

http://www.dtcms.com/a/604916.html

相关文章:

  • Java 开发 - 粘包处理器 - 基于消息头 + 消息体
  • dify零基础入门示例
  • 跨语言智能再升级!Multi-LMentry 打造多语理解新基准;Nemotron-Personas-USA重塑虚拟人画像生成
  • 门户网站建设项目书免费拒绝收费网站
  • 研发管理知识库(13)阿里云的DevOps工具介绍
  • WPF 使用UserControl / ContentControl显示子界面
  • Docker 的底层工作原理
  • 互联网门户网站是什么意思网站建设 源美设计
  • 重庆商业网站有哪些产品网站建设方案
  • C基础学习过程02
  • 视频矩阵哪个品牌好 十大视频矩阵品牌
  • 电子书《21天学通Java(第5版)》
  • maven 私服上传jar
  • 从自动驾驶到智能辅导:人工智能如何重塑商业与生活
  • Hadess入门到精通 - 如何管理通用Generic制品
  • 万物互联时代,如何选择合适的时序数据库?
  • 集团门户网站建设做国外网站要注意什么
  • 软件设计模式-适配器模式
  • 软件工程(速成笔记)
  • 深圳苏州企业网站建设服务公司网站建设很难吗
  • sward实战教程系列(4) - 如何编写Markdown文档
  • 树莓派5-ubuntu 24.04 ros-jazzy-desktop 创建 robot_navigation 包
  • 【Linux】调试监听接口是否正常
  • Flink CDC + StarRocks用 StarRocks Connector 打通实时明细与分析
  • Linux《Socket编程Tcp》
  • 2025.11.13 力扣每日一题
  • “暗激子(dark excitons)” 以 30万倍亮度被观测到
  • 数据归一化:提升模型训练的关键技巧
  • 网站外链建设可以提升网站权重对吗三亚平台公司
  • 怎么做一种网站为别人宣传lamp 做网站