1
0
mirror of https://github.com/deuill/go-php.git synced 2024-09-21 00:40:45 +00:00

Add struct-to-object value bindings

This commit is contained in:
Alex Palaistras 2015-10-17 16:00:16 +01:00
parent 7ed2c81ec6
commit 6a3fd786ea
4 changed files with 61 additions and 4 deletions

View File

@ -120,12 +120,29 @@ var bindTests = []struct {
value interface{} // Value to bind
expected string // Serialized form of value
}{
// Integer to integer.
{42, "i:42;"},
// Float to double.
{3.14159, "d:3.1415899999999999;"},
// Boolean to boolean.
{true, "b:1;"},
// String to string.
{"Such bind", `s:9:"Such bind";`},
// Simple slice of strings to indexed array.
{[]string{"this", "that"}, `a:2:{i:0;s:4:"this";i:1;s:4:"that";}`},
// Nested slice of integers to indexed array.
{[][]int{[]int{1, 2}, []int{3}}, `a:2:{i:0;a:2:{i:0;i:1;i:1;i:2;}i:1;a:1:{i:0;i:3;}}`},
// Struct to object, with nested struct.
{struct {
I int
C string
F struct {
G bool
}
h bool
}{3, "test", struct {
G bool
}{false}, true}, `O:8:"stdClass":3:{s:1:"I";i:3;s:1:"C";s:4:"test";s:1:"F";O:8:"stdClass":1:{s:1:"G";b:0;}}`},
}
func TestContextBind(t *testing.T) {

View File

@ -62,6 +62,19 @@ void value_array_set_key(void *arr, const char *key, void *val) {
add_assoc_zval((zval *) arr, key, (zval *) val);
}
void *value_create_object() {
zval *v;
MAKE_STD_ZVAL(v);
object_init(v);
return (void *) v;
}
void value_object_add_property(void *obj, const char *key, void *val) {
add_property_zval((zval *) obj, key, (zval *) val);
}
void value_destroy(void *zvalptr) {
zval_dtor((zval *) zvalptr);
}

View File

@ -53,9 +53,10 @@ func (v *Value) Destroy() {
// map[int|string] -> associative array
// 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
// execution.
// It is only possible to bind maps with integer or string keys. Only exported
// struct fields are passed to the PHP context. Bindings for functions and method
// receivers to PHP functions and classes are only available in the engine scope,
// and must be predeclared before context execution.
func New(val interface{}) (*Value, error) {
var ptr unsafe.Pointer
@ -74,9 +75,9 @@ func New(val interface{}) (*Value, error) {
// Bind string to PHP string type.
case reflect.String:
str := C.CString(v.String())
defer C.free(unsafe.Pointer(str))
ptr = C.value_create_string(str)
C.free(unsafe.Pointer(str))
// Bind slice to PHP indexed array type.
case reflect.Slice:
ptr = C.value_create_array(C.uint(v.Len()))
@ -84,6 +85,7 @@ func New(val interface{}) (*Value, error) {
for i := 0; i < v.Len(); i++ {
vs, err := New(v.Index(i).Interface())
if err != nil {
C.value_destroy(ptr)
return nil, err
}
@ -99,6 +101,7 @@ func New(val interface{}) (*Value, error) {
for _, key := range v.MapKeys() {
kv, err := New(v.MapIndex(key).Interface())
if err != nil {
C.value_destroy(ptr)
return nil, err
}
@ -114,6 +117,28 @@ func New(val interface{}) (*Value, error) {
} else {
return nil, errInvalidType
}
// Bind struct to PHP object (stdClass) type.
case reflect.Struct:
vt := v.Type()
ptr = C.value_create_object()
for i := 0; i < v.NumField(); i++ {
// Skip unexported fields.
if vt.Field(i).PkgPath != "" {
continue
}
fv, err := New(v.Field(i).Interface())
if err != nil {
C.value_destroy(ptr)
return nil, err
}
str := C.CString(vt.Field(i).Name)
C.value_object_add_property(ptr, str, fv.Ptr())
C.free(unsafe.Pointer(str))
}
default:
return nil, errInvalidType
}

View File

@ -12,6 +12,8 @@ void *value_create_string(char *value);
void *value_create_array(unsigned int size);
void value_array_set_index(void *arr, unsigned long idx, void *val);
void value_array_set_key(void *arr, const char *key, void *val);
void *value_create_object();
void value_object_add_property(void *obj, const char *key, void *val);
void value_destroy(void *zvalptr);
#endif