mirror of
https://github.com/deuill/go-php.git
synced 2024-09-21 00:40:45 +00:00
First version of variable bindings to context.
This commit contains an initial version of variable bindings to a context, along with tests. Currently supported types are integers, floating point numbers, and strings.
This commit is contained in:
parent
ee779b3698
commit
6fa93f5160
11
context.c
11
context.c
@ -61,6 +61,17 @@ void context_exec(engine_context *context, char *filename) {
|
|||||||
return_multi(NULL, 0);
|
return_multi(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void context_bind(engine_context *context, char *name, void *zvalptr) {
|
||||||
|
zval *value = (zval *) zvalptr;
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
void ***tsrm_ls = context->engine->tsrm_ls;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ZEND_SET_SYMBOL(EG(active_symbol_table), name, value);
|
||||||
|
return_multi(NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int context_write(engine_context *context, const char *message, unsigned int length) {
|
int context_write(engine_context *context, const char *message, unsigned int length) {
|
||||||
int written = contextWrite(context->parent, (void *) message, length);
|
int written = contextWrite(context->parent, (void *) message, length);
|
||||||
if (written != length) {
|
if (written != length) {
|
||||||
|
41
context.go
41
context.go
@ -4,6 +4,7 @@ package php
|
|||||||
// #include <stdlib.h>
|
// #include <stdlib.h>
|
||||||
// #include "engine.h"
|
// #include "engine.h"
|
||||||
// #include "context.h"
|
// #include "context.h"
|
||||||
|
// #include "value.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -15,6 +16,42 @@ import (
|
|||||||
type Context struct {
|
type Context struct {
|
||||||
context *C.struct__engine_context
|
context *C.struct__engine_context
|
||||||
writer io.Writer
|
writer io.Writer
|
||||||
|
zvals map[string]unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Bind(name string, value interface{}) error {
|
||||||
|
var zval unsafe.Pointer
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch v := value.(type) {
|
||||||
|
case int:
|
||||||
|
zval, err = C.value_long(C.long(v))
|
||||||
|
case float64:
|
||||||
|
zval, err = C.value_double(C.double(v))
|
||||||
|
case string:
|
||||||
|
str := C.CString(v)
|
||||||
|
defer C.free(unsafe.Pointer(str))
|
||||||
|
|
||||||
|
zval, err = C.value_string(str)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Cannot bind unknown type '%T'", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Binding value '%v' to context failed", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
n := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(n))
|
||||||
|
|
||||||
|
if _, err = C.context_bind(c.context, n, zval); err != nil {
|
||||||
|
C.value_destroy(zval)
|
||||||
|
return fmt.Errorf("Binding value '%v' to context failed", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.zvals[name] = zval
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) Exec(filename string) error {
|
func (c *Context) Exec(filename string) error {
|
||||||
@ -30,6 +67,10 @@ func (c *Context) Exec(filename string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) Destroy() {
|
func (c *Context) Destroy() {
|
||||||
|
for _, zval := range c.zvals {
|
||||||
|
C.value_destroy(zval)
|
||||||
|
}
|
||||||
|
|
||||||
C.context_destroy(c.context)
|
C.context_destroy(c.context)
|
||||||
c = nil
|
c = nil
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ typedef struct _engine_context {
|
|||||||
|
|
||||||
engine_context *context_new(php_engine *engine, void *parent);
|
engine_context *context_new(php_engine *engine, void *parent);
|
||||||
void context_exec(engine_context *context, char *filename);
|
void context_exec(engine_context *context, char *filename);
|
||||||
|
void context_bind(engine_context *context, char *name, void *vptr);
|
||||||
int context_write(engine_context *context, const char *message, unsigned int length);
|
int context_write(engine_context *context, const char *message, unsigned int length);
|
||||||
void context_destroy(engine_context *context);
|
void context_destroy(engine_context *context);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package php
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,12 +28,48 @@ func TestContextExec(t *testing.T) {
|
|||||||
for _, tt := range execTests {
|
for _, tt := range execTests {
|
||||||
file := path.Join(testDir, tt.file)
|
file := path.Join(testDir, tt.file)
|
||||||
if err := ctx.Exec(file); err != nil {
|
if err := ctx.Exec(file); err != nil {
|
||||||
t.Errorf("ContextExec(%s): %s", tt.file, err)
|
t.Errorf("Context.Exec(%s): %s", tt.file, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := w.String()
|
actual := w.String()
|
||||||
|
w.Reset()
|
||||||
|
|
||||||
if actual != tt.expected {
|
if actual != tt.expected {
|
||||||
t.Errorf("ContextExec(%s): expected '%s', actual '%s'", tt.file, tt.expected, actual)
|
t.Errorf("Context.Exec(%s): expected '%s', actual '%s'", tt.file, tt.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bindTests = []struct {
|
||||||
|
value interface{} // Value to bind
|
||||||
|
expected string // Serialized form of value
|
||||||
|
}{
|
||||||
|
{42, "i:42;"}, // Integer
|
||||||
|
{3.14159, "d:3.1415899999999999;"}, // Floating point
|
||||||
|
{"Such bind", `s:9:"Such bind";`}, // String
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextBind(t *testing.T) {
|
||||||
|
var w MockWriter
|
||||||
|
|
||||||
|
e, _ := New()
|
||||||
|
ctx, _ := e.NewContext(&w)
|
||||||
|
|
||||||
|
defer e.Destroy()
|
||||||
|
defer ctx.Destroy()
|
||||||
|
|
||||||
|
for i, tt := range bindTests {
|
||||||
|
if err := ctx.Bind(strconv.FormatInt(int64(i), 10), tt.value); err != nil {
|
||||||
|
t.Errorf("Context.Bind(%v): %s", tt.value, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Exec(path.Join(testDir, "bind.php"))
|
||||||
|
|
||||||
|
actual := w.String()
|
||||||
|
w.Reset()
|
||||||
|
|
||||||
|
if actual != tt.expected {
|
||||||
|
t.Errorf("Context.Bind(%v): expected '%s', actual '%s'", tt.value, tt.expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ type Engine struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) NewContext(w io.Writer) (*Context, error) {
|
func (e *Engine) NewContext(w io.Writer) (*Context, error) {
|
||||||
ctx := &Context{writer: w}
|
ctx := &Context{writer: w, zvals: make(map[string]unsafe.Pointer)}
|
||||||
|
|
||||||
ptr, err := C.context_new(e.engine, unsafe.Pointer(ctx))
|
ptr, err := C.context_new(e.engine, unsafe.Pointer(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,6 +26,12 @@ func (m *MockWriter) String() string {
|
|||||||
return string(m.buffer)
|
return string(m.buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockWriter) Reset() {
|
||||||
|
if m.buffer != nil {
|
||||||
|
m.buffer = m.buffer[:0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewEngineContext(t *testing.T) {
|
func TestNewEngineContext(t *testing.T) {
|
||||||
e, err := New()
|
e, err := New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
9
test/bind.php
Normal file
9
test/bind.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (isset($i)) {
|
||||||
|
$i += 1;
|
||||||
|
} else {
|
||||||
|
$i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo serialize($$i);
|
41
value.c
Normal file
41
value.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Standard library.
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
// PHP includes.
|
||||||
|
#include <main/php.h>
|
||||||
|
|
||||||
|
// Local includes.
|
||||||
|
#include "engine.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
void *value_long(long int value) {
|
||||||
|
zval *v;
|
||||||
|
|
||||||
|
MAKE_STD_ZVAL(v);
|
||||||
|
ZVAL_LONG(v, value);
|
||||||
|
|
||||||
|
return_multi((void *) v, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *value_double(double value) {
|
||||||
|
zval *v;
|
||||||
|
|
||||||
|
MAKE_STD_ZVAL(v);
|
||||||
|
ZVAL_DOUBLE(v, value);
|
||||||
|
|
||||||
|
return_multi((void *) v, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *value_string(char *value) {
|
||||||
|
zval *v;
|
||||||
|
|
||||||
|
MAKE_STD_ZVAL(v);
|
||||||
|
ZVAL_STRING(v, value, 1);
|
||||||
|
|
||||||
|
return_multi((void *) v, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void value_destroy(void *zvalptr) {
|
||||||
|
zval_dtor((zval *) zvalptr);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user