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);
|
||||
}
|
||||
|
||||
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 written = contextWrite(context->parent, (void *) message, length);
|
||||
if (written != length) {
|
||||
|
41
context.go
41
context.go
@ -4,6 +4,7 @@ package php
|
||||
// #include <stdlib.h>
|
||||
// #include "engine.h"
|
||||
// #include "context.h"
|
||||
// #include "value.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
@ -15,6 +16,42 @@ import (
|
||||
type Context struct {
|
||||
context *C.struct__engine_context
|
||||
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 {
|
||||
@ -30,6 +67,10 @@ func (c *Context) Exec(filename string) error {
|
||||
}
|
||||
|
||||
func (c *Context) Destroy() {
|
||||
for _, zval := range c.zvals {
|
||||
C.value_destroy(zval)
|
||||
}
|
||||
|
||||
C.context_destroy(c.context)
|
||||
c = nil
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ typedef struct _engine_context {
|
||||
|
||||
engine_context *context_new(php_engine *engine, void *parent);
|
||||
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);
|
||||
void context_destroy(engine_context *context);
|
||||
|
||||
|
@ -3,6 +3,7 @@ package php
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -27,12 +28,48 @@ func TestContextExec(t *testing.T) {
|
||||
for _, tt := range execTests {
|
||||
file := path.Join(testDir, tt.file)
|
||||
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()
|
||||
w.Reset()
|
||||
|
||||
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) {
|
||||
ctx := &Context{writer: w}
|
||||
ctx := &Context{writer: w, zvals: make(map[string]unsafe.Pointer)}
|
||||
|
||||
ptr, err := C.context_new(e.engine, unsafe.Pointer(ctx))
|
||||
if err != nil {
|
||||
|
@ -26,6 +26,12 @@ func (m *MockWriter) String() string {
|
||||
return string(m.buffer)
|
||||
}
|
||||
|
||||
func (m *MockWriter) Reset() {
|
||||
if m.buffer != nil {
|
||||
m.buffer = m.buffer[:0]
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewEngineContext(t *testing.T) {
|
||||
e, err := New()
|
||||
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