golang 调用 php7详解及实例
执行php文件
funcTest_exec(t*testing.T){
engine.Initialize()
ctx:=&engine.Context{
Output:os.Stdout,
}
err:=engine.RequestStartup(ctx)
iferr!=nil{
fmt.Println(err)
}
deferengine.RequestShutdown(ctx)
err=ctx.Exec("/tmp/index.php")
iferr!=nil{
fmt.Println(err)
}
}
其中/tmp/index.php的内容为
<?php
echo("hello\n");
Eval,返回值
funcTest_eval(t*testing.T){
engine.Initialize()
ctx:=&engine.Context{}
err:=engine.RequestStartup(ctx)
iferr!=nil{
fmt.Println(err)
}
deferengine.RequestShutdown(ctx)
val,err:=ctx.Eval("return'hello';")
iferr!=nil{
fmt.Println(err)
}
deferengine.DestroyValue(val)
ifengine.ToString(val)!="hello"{
t.FailNow()
}
}
返回的value的生命周期所有权是golang程序,所以我们要负责DestroyValue
设置全局变量来传参
funcTest_argument(t*testing.T){
engine.Initialize()
ctx:=&engine.Context{}
err:=engine.RequestStartup(ctx)
iferr!=nil{
fmt.Println(err)
}
deferengine.RequestShutdown(ctx)
err=ctx.Bind("greeting","hello")
iferr!=nil{
fmt.Println(err)
}
val,err:=ctx.Eval("return$greeting;")
iferr!=nil{
fmt.Println(err)
}
deferengine.DestroyValue(val)
ifengine.ToString(val)!="hello"{
t.FailNow()
}
}
传递进去的参数的生命周期是php控制的,在requestshutdown的时候内存会被释放。
PHP回调Golang
typegreetingProviderstruct{
greetingstring
}
func(provider*greetingProvider)GetGreeting()string{
returnprovider.greeting
}
funcnewGreetingProvider(args[]interface{})interface{}{
return&greetingProvider{
greeting:args[0].(string),
}
}
funcTest_callback(t*testing.T){
engine.Initialize()
ctx:=&engine.Context{}
err:=engine.RequestStartup(ctx)
iferr!=nil{
fmt.Println(err)
}
deferengine.RequestShutdown(ctx)
err=engine.Define("GreetingProvider",newGreetingProvider)
iferr!=nil{
fmt.Println(err)
}
val,err:=ctx.Eval(`
$greetingProvider=newGreetingProvider('hello');
return$greetingProvider->GetGreeting();`)
iferr!=nil{
fmt.Println(err)
}
deferengine.DestroyValue(val)
ifengine.ToString(val)!="hello"{
t.FailNow()
}
}
PHP错误日志
funcTest_log(t*testing.T){
engine.PHP_INI_PATH_OVERRIDE="/tmp/php.ini"
engine.Initialize()
ctx:=&engine.Context{
Log:os.Stderr,
}
err:=engine.RequestStartup(ctx)
iferr!=nil{
fmt.Println(err)
}
deferengine.RequestShutdown(ctx)
_,err=ctx.Eval("error_log('hello',4);trigger_error('sentfromgolang',E_USER_ERROR);")
iferr!=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输入输出
funcTest_http(t*testing.T){
engine.Initialize()
recorder:=httptest.NewRecorder()
ctx:=&engine.Context{
Request:httptest.NewRequest("GET","/hello",nil),
ResponseWriter:recorder,
}
err:=engine.RequestStartup(ctx)
iferr!=nil{
fmt.Println(err)
}
deferengine.RequestShutdown(ctx)
_,err=ctx.Eval("echo($_SERVER['REQUEST_URI']);")
iferr!=nil{
fmt.Println(err)
}
body,err:=ioutil.ReadAll(recorder.Result().Body)
iferr!=nil{
fmt.Println(err)
}
ifstring(body)!="/hello"{
t.FailNow()
}
}
所有的PHP超级全局变量都会被初始化为传递进去的Request的值,包括
$_SERVER $_GET $_POST $_FILE $_COOKIE $_ENV
echo的内容,httpcode和httpheader会被写回到传入的ResponseWriter
fastcgi_finish_request
PHP-FPM很常用的一个功能是fastcgi_finish_request,用于在php里做一些异步完成的事情。这个特殊的全局函数必须支持
funcTest_fastcgi_finish_reqeust(t*testing.T){
engine.Initialize()
buffer:=&bytes.Buffer{}
ctx:=&engine.Context{
Output:buffer,
}
err:=engine.RequestStartup(ctx)
iferr!=nil{
fmt.Println(err)
}
deferengine.RequestShutdown(ctx)
ctx.Eval("ob_start();echo('hello');")
ifbuffer.String()!=""{
t.FailNow()
}
ctx.Eval("fastcgi_finish_request();")
ifbuffer.String()!="hello"{
t.FailNow()
}
}
实际的作用就是把output提前输出到ResposneWriter里去,让调用方知道结果。对于当前进程的执行其实是没有影响的,只是影响了output。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!