golang 调用 php7详解及实例


Posted in PHP onJanuary 04, 2017

执行php文件

func Test_exec(t *testing.T) {
  engine.Initialize()
  ctx := &engine.Context{
    Output: os.Stdout,
  }
  err := engine.RequestStartup(ctx)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.RequestShutdown(ctx)
  err = ctx.Exec("/tmp/index.php")
  if err != nil {
    fmt.Println(err)
  }
}

其中 /tmp/index.php 的内容为

<?php
echo("hello\n");

Eval,返回值

func Test_eval(t *testing.T) {
  engine.Initialize()
  ctx := &engine.Context{}
  err := engine.RequestStartup(ctx)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.RequestShutdown(ctx)
  val, err := ctx.Eval("return 'hello';")
  if err != nil {
    fmt.Println(err)
  }
  defer engine.DestroyValue(val)
  if engine.ToString(val) != "hello" {
    t.FailNow()
  }
}

返回的value的生命周期所有权是golang程序,所以我们要负责DestroyValue

设置全局变量来传参

func Test_argument(t *testing.T) {
  engine.Initialize()
  ctx := &engine.Context{}
  err := engine.RequestStartup(ctx)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.RequestShutdown(ctx)
  err = ctx.Bind("greeting", "hello")
  if err != nil {
    fmt.Println(err)
  }
  val, err := ctx.Eval("return $greeting;")
  if err != nil {
    fmt.Println(err)
  }
  defer engine.DestroyValue(val)
  if engine.ToString(val) != "hello" {
    t.FailNow()
  }
}

传递进去的参数的生命周期是php控制的,在request shutdown的时候内存会被释放。

PHP 回调 Golang

type greetingProvider struct {
  greeting string
}

func (provider *greetingProvider) GetGreeting() string {
  return provider.greeting
}

func newGreetingProvider(args []interface{}) interface{} {
  return &greetingProvider{
    greeting: args[0].(string),
  }
}

func Test_callback(t *testing.T) {
  engine.Initialize()
  ctx := &engine.Context{}
  err := engine.RequestStartup(ctx)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.RequestShutdown(ctx)
  err = engine.Define("GreetingProvider", newGreetingProvider)
  if err != nil {
    fmt.Println(err)
  }
  val, err := ctx.Eval(`
  $greetingProvider = new GreetingProvider('hello');
  return $greetingProvider->GetGreeting();`)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.DestroyValue(val)
  if engine.ToString(val) != "hello" {
    t.FailNow()
  }
}

PHP 错误日志

func Test_log(t *testing.T) {
  engine.PHP_INI_PATH_OVERRIDE = "/tmp/php.ini"
  engine.Initialize()
  ctx := &engine.Context{
    Log: os.Stderr,
  }
  err := engine.RequestStartup(ctx)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.RequestShutdown(ctx)
  _, err = ctx.Eval("error_log('hello', 4); trigger_error('sent from golang', E_USER_ERROR);")
  if err != nil {
    fmt.Println(err)
  }
}

其中 /tmp/php.ini 的内容为

error_reporting = E_ALL
error_log = "/tmp/php-error.log"

错误会被输出到 /tmp/php-error.log。直接调用error_log会同时再输出一份到stderr

HTTP 输入输出

func Test_http(t *testing.T) {
  engine.Initialize()
  recorder := httptest.NewRecorder()
  ctx := &engine.Context{
    Request: httptest.NewRequest("GET", "/hello", nil),
    ResponseWriter: recorder,
  }
  err := engine.RequestStartup(ctx)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.RequestShutdown(ctx)
  _, err = ctx.Eval("echo($_SERVER['REQUEST_URI']);")
  if err != nil {
    fmt.Println(err)
  }
  body, err := ioutil.ReadAll(recorder.Result().Body)
  if err != nil {
    fmt.Println(err)
  }
  if string(body) != "/hello" {
    t.FailNow()
  }
}

所有的PHP超级全局变量都会被初始化为传递进去的Request的值,包括

$_SERVER
$_GET
$_POST
$_FILE
$_COOKIE
$_ENV

echo的内容,http code和http header会被写回到传入的ResponseWriter

fastcgi_finish_request

PHP-FPM 很常用的一个功能是 fastcgi_finish_request ,用于在php里做一些异步完成的事情。这个特殊的全局函数必须支持

