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

123 lines
3.1 KiB
Go
Raw Normal View History

// Copyright 2015 Alexander Palaistras. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
// Package value implements value transformation between Go and PHP contexts.
2015-10-01 23:48:33 +00:00
package value
2015-09-22 20:54:58 +00:00
2015-10-01 23:48:33 +00:00
// #cgo CFLAGS: -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM
// #cgo CFLAGS: -I/usr/include/php/Zend
// #cgo LDFLAGS: -lphp5
//
2015-09-22 20:54:58 +00:00
// #include <stdlib.h>
2015-09-22 21:14:51 +00:00
// #include <stdbool.h>
2015-09-22 20:54:58 +00:00
// #include "value.h"
import "C"
import (
2015-10-01 21:57:17 +00:00
"errors"
"reflect"
2015-09-22 20:54:58 +00:00
"unsafe"
)
2015-10-01 21:57:17 +00:00
var errInvalidType = errors.New("Cannot create value of unknown type")
// Value represents a PHP value.
2015-09-22 20:54:58 +00:00
type Value struct {
value unsafe.Pointer
}
// Ptr returns a pointer to the internal PHP value, and is mostly used for
// passing to C functions.
2015-09-22 20:54:58 +00:00
func (v *Value) Ptr() unsafe.Pointer {
return v.value
}
// Destroy removes all active references to the internal PHP value and frees
// any resources used.
2015-09-22 20:54:58 +00:00
func (v *Value) Destroy() {
if v.value != nil {
C.value_destroy(v.value)
v.value = nil
}
2015-09-22 20:54:58 +00:00
}
// 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
// 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.
2015-10-01 23:48:33 +00:00
func New(val interface{}) (*Value, error) {
2015-09-22 20:54:58 +00:00
var ptr unsafe.Pointer
2015-09-26 19:40:41 +00:00
// Determine value type and create PHP value from the concrete type.
2015-10-01 21:57:17 +00:00
v := reflect.ValueOf(val)
switch v.Kind() {
// Bind integer to PHP int type.
case reflect.Int:
ptr = C.value_create_long(C.long(v.Int()))
// Bind floating point number to PHP double type.
case reflect.Float64:
ptr = C.value_create_double(C.double(v.Float()))
// Bind boolean to PHP bool type.
case reflect.Bool:
ptr = C.value_create_bool(C.bool(v.Bool()))
// Bind string to PHP string type.
case reflect.String:
str := C.CString(v.String())
2015-09-22 20:54:58 +00:00
defer C.free(unsafe.Pointer(str))
2015-10-01 21:57:17 +00:00
ptr = C.value_create_string(str)
// Bind slice to PHP indexed array type.
case reflect.Slice:
ptr = C.value_create_array(C.uint(v.Len()))
for i := 0; i < v.Len(); i++ {
2015-10-01 23:48:33 +00:00
vs, err := New(v.Index(i).Interface())
2015-10-01 21:57:17 +00:00
if err != nil {
return nil, err
}
C.value_array_set_index(ptr, C.ulong(i), vs.Ptr())
}
// Bind map (with integer or string keys) to PHP associative array type.
case reflect.Map:
kt := v.Type().Key().Kind()
2015-09-22 20:54:58 +00:00
if kt == reflect.Int || kt == reflect.String {
2015-10-01 21:57:17 +00:00
ptr = C.value_create_array(C.uint(v.Len()))
for _, key := range v.MapKeys() {
kv, err := New(v.MapIndex(key).Interface())
2015-10-01 21:57:17 +00:00
if err != nil {
return nil, err
}
if kt == reflect.Int {
C.value_array_set_index(ptr, C.ulong(key.Int()), kv.Ptr())
2015-10-01 21:57:17 +00:00
} else {
str := C.CString(key.String())
2015-10-01 21:57:17 +00:00
C.value_array_set_key(ptr, str, kv.Ptr())
2015-10-01 21:57:17 +00:00
C.free(unsafe.Pointer(str))
}
}
} else {
return nil, errInvalidType
}
default:
return nil, errInvalidType
2015-09-22 20:54:58 +00:00
}
return &Value{value: ptr}, nil
}