-
Notifications
You must be signed in to change notification settings - Fork 105
/
receiver.go
163 lines (133 loc) · 4.04 KB
/
receiver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2017 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 php
// #cgo CFLAGS: -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM
// #cgo CFLAGS: -I/usr/include/php/Zend -Iinclude
//
// #include <stdlib.h>
// #include <main/php.h>
// #include "receiver.h"
import "C"
import (
"fmt"
"reflect"
"unsafe"
)
// Receiver represents a method receiver.
type Receiver struct {
name string
create func(args []interface{}) interface{}
objects map[*C.struct__engine_receiver]*ReceiverObject
}
// NewObject instantiates a new method receiver object, using the Receiver's
// create function and passing in a slice of values as a parameter.
func (r *Receiver) NewObject(args []interface{}) (*ReceiverObject, error) {
obj := &ReceiverObject{
instance: r.create(args),
values: make(map[string]reflect.Value),
methods: make(map[string]reflect.Value),
}
if obj.instance == nil {
return nil, fmt.Errorf("Failed to instantiate method receiver")
}
v := reflect.ValueOf(obj.instance)
vi := reflect.Indirect(v)
for i := 0; i < v.NumMethod(); i++ {
// Skip unexported methods.
if v.Type().Method(i).PkgPath != "" {
continue
}
obj.methods[v.Type().Method(i).Name] = v.Method(i)
}
if vi.Kind() == reflect.Struct {
for i := 0; i < vi.NumField(); i++ {
// Skip unexported fields.
if vi.Type().Field(i).PkgPath != "" {
continue
}
obj.values[vi.Type().Field(i).Name] = vi.Field(i)
}
}
return obj, nil
}
// Destroy removes references to the generated PHP class for this receiver and
// frees any memory used by object instances.
func (r *Receiver) Destroy() {
if r.create == nil {
return
}
n := C.CString(r.name)
defer C.free(unsafe.Pointer(n))
C.receiver_destroy(n)
r.create = nil
r.objects = nil
}
// ReceiverObject represents an object instance of a pre-defined method receiver.
type ReceiverObject struct {
instance interface{}
values map[string]reflect.Value
methods map[string]reflect.Value
}
// Get returns a named internal property of the receiver object instance, or an
// error if the property does not exist or is not addressable.
func (o *ReceiverObject) Get(name string) (*Value, error) {
if _, exists := o.values[name]; !exists || !o.values[name].CanInterface() {
return nil, fmt.Errorf("Value '%s' does not exist or is not addressable", name)
}
val, err := NewValue(o.values[name].Interface())
if err != nil {
return nil, err
}
return val, nil
}
// Set assigns value to named internal property. If the named property does not
// exist or cannot be set, the method does nothing.
func (o *ReceiverObject) Set(name string, val interface{}) {
// Do not attempt to set non-existing or unset-able field.
if _, exists := o.values[name]; !exists || !o.values[name].CanSet() {
return
}
o.values[name].Set(reflect.ValueOf(val))
}
// Exists checks if named internal property exists and returns true, or false if
// property does not exist.
func (o *ReceiverObject) Exists(name string) bool {
if _, exists := o.values[name]; !exists {
return false
}
return true
}
// Call executes a method receiver's named internal method, passing a slice of
// values as arguments to the method. If the method fails to execute or returns
// no value, nil is returned, otherwise a Value instance is returned.
func (o *ReceiverObject) Call(name string, args []interface{}) *Value {
if _, exists := o.methods[name]; !exists {
return nil
}
var in []reflect.Value
for _, v := range args {
in = append(in, reflect.ValueOf(v))
}
// Call receiver method.
var result interface{}
val := o.methods[name].Call(in)
// Process results, returning a single value if result slice contains a single
// element, otherwise returns a slice of values.
if len(val) > 1 {
t := make([]interface{}, len(val))
for i, v := range val {
t[i] = v.Interface()
}
result = t
} else if len(val) == 1 {
result = val[0].Interface()
} else {
return nil
}
v, err := NewValue(result)
if err != nil {
return nil
}
return v
}