Ejemplo n.º 1
0
// New creates a PHP value representation of a Go value val. Available bindings
// for Go to PHP types are:
//
//	int             -> integer
//	float64         -> double
//	bool            -> boolean
//	string          -> string
//	slice           -> indexed array
//	map[int|string] -> associative array
//	struct          -> object
//
// 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 *C.struct__engine_value
	var err error

	// Determine value type and create PHP value from the concrete type.
	v := reflect.ValueOf(val)
	switch v.Kind() {
	// Bind integer to PHP int type.
	case reflect.Int:
		ptr, err = C.value_create_long(C.long(v.Int()))
	// Bind floating point number to PHP double type.
	case reflect.Float64:
		ptr, err = C.value_create_double(C.double(v.Float()))
	// Bind boolean to PHP bool type.
	case reflect.Bool:
		ptr, err = C.value_create_bool(C.bool(v.Bool()))
	// Bind string to PHP string type.
	case reflect.String:
		str := C.CString(v.String())

		ptr, err = C.value_create_string(str)
		C.free(unsafe.Pointer(str))
	// Bind slice to PHP indexed array type.
	case reflect.Slice:
		if ptr, err = C.value_create_array(C.uint(v.Len())); err != nil {
			break
		}

		for i := 0; i < v.Len(); i++ {
			vs, err := New(v.Index(i).Interface())
			if err != nil {
				C.value_destroy(ptr)
				return nil, err
			}

			C.value_array_next_set(ptr, vs.value)
		}
	// Bind map (with integer or string keys) to PHP associative array type.
	case reflect.Map:
		kt := v.Type().Key().Kind()

		if kt == reflect.Int || kt == reflect.String {
			if ptr, err = C.value_create_array(C.uint(v.Len())); err != nil {
				break
			}

			for _, key := range v.MapKeys() {
				kv, err := New(v.MapIndex(key).Interface())
				if err != nil {
					C.value_destroy(ptr)
					return nil, err
				}

				if kt == reflect.Int {
					C.value_array_index_set(ptr, C.ulong(key.Int()), kv.value)
				} else {
					str := C.CString(key.String())

					C.value_array_key_set(ptr, str, kv.value)
					C.free(unsafe.Pointer(str))
				}
			}
		} else {
			return nil, errInvalidType(val)
		}
	// Bind struct to PHP object (stdClass) type.
	case reflect.Struct:
		vt := v.Type()
		if ptr, err = C.value_create_object(); err != nil {
			break
		}

		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_property_add(ptr, str, fv.value)
			C.free(unsafe.Pointer(str))
		}
	default:
		return nil, errInvalidType(val)
	}

	if err != nil {
		return nil, fmt.Errorf("Unable to create PHP value from Go value '%v'", val)
	}

	return &Value{value: ptr}, nil
}
Ejemplo n.º 2
0
// NewValue creates a PHP value representation of a Go value val. Available
// bindings for Go to PHP types are:
//
//	int             -> integer
//	float64         -> double
//	bool            -> boolean
//	string          -> string
//	slice           -> indexed array
//	map[int|string] -> associative array
//	struct          -> object
//
// 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 NewValue(val interface{}) (*Value, error) {
	ptr, err := C.value_new()
	if err != nil {
		return nil, fmt.Errorf("Unable to instantiate PHP value")
	}

	v := reflect.ValueOf(val)

	// Determine interface value type and create PHP value from the concrete type.
	switch v.Kind() {
	// Bind integer to PHP int type.
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		C.value_set_long(ptr, C.long(v.Int()))
	// Bind floating point number to PHP double type.
	case reflect.Float32, reflect.Float64:
		C.value_set_double(ptr, C.double(v.Float()))
	// Bind boolean to PHP bool type.
	case reflect.Bool:
		C.value_set_bool(ptr, C.bool(v.Bool()))
	// Bind string to PHP string type.
	case reflect.String:
		str := C.CString(v.String())
		defer C.free(unsafe.Pointer(str))

		C.value_set_string(ptr, str)
	// Bind slice to PHP indexed array type.
	case reflect.Slice:
		C.value_set_array(ptr, C.uint(v.Len()))

		for i := 0; i < v.Len(); i++ {
			vs, err := NewValue(v.Index(i).Interface())
			if err != nil {
				C.value_destroy(ptr)
				return nil, err
			}

			C.value_array_next_set(ptr, vs.value)
		}
	// Bind map (with integer or string keys) to PHP associative array type.
	case reflect.Map:
		kt := v.Type().Key().Kind()

		if kt == reflect.Int || kt == reflect.String {
			C.value_set_array(ptr, C.uint(v.Len()))

			for _, key := range v.MapKeys() {
				kv, err := NewValue(v.MapIndex(key).Interface())
				if err != nil {
					C.value_destroy(ptr)
					return nil, err
				}

				if kt == reflect.Int {
					C.value_array_index_set(ptr, C.ulong(key.Int()), kv.value)
				} else {
					str := C.CString(key.String())
					defer C.free(unsafe.Pointer(str))

					C.value_array_key_set(ptr, str, kv.value)
				}
			}
		} else {
			return nil, fmt.Errorf("Unable to create value of unknown type '%T'", val)
		}
	// Bind struct to PHP object (stdClass) type.
	case reflect.Struct:
		C.value_set_object(ptr)
		vt := v.Type()

		for i := 0; i < v.NumField(); i++ {
			// Skip unexported fields.
			if vt.Field(i).PkgPath != "" {
				continue
			}

			fv, err := NewValue(v.Field(i).Interface())
			if err != nil {
				C.value_destroy(ptr)
				return nil, err
			}

			str := C.CString(vt.Field(i).Name)
			defer C.free(unsafe.Pointer(str))

			C.value_object_property_set(ptr, str, fv.value)
		}
	case reflect.Invalid:
		C.value_set_null(ptr)
	default:
		C.value_destroy(ptr)
		return nil, fmt.Errorf("Unable to create value of unknown type '%T'", val)
	}

	return &Value{value: ptr}, nil
}