From 7ed2c81ec6fbd2b67e8824f195cad86a69ff11c7 Mon Sep 17 00:00:00 2001 From: Alex Palaistras Date: Fri, 16 Oct 2015 14:41:13 +0100 Subject: [PATCH] Move `NewContext` function to `engine` package Call order is now enforced when using the root `php` package by moving the `NewContext` function in the `engine` package, as a method of the `Engine` method receiver. Further clean-ups have been made to the code as a result of this change. --- context/context.c | 4 ++++ context/context.go | 14 ++++++++------ context/context.h | 3 ++- engine/engine.c | 4 ++-- engine/engine.go | 35 +++++++++++++++++++++++++++++------ php.go | 10 ---------- php_test.go | 14 +++++--------- value/value.go | 18 ++++++++++-------- 8 files changed, 60 insertions(+), 42 deletions(-) diff --git a/context/context.c b/context/context.c index 7b906f9..cd3a5cb 100644 --- a/context/context.c +++ b/context/context.c @@ -92,6 +92,10 @@ void context_bind(engine_context *context, char *name, void *zvalptr) { return NULL; } +int context_write(engine_context *context, const char *str, unsigned int len) { + return contextWrite(context->parent, (void *) str, len); +} + void context_destroy(engine_context *context) { php_request_shutdown((void *) 0); diff --git a/context/context.go b/context/context.go index a3cc34f..4fea581 100644 --- a/context/context.go +++ b/context/context.go @@ -81,15 +81,17 @@ func (c *Context) Eval(script string) error { return nil } -// Destroy tears down the current execution context along with any values binded -// in. +// Destroy tears down the current execution context along with any active value +// bindings for that context. func (c *Context) Destroy() { for _, v := range c.values { v.Destroy() } - C.context_destroy(c.context) - c = nil + if c.context != nil { + C.context_destroy(c.context) + c.context = nil + } } // New creates a new execution context, passing all script output into w. It @@ -107,8 +109,8 @@ func New(w io.Writer) (*Context, error) { return ctx, nil } -//export context_write -func context_write(ctxptr unsafe.Pointer, buffer unsafe.Pointer, length C.uint) C.int { +//export contextWrite +func contextWrite(ctxptr unsafe.Pointer, buffer unsafe.Pointer, length C.uint) C.int { c := (*Context)(ctxptr) written, err := c.writer.Write(C.GoBytes(buffer, C.int(length))) diff --git a/context/context.h b/context/context.h index 63fb87f..edf1620 100644 --- a/context/context.h +++ b/context/context.h @@ -11,13 +11,14 @@ typedef struct _engine_context { #endif void *parent; // Pointer to parent Go context, used for passing to callbacks. - int (*write)(void *parent, void *msg, unsigned int len); + int (*write)(struct _engine_context *context, const char *msg, unsigned int len); } engine_context; engine_context *context_new(void *parent); void context_exec(engine_context *context, char *filename); void context_eval(engine_context *context, char *script); void context_bind(engine_context *context, char *name, void *zvalptr); +int context_write(engine_context *context, const char *str, unsigned int len); void context_destroy(engine_context *context); #endif \ No newline at end of file diff --git a/engine/engine.c b/engine/engine.c index 233b982..60a7af5 100644 --- a/engine/engine.c +++ b/engine/engine.c @@ -23,10 +23,10 @@ const char engine_ini_defaults[] = "max_input_time = -1\n\0" ; -static int engine_ub_write(const char *str, uint str_length TSRMLS_DC) { +static int engine_ub_write(const char *str, uint str_length TSRMLS_DC) { engine_context *context = (engine_context *) SG(server_context); - int written = context->write(context->parent, (void *) str, str_length); + int written = context->write(context, str, str_length); if (written != str_length) { php_handle_aborted_connection(); } diff --git a/engine/engine.go b/engine/engine.go index dbc8aef..af15145 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -16,18 +16,41 @@ import "C" import ( "fmt" + "io" + + "github.com/deuill/go-php/context" ) // Engine represents the core PHP engine bindings. type Engine struct { - engine *C.struct__php_engine + engine *C.struct__php_engine + contexts []*context.Context } -// Destroy shuts down and frees any resources related to the PHP engine -// bindings. +// NewContext creates a new execution context on which scripts can be executed +// and variables can be binded. It corresponds to PHP's RINIT (request init) +// phase. +func (e *Engine) NewContext(w io.Writer) (*context.Context, error) { + c, err := context.New(w) + if err != nil { + return nil, err + } + + e.contexts = append(e.contexts, c) + + return c, nil +} + +// Destroy shuts down and frees any resources related to the PHP engine bindings. func (e *Engine) Destroy() { - C.engine_shutdown(e.engine) - e = nil + for _, c := range e.contexts { + c.Destroy() + } + + if e.engine != nil { + C.engine_shutdown(e.engine) + e.engine = nil + } } // New initializes a PHP engine instance on which contexts can be executed. It @@ -38,5 +61,5 @@ func New() (*Engine, error) { return nil, fmt.Errorf("PHP engine failed to initialize") } - return &Engine{engine: ptr}, nil + return &Engine{engine: ptr, contexts: make([]*context.Context, 0)}, nil } diff --git a/php.go b/php.go index ae1232c..1af8d80 100644 --- a/php.go +++ b/php.go @@ -8,9 +8,6 @@ package php import ( - "io" - - "github.com/deuill/go-php/context" "github.com/deuill/go-php/engine" ) @@ -19,10 +16,3 @@ import ( func New() (*engine.Engine, error) { return engine.New() } - -// NewContext creates a new execution context on which scripts can be executed -// and variables can be binded. It corresponds to PHP's RINIT (request init -// phase and *must* be preceeded by a call to `php.New()`. -func NewContext(w io.Writer) (*context.Context, error) { - return context.New(w) -} diff --git a/php_test.go b/php_test.go index 496837c..4788a55 100644 --- a/php_test.go +++ b/php_test.go @@ -49,12 +49,10 @@ func TestNewEngineContext(t *testing.T) { defer e.Destroy() - ctx, err := NewContext(os.Stdout) + _, err = e.NewContext(os.Stdout) if err != nil { t.Errorf("NewContext(): %s", err) } - - defer ctx.Destroy() } var execTests = []struct { @@ -68,10 +66,9 @@ func TestContextExec(t *testing.T) { var w MockWriter e, _ := New() - ctx, _ := NewContext(&w) + ctx, _ := e.NewContext(&w) defer e.Destroy() - defer ctx.Destroy() for _, tt := range execTests { file := path.Join(testDir, tt.file) @@ -94,16 +91,16 @@ var evalTests = []struct { }{ {"echo 'Hello World';", "Hello World"}, {"$i = 10; $d = 20; echo $i + $d;", "30"}, + {"notascript{}!!*", ""}, } func TestContextEval(t *testing.T) { var w MockWriter e, _ := New() - ctx, _ := NewContext(&w) + ctx, _ := e.NewContext(&w) defer e.Destroy() - defer ctx.Destroy() for _, tt := range evalTests { if err := ctx.Eval(tt.script); err != nil { @@ -135,10 +132,9 @@ func TestContextBind(t *testing.T) { var w MockWriter e, _ := New() - ctx, _ := NewContext(&w) + 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 { diff --git a/value/value.go b/value/value.go index c30b5f6..88d53d9 100644 --- a/value/value.go +++ b/value/value.go @@ -36,20 +36,22 @@ func (v *Value) Ptr() unsafe.Pointer { // Destroy removes all active references to the internal PHP value and frees // any resources used. func (v *Value) Destroy() { - C.value_destroy(v.value) - v = nil + if v.value != nil { + C.value_destroy(v.value) + v.value = nil + } } // New creates a PHP value representtion of a Go value val. Available bindings // for Go to PHP types are: // -// int -> integer -// float64 -> double -// bool -> boolean -// string -> string -// slice -> indexed array +// int -> integer +// float64 -> double +// bool -> boolean +// string -> string +// slice -> indexed array // map[int|string] -> associative array -// struct -> object +// struct -> object // // Bindings for functions and method receivers to PHP functions and classes are // only available in the engine scope, and must be predeclared before context