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输出控制功能在简繁体转换中的应用
Oct 09 PHP
PHP 和 MySQL 基础教程(三)
Oct 09 PHP
模仿OSO的论坛(二)
Oct 09 PHP
phpMyAdmin 链接表的附加功能尚未激活的问题
Aug 01 PHP
ThinkPHP关联模型操作实例分析
Sep 23 PHP
PHP header()函数使用详细(301、404等错误设置)
Apr 17 PHP
PHP Session 变量的使用方法详解与实例代码
Sep 11 PHP
PHP实现模仿socket请求返回页面的方法
Nov 04 PHP
PHP发送短信代码分享
Aug 11 PHP
详解WordPress中用于合成数组的wp_parse_args()函数
Dec 18 PHP
php实现获取农历(阴历)、节日、节气的类与用法示例
Nov 20 PHP
PHP实现的简单留言板功能示例【基于thinkPHP框架】
Dec 07 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基于CURL进行POST数据上传实例
2014/11/10 PHP
静态html文件执行php语句的方法(推荐)
2016/11/21 PHP
jQuery检测鼠标左键和右键点击的方法
2015/03/17 Javascript
Bootstrap导航条鼠标悬停下拉菜单
2017/01/04 Javascript
JS遍历对象属性的方法示例
2017/01/10 Javascript
微信小程序动态显示项目倒计时效果
2017/06/13 Javascript
Parcel 打包示例(React HelloWorld)
2018/01/16 Javascript
VUE脚手架的下载和配置步骤详解
2019/04/01 Javascript
基于layui框架响应式布局的一些使用详解
2019/09/16 Javascript
Node.js开发之套接字(socket)编程入门示例
2019/11/05 Javascript
详解Vscode中使用Eslint终极配置大全
2019/11/08 Javascript
[38:32]完美世界DOTA2联赛循环赛 Forest vs DM 第二场 11.06
2020/11/06 DOTA
Python代理抓取并验证使用多线程实现
2013/05/03 Python
Python常见格式化字符串方法小结【百分号与format方法】
2016/09/18 Python
python引入不同文件夹下的自定义模块方法
2018/10/27 Python
python 将字符串完成特定的向右移动方法
2019/06/11 Python
Python类中self参数用法详解
2020/02/13 Python
Python socket处理client连接过程解析
2020/03/18 Python
Python内置函数及功能简介汇总
2020/10/13 Python
Python爬虫之Selenium下拉框处理的实现
2020/12/04 Python
html5 css3 动态气泡按钮实例演示
2012/12/02 HTML / CSS
CSS3中HSL和HSLA的简单使用示例
2015/07/14 HTML / CSS
加拿大女装网上购物:Reitmans
2016/10/20 全球购物
创新型城市实施方案
2014/03/06 职场文书
亲子活动总结
2014/04/26 职场文书
放飞梦想演讲稿600字
2014/08/26 职场文书
村委会贫困证明范本
2014/09/17 职场文书
个人作风建设自查报告
2014/10/22 职场文书
道歉情书大全
2015/05/12 职场文书
关于开学的感想
2015/08/10 职场文书
2016年春季趣味运动会开幕词
2016/03/04 职场文书
解决mysql:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO/YES)
2021/06/26 MySQL
Java 在生活中的 10 大应用
2021/11/02 Java/Android
MySQL派生表联表查询实战过程
2022/03/20 MySQL
springboot用户数据修改的详细实现
2022/04/06 Java/Android
SQL Server删除表中的重复数据
2022/05/25 SQL Server