欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

golang 调用 php7详解及实例

程序员文章站 2024-03-06 12:10:55
执行php文件 func test_exec(t *testing.t) { engine.initialize() ctx := &engine...

执行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。

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