forked from deuill/go-php
-
Notifications
You must be signed in to change notification settings - Fork 0
/
receiver.c
179 lines (142 loc) · 5.01 KB
/
receiver.c
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// 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.
#include <stdio.h>
#include <stdbool.h>
#include <main/php.h>
#include <zend_exceptions.h>
#include <ext/standard/php_string.h>
#include "value.h"
#include "receiver.h"
#include "_cgo_export.h"
// Fetch and return field for method receiver.
static engine_value *receiver_get(zval *object, zval *member) {
engine_receiver *this = _receiver_this(object);
return engineReceiverGet(this, Z_STRVAL_P(member));
}
// Set field for method receiver.
static void receiver_set(zval *object, zval *member, zval *value) {
engine_receiver *this = _receiver_this(object);
engineReceiverSet(this, Z_STRVAL_P(member), (void *) value);
}
// Check if field exists for method receiver.
static int receiver_exists(zval *object, zval *member, int check) {
engine_receiver *this = _receiver_this(object);
if (!engineReceiverExists(this, Z_STRVAL_P(member))) {
// Value does not exist.
return 0;
} else if (check == 2) {
// Value exists.
return 1;
}
int result = 0;
engine_value *val = engineReceiverGet(this, Z_STRVAL_P(member));
if (check == 1) {
// Value exists and is "truthy".
convert_to_boolean(val->internal);
result = _value_truth(val->internal);
} else if (check == 0) {
// Value exists and is not null.
result = (val->kind != KIND_NULL) ? 1 : 0;
} else {
// Check value is invalid.
result = 0;
}
_value_destroy(val);
return result;
}
// Call function with arguments passed and return value (if any).
static int receiver_method_call(char *name, INTERNAL_FUNCTION_PARAMETERS) {
zval args;
engine_receiver *this = _receiver_this(getThis());
array_init_size(&args, ZEND_NUM_ARGS());
if (zend_copy_parameters_array(ZEND_NUM_ARGS(), &args) == FAILURE) {
RETVAL_NULL();
} else {
engine_value *result = engineReceiverCall(this, name, (void *) &args);
if (result == NULL) {
RETVAL_NULL();
} else {
value_copy(return_value, result->internal);
_value_destroy(result);
}
}
zval_dtor(&args);
}
// Create new method receiver instance and attach to instantiated PHP object.
// Returns an exception if method receiver failed to initialize for any reason.
static void receiver_new(INTERNAL_FUNCTION_PARAMETERS) {
zval args;
engine_receiver *this = _receiver_this(getThis());
array_init_size(&args, ZEND_NUM_ARGS());
if (zend_copy_parameters_array(ZEND_NUM_ARGS(), &args) == FAILURE) {
zend_throw_exception(NULL, "Could not parse parameters for method receiver", 0);
} else {
// Create receiver instance. Throws an exception if creation fails.
int result = engineReceiverNew(this, (void *) &args);
if (result != 0) {
zend_throw_exception(NULL, "Failed to instantiate method receiver", 0);
}
}
zval_dtor(&args);
}
// Fetch and return function definition for method receiver. The method call
// happens in the method handler, as returned by this function.
static zend_internal_function *receiver_method_get(zend_object *object) {
zend_internal_function *func = emalloc(sizeof(zend_internal_function));
func->type = ZEND_OVERLOADED_FUNCTION;
func->handler = NULL;
func->arg_info = NULL;
func->num_args = 0;
func->scope = object->ce;
func->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
return func;
}
// Fetch and return constructor function definition for method receiver. The
// construct call happens in the constructor handler, as returned by this
// function.
static zend_internal_function *receiver_constructor_get(zend_object *object) {
static zend_internal_function func;
func.type = ZEND_INTERNAL_FUNCTION;
func.handler = receiver_new;
func.arg_info = NULL;
func.num_args = 0;
func.scope = object->ce;
func.fn_flags = 0;
func.function_name = object->ce->name;
return &func;
}
// Table of handler functions for method receivers.
static zend_object_handlers receiver_handlers = {
ZEND_OBJECTS_STORE_HANDLERS,
_receiver_get, // read_property
_receiver_set, // write_property
NULL, // read_dimension
NULL, // write_dimension
NULL, // get_property_ptr_ptr
NULL, // get
NULL, // set
_receiver_exists, // has_property
NULL, // unset_property
NULL, // has_dimension
NULL, // unset_dimension
NULL, // get_properties
_receiver_method_get, // get_method
_receiver_method_call, // call_method
_receiver_constructor_get // get_constructor
};
// Define class with unique name.
void receiver_define(char *name) {
zend_class_entry tmp;
INIT_CLASS_ENTRY_EX(tmp, name, strlen(name), NULL);
zend_class_entry *this = zend_register_internal_class(&tmp);
this->create_object = _receiver_init;
this->ce_flags |= ZEND_ACC_FINAL;
// Set standard handlers for receiver.
_receiver_handlers_set(&receiver_handlers);
}
void receiver_destroy(char *name) {
name = php_strtolower(name, strlen(name));
_receiver_destroy(name);
}
#include "_receiver.c"