func Test_fastcgi_finish_reqeust(t *testing.T) {
  engine.Initialize()
  buffer := &bytes.Buffer{}
  ctx := &engine.Context{
    Output: buffer,
  }
  err := engine.RequestStartup(ctx)
  if err != nil {
    fmt.Println(err)
  }
  defer engine.RequestShutdown(ctx)
  ctx.Eval("ob_start(); echo ('hello');")
  if buffer.String() != "" {
    t.FailNow()
  }
  ctx.Eval("fastcgi_finish_request();")
  if buffer.String() != "hello" {
    t.FailNow()
  }
}

实际的作用就是把output提前输出到 ResposneWriter 里去,让调用方知道结果。对于当前进程的执行其实是没有影响的,只是影响了output。

 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

PHP 相关文章推荐
php 多线程上下文中安全写文件实现代码
Dec 28 PHP
PHP开发环境配置(MySQL数据库安装图文教程)
Apr 28 PHP
php设计模式 Interpreter(解释器模式)
Jun 26 PHP
114啦源码(114la)不能生成地方房产和地方报刊问题4级页面0字节的解决方法
Jan 12 PHP
php自动给文章加关键词链接的函数代码
Nov 29 PHP
基于php冒泡排序算法的深入理解
Jun 09 PHP
基于xcache的配置与使用详解
Jun 18 PHP
php实现水仙花数的4个示例分享
Apr 08 PHP
php中file_get_content 和curl以及fopen 效率分析
Sep 19 PHP
PHP中的socket_read和socket_recv区别详解
Feb 09 PHP
PHP也能干大事之PHP中的编码解码详解
Apr 20 PHP
PHP中rename()函数的妙用讲解
Feb 28 PHP
PHP 与 UTF-8 的最佳实践详细介绍
Jan 04 #PHP
详解Yii2 定制表单输入字段的标签和样式
Jan 04 #PHP
PHPExcel导出2003和2007的excel文档功能示例
Jan 04 #PHP
CI框架实现优化文件上传及多文件上传的方法
Jan 04 #PHP
PHP搭建大文件切割分块上传功能示例
Jan 04 #PHP
php实现的简单中文验证码功能示例
Jan 03 #PHP
php与c 实现按行读取文件实例代码
Jan 03 #PHP
You might like
PHP 字符串加密函数(在指定时间内加密还原字符串,超时无法还原)
2010/04/28 PHP
PHP中根据IP地址判断城市实现城市切换或跳转代码
2012/09/04 PHP
php sybase_fetch_array使用方法
2014/04/15 PHP
php使用gd2绘制基本图形示例(直线、圆、正方形)
2017/02/15 PHP
查找页面中所有类为test的结点的方法
2014/03/28 Javascript
jQuery实现鼠标经过图片变亮其他变暗效果
2015/05/08 Javascript
jquery淡入淡出效果简单实例
2016/01/14 Javascript
浅析Javascript中bind()方法的使用与实现
2016/05/30 Javascript
jQuery Jsonp跨域模拟搜索引擎
2017/06/17 jQuery
jQuery+Ajax请求本地数据加载商品列表页并跳转详情页的实现方法
2017/07/12 jQuery
Cpage.js给组件绑定事件的实现代码
2017/08/31 Javascript
浅谈vue中.vue文件解析流程
2018/04/24 Javascript
vuejs实现折叠面板展开收缩动画效果
2018/09/06 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
JavaScript常用内置对象用法分析
2019/07/09 Javascript
ES6中异步对象Promise用法详解
2019/07/31 Javascript
小程序分享链接onShareAppMessage的具体用法
2020/05/22 Javascript
解决VUE项目使用Element-ui 下拉组件的验证失效问题
2020/11/07 Javascript
JavaScript实现通讯录功能
2020/12/27 Javascript
浅谈Python的异常处理
2016/06/19 Python
python批量修改图片尺寸,并保存指定路径的实现方法
2019/07/04 Python
Django中的FBV和CBV用法详解
2019/09/15 Python
Python执行时间的几种计算方法
2020/07/31 Python
Python用户自定义异常的实现
2020/12/25 Python
香港时尚女装购物网站:ZAFUL
2017/07/19 全球购物
写一个在SQL Server创建表的SQL语句
2012/03/10 面试题
国际政治个人自荐信范文
2013/11/26 职场文书
关爱女孩行动实施方案
2014/03/13 职场文书
2014年国庆节活动总结
2014/08/26 职场文书
师德师风自查材料
2014/10/14 职场文书
合作合同协议书范本
2015/01/27 职场文书
四大名著读书笔记
2015/06/25 职场文书
2019个人工作态度自我评价
2019/04/24 职场文书
GO语言字符串处理函数之处理Strings包
2022/04/14 Golang
MySQL的prepare使用以及遇到的bug
2022/05/11 MySQL
Redis全局ID生成器的实现
2022/06/05 Redis