php_vm 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/extconf.rb +9 -0
- data/ext/php_vm.c +567 -0
- data/ext/php_vm.h +64 -0
- data/ext/php_vm_v2z.c +81 -0
- data/ext/php_vm_v2z.h +9 -0
- data/ext/php_vm_z2v.c +155 -0
- data/ext/php_vm_z2v.h +9 -0
- data/sample/class.rb +57 -0
- data/sample/exec.rb +6 -0
- data/sample/exec_raise_exception.rb +10 -0
- data/sample/require.php +3 -0
- data/sample/require.rb +6 -0
- data/sample/version.rb +6 -0
- metadata +59 -0
data/ext/extconf.rb
ADDED
data/ext/php_vm.c
ADDED
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
#include "php_vm.h"
|
|
2
|
+
#include "php_vm_z2v.h"
|
|
3
|
+
#include "php_vm_v2z.h"
|
|
4
|
+
#include <string.h>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
// global
|
|
8
|
+
|
|
9
|
+
VALUE rb_mPHPVM;
|
|
10
|
+
VALUE rb_cPHPClass;
|
|
11
|
+
VALUE rb_cPHPObject;
|
|
12
|
+
VALUE rb_ePHPError;
|
|
13
|
+
VALUE rb_ePHPExceptionObject;
|
|
14
|
+
VALUE rb_ePHPSyntaxError;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// PHP
|
|
18
|
+
|
|
19
|
+
void php_eval_string(char *code, int code_len TSRMLS_DC)
|
|
20
|
+
{
|
|
21
|
+
int syntax_error = 0;
|
|
22
|
+
|
|
23
|
+
// eval
|
|
24
|
+
zend_try {
|
|
25
|
+
if (zend_eval_stringl(code, code_len, NULL, "php_vm" TSRMLS_CC)==FAILURE) {
|
|
26
|
+
syntax_error = 1;
|
|
27
|
+
}
|
|
28
|
+
} zend_end_try();
|
|
29
|
+
|
|
30
|
+
// syntax error
|
|
31
|
+
if (syntax_error) {
|
|
32
|
+
VALUE exception = rb_exc_new2(rb_ePHPSyntaxError, "Syntax error");
|
|
33
|
+
rb_exc_raise(exception);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// exception
|
|
37
|
+
if (EG(exception)) {
|
|
38
|
+
VALUE exception = zval_to_value(EG(exception));
|
|
39
|
+
EG(exception) = NULL;
|
|
40
|
+
rb_exc_raise(exception);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// exit
|
|
44
|
+
if (EG(exit_status)!=0) {
|
|
45
|
+
int exit_status = EG(exit_status);
|
|
46
|
+
EG(exit_status) = 0;
|
|
47
|
+
|
|
48
|
+
char message[32];
|
|
49
|
+
sprintf(message, "exit status error: %d", exit_status);
|
|
50
|
+
|
|
51
|
+
VALUE exception = rb_exc_new2(rb_ePHPError, message);
|
|
52
|
+
rb_exc_raise(exception);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void find_zend_class_entry(char *name, int name_len, zend_class_entry ***ce)
|
|
57
|
+
{
|
|
58
|
+
// lowercase
|
|
59
|
+
char *lcname = malloc(name_len+1);
|
|
60
|
+
memcpy(lcname, name, name_len);
|
|
61
|
+
zend_str_tolower(lcname, name_len);
|
|
62
|
+
lcname[name_len] = '\0';
|
|
63
|
+
|
|
64
|
+
// find zend class
|
|
65
|
+
*ce = NULL;
|
|
66
|
+
zend_hash_find(CG(class_table), lcname, name_len+1, (void **)ce);
|
|
67
|
+
if (*ce) {
|
|
68
|
+
// check string case
|
|
69
|
+
if (strcmp(name, (**ce)->name)!=0) {
|
|
70
|
+
*ce = NULL;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
free(lcname);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
int is_exception_zend_class_entry(zend_class_entry *ce TSRMLS_DC)
|
|
78
|
+
{
|
|
79
|
+
return instanceof_function(ce, zend_exception_get_default() TSRMLS_CC);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
int is_exception_zval(zval *z TSRMLS_DC)
|
|
83
|
+
{
|
|
84
|
+
return is_exception_zend_class_entry(Z_OBJCE_P(z) TSRMLS_CC);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void find_zend_function(zend_class_entry *ce, char *name, int name_len, zend_function **mptr)
|
|
88
|
+
{
|
|
89
|
+
// function_table
|
|
90
|
+
HashTable *function_table = NULL;
|
|
91
|
+
if (ce && &ce->function_table) {
|
|
92
|
+
function_table = &ce->function_table;
|
|
93
|
+
} else {
|
|
94
|
+
function_table = EG(function_table);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// lowercase
|
|
98
|
+
char *lcname = malloc(name_len+1);
|
|
99
|
+
memcpy(lcname, name, name_len);
|
|
100
|
+
zend_str_tolower(lcname, name_len);
|
|
101
|
+
lcname[name_len] = '\0';
|
|
102
|
+
|
|
103
|
+
// find zend function
|
|
104
|
+
*mptr = NULL;
|
|
105
|
+
zend_hash_find(function_table, lcname, name_len+1, (void **)mptr);
|
|
106
|
+
if (*mptr) {
|
|
107
|
+
// check string case
|
|
108
|
+
if (strcmp(name, (*mptr)->common.function_name)!=0) {
|
|
109
|
+
*mptr = NULL;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
free(lcname);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
int new_php_object(zend_class_entry *ce, VALUE v_args, zval *retval)
|
|
117
|
+
{
|
|
118
|
+
int result = FAILURE;
|
|
119
|
+
|
|
120
|
+
if (ce->constructor) {
|
|
121
|
+
// defined constructor
|
|
122
|
+
/*
|
|
123
|
+
if (!(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
|
|
124
|
+
char *message = malloc(50+strlen(ce->name));
|
|
125
|
+
sprintf(message, "Access to non-public constructor of class %s", ce->name);
|
|
126
|
+
VALUE v_exception = rb_exc_new2(rb_ePHPError, message);
|
|
127
|
+
free(message);
|
|
128
|
+
rb_exc_raise(v_exception);
|
|
129
|
+
}
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
// alloc
|
|
133
|
+
object_init_ex(retval, ce);
|
|
134
|
+
|
|
135
|
+
// call
|
|
136
|
+
int result = call_php_method(ce, retval, ce->constructor, RARRAY_LEN(v_args), RARRAY_PTR(v_args), &retval TSRMLS_CC);
|
|
137
|
+
|
|
138
|
+
// error
|
|
139
|
+
if (result==FAILURE) {
|
|
140
|
+
char *message = malloc(40+strlen(ce->name));
|
|
141
|
+
sprintf(message, "Invocation of %s's constructor failed", ce->name);
|
|
142
|
+
VALUE v_exception = rb_exc_new2(rb_ePHPError, message);
|
|
143
|
+
free(message);
|
|
144
|
+
rb_exc_raise(v_exception);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
} else if (!RARRAY_LEN(v_args)) {
|
|
148
|
+
// undefined constructor, hasnt args
|
|
149
|
+
object_init_ex(retval, ce);
|
|
150
|
+
result = SUCCESS;
|
|
151
|
+
|
|
152
|
+
} else {
|
|
153
|
+
// undefine constructor, has args
|
|
154
|
+
char *message = malloc(90+strlen(ce->name));
|
|
155
|
+
sprintf(message, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ce->name);
|
|
156
|
+
VALUE v_exception = rb_exc_new2(rb_ePHPError, message);
|
|
157
|
+
free(message);
|
|
158
|
+
rb_exc_raise(v_exception);
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
void define_php_methods(VALUE v_obj, zend_class_entry *ce, int is_static)
|
|
164
|
+
{
|
|
165
|
+
// TODO: access modifier
|
|
166
|
+
// TODO: __toString
|
|
167
|
+
// TODO: __clone
|
|
168
|
+
// TODO: __call
|
|
169
|
+
// TODO: __callStatic
|
|
170
|
+
// TODO: __get
|
|
171
|
+
// TODO: __set
|
|
172
|
+
// TODO: __isset
|
|
173
|
+
|
|
174
|
+
HashPosition pos;
|
|
175
|
+
zend_function *mptr;
|
|
176
|
+
|
|
177
|
+
zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
|
|
178
|
+
|
|
179
|
+
while (zend_hash_get_current_data_ex(&ce->function_table, (void **)&mptr, &pos) == SUCCESS) {
|
|
180
|
+
int flag = mptr->common.fn_flags;
|
|
181
|
+
const char *fname = mptr->common.function_name;
|
|
182
|
+
|
|
183
|
+
if (is_static) {
|
|
184
|
+
// class method
|
|
185
|
+
if (strcmp("new", fname)==0) {
|
|
186
|
+
// new => no define
|
|
187
|
+
} else if (0<(flag & ZEND_ACC_STATIC)) {
|
|
188
|
+
// other method
|
|
189
|
+
rb_define_singleton_method(v_obj, fname, rb_php_class_call, -1);
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
// instance method
|
|
193
|
+
if (strcmp("__construct", fname)==0) {
|
|
194
|
+
// __construct => no define
|
|
195
|
+
|
|
196
|
+
} else if (0==(flag & ZEND_ACC_STATIC)) {
|
|
197
|
+
// other method
|
|
198
|
+
rb_define_singleton_method(v_obj, fname, rb_php_object_call, -1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
zend_hash_move_forward_ex(&ce->function_table, &pos);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
int call_php_method(zend_class_entry *ce, zval *obj, zend_function *mptr, int argc, VALUE *v_argv, zval **retval_ptr TSRMLS_DC)
|
|
207
|
+
{
|
|
208
|
+
int result = FAILURE;
|
|
209
|
+
|
|
210
|
+
// argv
|
|
211
|
+
zval ***z_argv = malloc(sizeof(zval **) * argc);
|
|
212
|
+
long i;
|
|
213
|
+
for (i=0; i<argc; i++) {
|
|
214
|
+
zval *tmp;
|
|
215
|
+
MAKE_STD_ZVAL(tmp);
|
|
216
|
+
value_to_zval(v_argv[i], tmp);
|
|
217
|
+
z_argv[i] = &tmp;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// call info
|
|
221
|
+
zend_fcall_info fci;
|
|
222
|
+
zend_fcall_info_cache fcc;
|
|
223
|
+
zval *return_value;
|
|
224
|
+
ALLOC_INIT_ZVAL(return_value);
|
|
225
|
+
|
|
226
|
+
fci.size = sizeof(fci);
|
|
227
|
+
fci.function_table = NULL;
|
|
228
|
+
fci.function_name = NULL;
|
|
229
|
+
fci.symbol_table = NULL;
|
|
230
|
+
fci.object_ptr = obj;
|
|
231
|
+
fci.retval_ptr_ptr = retval_ptr;
|
|
232
|
+
fci.param_count = argc;
|
|
233
|
+
fci.params = z_argv;
|
|
234
|
+
fci.no_separation = 1;
|
|
235
|
+
|
|
236
|
+
fcc.initialized = 1;
|
|
237
|
+
fcc.function_handler = mptr;
|
|
238
|
+
fcc.calling_scope = ce ? ce : EG(scope);
|
|
239
|
+
fcc.called_scope = ce ? ce : NULL;
|
|
240
|
+
fcc.object_ptr = obj;
|
|
241
|
+
|
|
242
|
+
// call
|
|
243
|
+
zend_try {
|
|
244
|
+
result = zend_call_function(&fci, &fcc TSRMLS_CC);
|
|
245
|
+
} zend_catch {
|
|
246
|
+
//printf("call_php_method exception: %p\n", EG(exception));
|
|
247
|
+
} zend_end_try();
|
|
248
|
+
|
|
249
|
+
// release
|
|
250
|
+
for (i=0; i<argc; i++) {
|
|
251
|
+
zval_ptr_dtor(z_argv[i]);
|
|
252
|
+
}
|
|
253
|
+
free(z_argv);
|
|
254
|
+
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
// Ruby
|
|
260
|
+
|
|
261
|
+
VALUE get_callee_name()
|
|
262
|
+
{
|
|
263
|
+
VALUE backtrace_arr = rb_funcall(rb_mKernel, rb_intern("caller"), 1, INT2NUM(0));
|
|
264
|
+
if (backtrace_arr) {
|
|
265
|
+
VALUE backtrace = rb_funcall(backtrace_arr, rb_intern("first"), 0);
|
|
266
|
+
if (backtrace) {
|
|
267
|
+
VALUE re = rb_funcall(rb_cRegexp, rb_intern("new"), 1, rb_str_new2("^(.+?):(\\d+)(?::in `(.*)')?"));
|
|
268
|
+
VALUE m = rb_funcall(backtrace, rb_intern("match"), 1, re);
|
|
269
|
+
if (m) {
|
|
270
|
+
return rb_funcall(m, rb_intern("[]"), 1, INT2NUM(3));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return Qnil;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
VALUE call_php_method_bridge(zend_class_entry *ce, zval *obj, VALUE callee, int argc, VALUE *argv)
|
|
278
|
+
{
|
|
279
|
+
// callee
|
|
280
|
+
if (callee==Qnil) {
|
|
281
|
+
VALUE exception = rb_exc_new2(rb_ePHPError, "callee is nil");
|
|
282
|
+
rb_exc_raise(exception);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// method
|
|
286
|
+
zend_function *mptr;
|
|
287
|
+
find_zend_function(ce, RSTRING_PTR(callee), RSTRING_LEN(callee), &mptr);
|
|
288
|
+
|
|
289
|
+
// call
|
|
290
|
+
zval *retval;
|
|
291
|
+
int result = call_php_method(ce, obj, mptr, argc, argv, &retval TSRMLS_CC);
|
|
292
|
+
|
|
293
|
+
// exception
|
|
294
|
+
if (result==FAILURE) {
|
|
295
|
+
// TODO: read var
|
|
296
|
+
// TODO: raise exception. method missing
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return zval_to_value(retval);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
// PHP Native resource
|
|
304
|
+
|
|
305
|
+
void php_native_resource_delete(PHPNativeResource *p)
|
|
306
|
+
{
|
|
307
|
+
free(p);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
zend_class_entry* get_zend_class_entry(VALUE self)
|
|
311
|
+
{
|
|
312
|
+
VALUE resource = rb_iv_get(self, "php_native_resource");
|
|
313
|
+
if (resource==Qnil) {
|
|
314
|
+
return NULL;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
PHPNativeResource *p;
|
|
318
|
+
Data_Get_Struct(rb_iv_get(self, "php_native_resource"), PHPNativeResource, p);
|
|
319
|
+
if (p) {
|
|
320
|
+
return p->ce;
|
|
321
|
+
}
|
|
322
|
+
return NULL;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
zval* get_zval(VALUE self)
|
|
326
|
+
{
|
|
327
|
+
VALUE resource = rb_iv_get(self, "php_native_resource");
|
|
328
|
+
if (resource==Qnil) {
|
|
329
|
+
return NULL;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
PHPNativeResource *p;
|
|
333
|
+
Data_Get_Struct(rb_iv_get(self, "php_native_resource"), PHPNativeResource, p);
|
|
334
|
+
if (p) {
|
|
335
|
+
return p->zobj;
|
|
336
|
+
}
|
|
337
|
+
return NULL;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
// module PHPVM
|
|
342
|
+
|
|
343
|
+
VALUE rb_php_vm_require(VALUE cls, VALUE filepath)
|
|
344
|
+
{
|
|
345
|
+
StringValue(filepath);
|
|
346
|
+
filepath = rb_funcall(filepath, rb_intern("gsub"), 2, rb_str_new2("\\"), rb_str_new2("\\\\"));
|
|
347
|
+
filepath = rb_funcall(filepath, rb_intern("gsub"), 2, rb_str_new2("\""), rb_str_new2("\\\""));
|
|
348
|
+
|
|
349
|
+
VALUE code = rb_str_new2("require \"");
|
|
350
|
+
code = rb_str_plus(code, filepath);
|
|
351
|
+
code = rb_str_plus(code, rb_str_new2("\";"));
|
|
352
|
+
|
|
353
|
+
php_eval_string(RSTRING_PTR(code), RSTRING_LEN(code));
|
|
354
|
+
|
|
355
|
+
return Qnil;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
VALUE rb_php_vm_require_once(VALUE cls, VALUE filepath)
|
|
359
|
+
{
|
|
360
|
+
StringValue(filepath);
|
|
361
|
+
filepath = rb_funcall(filepath, rb_intern("gsub"), 2, rb_str_new2("\\"), rb_str_new2("\\\\"));
|
|
362
|
+
filepath = rb_funcall(filepath, rb_intern("gsub"), 2, rb_str_new2("\""), rb_str_new2("\\\""));
|
|
363
|
+
|
|
364
|
+
VALUE code = rb_str_new2("require_once \"");
|
|
365
|
+
code = rb_str_plus(code, filepath);
|
|
366
|
+
code = rb_str_plus(code, rb_str_new2("\";"));
|
|
367
|
+
|
|
368
|
+
php_eval_string(RSTRING_PTR(code), RSTRING_LEN(code));
|
|
369
|
+
|
|
370
|
+
return Qnil;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
VALUE rb_php_vm_exec(VALUE cls, VALUE code)
|
|
374
|
+
{
|
|
375
|
+
php_eval_string(RSTRING_PTR(code), RSTRING_LEN(code) TSRMLS_CC);
|
|
376
|
+
return Qnil;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
VALUE rb_php_vm_getClass(VALUE cls, VALUE v_class_name)
|
|
380
|
+
{
|
|
381
|
+
return rb_php_class_get(rb_cPHPClass, v_class_name);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
// class PHPVM::PHPClass
|
|
386
|
+
|
|
387
|
+
VALUE rb_php_class_get(VALUE cls, VALUE v_name)
|
|
388
|
+
{
|
|
389
|
+
// find
|
|
390
|
+
VALUE name_sym = rb_str_intern(v_name);
|
|
391
|
+
VALUE classes = rb_cv_get(cls, "@@classes");
|
|
392
|
+
VALUE class = rb_hash_lookup(classes, name_sym);
|
|
393
|
+
|
|
394
|
+
if (class==Qnil) {
|
|
395
|
+
// create
|
|
396
|
+
class = rb_obj_alloc(rb_cPHPClass);
|
|
397
|
+
rb_php_class_initialize(class, v_name);
|
|
398
|
+
rb_hash_aset(classes, name_sym, class);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return class;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
VALUE rb_php_class_initialize(VALUE self, VALUE v_name)
|
|
405
|
+
{
|
|
406
|
+
rb_iv_set(self, "name", v_name);
|
|
407
|
+
|
|
408
|
+
// find zend class
|
|
409
|
+
zend_class_entry **ce = NULL;
|
|
410
|
+
find_zend_class_entry(RSTRING_PTR(v_name), RSTRING_LEN(v_name), &ce);
|
|
411
|
+
|
|
412
|
+
// class not found
|
|
413
|
+
if (!ce) {
|
|
414
|
+
char *message = malloc(32+RSTRING_LEN(v_name));
|
|
415
|
+
sprintf(message, "Class is not found: %s", RSTRING_PTR(v_name));
|
|
416
|
+
VALUE exception = rb_exc_new2(rb_ePHPError, message);
|
|
417
|
+
free(message);
|
|
418
|
+
rb_exc_raise(exception);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// set resource
|
|
422
|
+
PHPNativeResource *p = ALLOC(PHPNativeResource);
|
|
423
|
+
p->ce = *ce;
|
|
424
|
+
VALUE resource = Data_Wrap_Struct(CLASS_OF(self), 0, php_native_resource_delete, p);
|
|
425
|
+
rb_iv_set(self, "php_native_resource", resource);
|
|
426
|
+
|
|
427
|
+
// define php static methods
|
|
428
|
+
define_php_methods(self, *ce, 1);
|
|
429
|
+
|
|
430
|
+
return self;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
VALUE rb_php_class_name(VALUE self)
|
|
434
|
+
{
|
|
435
|
+
return rb_iv_get(self, "name");
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
VALUE rb_php_class_new(int argc, VALUE *argv, VALUE self)
|
|
439
|
+
{
|
|
440
|
+
VALUE args;
|
|
441
|
+
rb_scan_args(argc, argv, "*", &args);
|
|
442
|
+
|
|
443
|
+
VALUE obj = Qnil;
|
|
444
|
+
zend_class_entry *ce = get_zend_class_entry(self);
|
|
445
|
+
if (is_exception_zend_class_entry(ce)) {
|
|
446
|
+
obj = rb_obj_alloc(rb_ePHPExceptionObject);
|
|
447
|
+
} else {
|
|
448
|
+
obj = rb_obj_alloc(rb_cPHPObject);
|
|
449
|
+
}
|
|
450
|
+
rb_php_object_initialize(obj, self, args);
|
|
451
|
+
|
|
452
|
+
// define php instance method
|
|
453
|
+
define_php_methods(obj, ce, 0);
|
|
454
|
+
|
|
455
|
+
return obj;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
VALUE rb_php_class_call(int argc, VALUE *argv, VALUE self)
|
|
459
|
+
{
|
|
460
|
+
zend_class_entry *ce = get_zend_class_entry(self);
|
|
461
|
+
VALUE callee = get_callee_name();
|
|
462
|
+
return call_php_method_bridge(ce, NULL, callee, argc, argv);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
// class PHPVM::PHPObject
|
|
467
|
+
|
|
468
|
+
VALUE rb_php_object_initialize(VALUE self, VALUE class, VALUE args)
|
|
469
|
+
{
|
|
470
|
+
// set class
|
|
471
|
+
rb_iv_set(self, "php_class", class);
|
|
472
|
+
|
|
473
|
+
// create php object
|
|
474
|
+
zend_class_entry *ce = get_zend_class_entry(class);
|
|
475
|
+
zval *z_obj;
|
|
476
|
+
ALLOC_INIT_ZVAL(z_obj);
|
|
477
|
+
new_php_object(ce, args, z_obj);
|
|
478
|
+
|
|
479
|
+
// set resource
|
|
480
|
+
PHPNativeResource *p = ALLOC(PHPNativeResource);
|
|
481
|
+
p->ce = ce;
|
|
482
|
+
p->zobj = z_obj;
|
|
483
|
+
VALUE resource = Data_Wrap_Struct(CLASS_OF(self), 0, php_native_resource_delete, p);
|
|
484
|
+
rb_iv_set(self, "php_native_resource", resource);
|
|
485
|
+
|
|
486
|
+
return self;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
VALUE rb_php_object_php_class(VALUE self)
|
|
490
|
+
{
|
|
491
|
+
return rb_iv_get(self, "php_class");
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
VALUE rb_php_object_call(int argc, VALUE *argv, VALUE self)
|
|
495
|
+
{
|
|
496
|
+
zend_class_entry *ce = get_zend_class_entry(self);
|
|
497
|
+
zval *zobj = get_zval(self);
|
|
498
|
+
VALUE callee = get_callee_name();
|
|
499
|
+
return call_php_method_bridge(ce, zobj, callee, argc, argv);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
// class PHPVM::PHPExceptionObject
|
|
504
|
+
|
|
505
|
+
VALUE rb_php_exception_object_initialize(int argc, VALUE *argv, VALUE self)
|
|
506
|
+
{
|
|
507
|
+
rb_call_super(argc, argv);
|
|
508
|
+
return self;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
// module
|
|
513
|
+
|
|
514
|
+
void php_vm_module_init()
|
|
515
|
+
{
|
|
516
|
+
int argc = 1;
|
|
517
|
+
char *argv[2] = {"php_vm", NULL};
|
|
518
|
+
php_embed_init(argc, argv PTSRMLS_CC);
|
|
519
|
+
EG(bailout) = NULL;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
void php_vm_module_exit()
|
|
523
|
+
{
|
|
524
|
+
php_embed_shutdown(TSRMLS_C);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
void Init_php_vm()
|
|
528
|
+
{
|
|
529
|
+
// initialize php_vm
|
|
530
|
+
php_vm_module_init();
|
|
531
|
+
atexit(php_vm_module_exit);
|
|
532
|
+
|
|
533
|
+
// module PHPVM
|
|
534
|
+
rb_mPHPVM = rb_define_module("PHPVM");
|
|
535
|
+
|
|
536
|
+
rb_define_singleton_method(rb_mPHPVM, "require", rb_php_vm_require, 1);
|
|
537
|
+
rb_define_singleton_method(rb_mPHPVM, "require_once", rb_php_vm_require_once, 1);
|
|
538
|
+
rb_define_singleton_method(rb_mPHPVM, "exec", rb_php_vm_exec, 1);
|
|
539
|
+
rb_define_singleton_method(rb_mPHPVM, "getClass", rb_php_vm_getClass, 1);
|
|
540
|
+
|
|
541
|
+
// class PHPVM::PHPClass
|
|
542
|
+
rb_cPHPClass = rb_define_class_under(rb_mPHPVM, "PHPClass", rb_cObject);
|
|
543
|
+
rb_define_class_variable(rb_cPHPClass, "@@classes", rb_obj_alloc(rb_cHash));
|
|
544
|
+
|
|
545
|
+
rb_define_private_method(rb_cPHPClass, "initialize", rb_php_class_initialize, 1);
|
|
546
|
+
rb_define_method(rb_cPHPClass, "name", rb_php_class_name, 0);
|
|
547
|
+
rb_define_method(rb_cPHPClass, "new", rb_php_class_new, -1);
|
|
548
|
+
rb_define_singleton_method(rb_cPHPClass, "get", rb_php_class_get, 1);
|
|
549
|
+
|
|
550
|
+
// class PHPVM::PHPObject
|
|
551
|
+
rb_cPHPObject = rb_define_class_under(rb_mPHPVM, "PHPObject", rb_cObject);
|
|
552
|
+
|
|
553
|
+
rb_define_private_method(rb_cPHPObject, "initialize", rb_php_object_initialize, 1);
|
|
554
|
+
rb_define_method(rb_cPHPObject, "php_class", rb_php_object_php_class, 0);
|
|
555
|
+
|
|
556
|
+
// class PHPVM::PHPError < StandardError
|
|
557
|
+
rb_ePHPError = rb_define_class_under(rb_mPHPVM, "PHPError", rb_eStandardError);
|
|
558
|
+
|
|
559
|
+
// class PHPVM::PHPExceptionObject < PHPVM::PHPError
|
|
560
|
+
rb_ePHPExceptionObject = rb_define_class_under(rb_mPHPVM, "PHPExceptionObject", rb_ePHPError);
|
|
561
|
+
|
|
562
|
+
rb_define_method(rb_ePHPExceptionObject, "initialize", rb_php_exception_object_initialize, -1);
|
|
563
|
+
rb_define_method(rb_ePHPExceptionObject, "php_class", rb_php_object_php_class, 0);
|
|
564
|
+
|
|
565
|
+
// class PHPVM::PHPSyntaxError < PHPVM::PHPError
|
|
566
|
+
rb_ePHPSyntaxError = rb_define_class_under(rb_mPHPVM, "PHPSyntaxError", rb_ePHPError);
|
|
567
|
+
}
|
data/ext/php_vm.h
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#ifndef PHP_VM_H
|
|
2
|
+
#define PHP_VM_H
|
|
3
|
+
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
#include <sapi/embed/php_embed.h>
|
|
6
|
+
#include <Zend/zend_execute.h>
|
|
7
|
+
#include <Zend/zend_exceptions.h>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
extern VALUE rb_mPHPVM;
|
|
11
|
+
extern VALUE rb_cPHPClass;
|
|
12
|
+
extern VALUE rb_cPHPObject;
|
|
13
|
+
extern VALUE rb_ePHPExceptionObject;
|
|
14
|
+
extern VALUE rb_ePHPError;
|
|
15
|
+
extern VALUE rb_ePHPSyntaxError;
|
|
16
|
+
|
|
17
|
+
typedef struct {
|
|
18
|
+
zend_class_entry *ce;
|
|
19
|
+
zval *zobj;
|
|
20
|
+
} PHPNativeResource;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
// PHP
|
|
24
|
+
extern void php_eval_string(char *code, int code_len TSRMLS_DC);
|
|
25
|
+
extern void find_zend_class_entry(char *name, int name_len, zend_class_entry ***ce);
|
|
26
|
+
extern void find_zend_class_entry2(char *name, zend_class_entry ***ce);
|
|
27
|
+
extern int is_exception_zend_class_entry(zend_class_entry *ce TSRMLS_DC);
|
|
28
|
+
extern int is_exception_zval(zval *z TSRMLS_DC);
|
|
29
|
+
extern int new_php_object(zend_class_entry *ce, VALUE v_args, zval *retval);
|
|
30
|
+
extern void define_php_methods(VALUE v_obj, zend_class_entry *ce, int is_static);
|
|
31
|
+
extern int call_php_method(zend_class_entry *ce, zval *obj, zend_function *mptr, int argc, VALUE *v_argv, zval **retval_ptr TSRMLS_DC);
|
|
32
|
+
|
|
33
|
+
// Ruby
|
|
34
|
+
extern VALUE get_callee_name();
|
|
35
|
+
extern VALUE call_php_method_bridge(zend_class_entry *ce, zval *obj, VALUE callee, int argc, VALUE *argv);
|
|
36
|
+
|
|
37
|
+
// PHP Native resource
|
|
38
|
+
extern void php_native_resource_delete(PHPNativeResource *p);
|
|
39
|
+
extern zend_class_entry* get_zend_class_entry(VALUE self);
|
|
40
|
+
extern zval* get_zval(VALUE self);
|
|
41
|
+
|
|
42
|
+
// module PHPVM
|
|
43
|
+
extern VALUE rb_php_vm_require(VALUE cls, VALUE rbv_filepath);
|
|
44
|
+
extern VALUE rb_php_vm_exec(VALUE cls, VALUE rbv_code);
|
|
45
|
+
extern VALUE rb_php_vm_getClass(VALUE cls, VALUE rbv_class_name);
|
|
46
|
+
|
|
47
|
+
// class PHPVM::PHPClass
|
|
48
|
+
extern VALUE rb_php_class_get(VALUE cls, VALUE rbv_name);
|
|
49
|
+
extern VALUE rb_php_class_initialize(VALUE self, VALUE rbv_name);
|
|
50
|
+
extern VALUE rb_php_class_name(VALUE self);
|
|
51
|
+
extern VALUE rb_php_class_new(int argc, VALUE *argv, VALUE self);
|
|
52
|
+
extern VALUE rb_php_class_call(int argc, VALUE *argv, VALUE self);
|
|
53
|
+
|
|
54
|
+
// class PHPVM::PHPObject
|
|
55
|
+
extern VALUE rb_php_object_initialize(VALUE self, VALUE class, VALUE arg_arr);
|
|
56
|
+
extern VALUE rb_php_object_php_class(VALUE self);
|
|
57
|
+
extern VALUE rb_php_object_call(int argc, VALUE *argv, VALUE self);
|
|
58
|
+
|
|
59
|
+
// module
|
|
60
|
+
extern void php_vm_module_init();
|
|
61
|
+
extern void php_vm_module_exit();
|
|
62
|
+
extern void Init_php_vm();
|
|
63
|
+
|
|
64
|
+
#endif
|
data/ext/php_vm_v2z.c
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#include "php_vm.h"
|
|
2
|
+
#include "php_vm_v2z.h"
|
|
3
|
+
#include <string.h>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
static void value_to_zval_array(VALUE v, zval *z)
|
|
7
|
+
{
|
|
8
|
+
array_init(z);
|
|
9
|
+
|
|
10
|
+
long i;
|
|
11
|
+
for (i=0; i<RARRAY_LEN(v); i++) {
|
|
12
|
+
zval *new_var;
|
|
13
|
+
MAKE_STD_ZVAL(z);
|
|
14
|
+
value_to_zval(RARRAY_PTR(v)[i], new_var);
|
|
15
|
+
|
|
16
|
+
zend_hash_next_index_insert(Z_ARRVAL_P(z), &new_var, sizeof(zval *), NULL);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static void value_to_zval_hash(VALUE v, zval *z)
|
|
21
|
+
{
|
|
22
|
+
array_init(z);
|
|
23
|
+
|
|
24
|
+
v = rb_funcall(v, rb_intern("flatten"), 0);
|
|
25
|
+
|
|
26
|
+
long i;
|
|
27
|
+
for (i=0; i<RARRAY_LEN(v); i+=2) {
|
|
28
|
+
VALUE v_key = RARRAY_PTR(v)[i];
|
|
29
|
+
StringValue(v_key);
|
|
30
|
+
|
|
31
|
+
zval *z_value;
|
|
32
|
+
MAKE_STD_ZVAL(z);
|
|
33
|
+
value_to_zval(RARRAY_PTR(v)[i+1], z_value);
|
|
34
|
+
|
|
35
|
+
add_assoc_zval_ex(z, RSTRING_PTR(v_key), RSTRING_LEN(v), z_value);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
void value_to_zval(VALUE v, zval *z)
|
|
41
|
+
{
|
|
42
|
+
switch (TYPE(v)) {
|
|
43
|
+
// nil
|
|
44
|
+
case T_NIL:
|
|
45
|
+
ZVAL_NULL(z);
|
|
46
|
+
break;
|
|
47
|
+
// bool
|
|
48
|
+
case T_TRUE:
|
|
49
|
+
ZVAL_TRUE(z);
|
|
50
|
+
break;
|
|
51
|
+
case T_FALSE:
|
|
52
|
+
ZVAL_FALSE(z);
|
|
53
|
+
break;
|
|
54
|
+
// number
|
|
55
|
+
case T_FIXNUM:
|
|
56
|
+
ZVAL_LONG(z, NUM2LONG(v));
|
|
57
|
+
break;
|
|
58
|
+
case T_FLOAT:
|
|
59
|
+
ZVAL_DOUBLE(z, RFLOAT_VALUE(v));
|
|
60
|
+
break;
|
|
61
|
+
// array
|
|
62
|
+
case T_ARRAY:
|
|
63
|
+
value_to_zval_array(v, z);
|
|
64
|
+
break;
|
|
65
|
+
// hash
|
|
66
|
+
case T_HASH:
|
|
67
|
+
value_to_zval_hash(v, z);
|
|
68
|
+
break;
|
|
69
|
+
// object string
|
|
70
|
+
default:{
|
|
71
|
+
VALUE cls = CLASS_OF(v);
|
|
72
|
+
if (cls==rb_cPHPObject || cls==rb_ePHPExceptionObject) {
|
|
73
|
+
// wrap php object
|
|
74
|
+
} else {
|
|
75
|
+
// other to_s
|
|
76
|
+
StringValue(v);
|
|
77
|
+
ZVAL_STRING(z, RSTRING_PTR(v), 1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
data/ext/php_vm_v2z.h
ADDED
data/ext/php_vm_z2v.c
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#include "php_vm.h"
|
|
2
|
+
#include "php_vm_z2v.h"
|
|
3
|
+
#include <string.h>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
static int is_array_convertable(HashTable* ht)
|
|
7
|
+
{
|
|
8
|
+
HashPosition pos;
|
|
9
|
+
char *string_key;
|
|
10
|
+
ulong num_index;
|
|
11
|
+
ulong index = 0;
|
|
12
|
+
|
|
13
|
+
zend_hash_internal_pointer_reset_ex(ht, &pos);
|
|
14
|
+
do {
|
|
15
|
+
switch(zend_hash_get_current_key_ex(ht, &string_key, NULL, &num_index, 0, &pos)) {
|
|
16
|
+
case HASH_KEY_IS_STRING:
|
|
17
|
+
return 0;
|
|
18
|
+
case HASH_KEY_NON_EXISTANT:
|
|
19
|
+
return 1;
|
|
20
|
+
case HASH_KEY_IS_LONG:
|
|
21
|
+
if (num_index != index) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
++index;
|
|
25
|
+
}
|
|
26
|
+
} while(SUCCESS == zend_hash_move_forward_ex(ht, &pos));
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static VALUE zval_to_value_array(HashTable* ht)
|
|
31
|
+
{
|
|
32
|
+
HashPosition pos;
|
|
33
|
+
zval** data;
|
|
34
|
+
VALUE ret;
|
|
35
|
+
|
|
36
|
+
ret = rb_ary_new2(zend_hash_num_elements(ht));
|
|
37
|
+
|
|
38
|
+
zend_hash_internal_pointer_reset_ex(ht, &pos);
|
|
39
|
+
while (SUCCESS == zend_hash_get_current_data_ex(ht, (void **)&data, &pos)) {
|
|
40
|
+
VALUE t = zval_to_value(*data);
|
|
41
|
+
rb_ary_push(ret, t);
|
|
42
|
+
zend_hash_move_forward_ex(ht, &pos);
|
|
43
|
+
}
|
|
44
|
+
return ret;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static VALUE zval_to_value_hash(HashTable* ht)
|
|
48
|
+
{
|
|
49
|
+
HashPosition pos;
|
|
50
|
+
zval** data;
|
|
51
|
+
VALUE ret;
|
|
52
|
+
|
|
53
|
+
ret = rb_hash_new();
|
|
54
|
+
|
|
55
|
+
zend_hash_internal_pointer_reset_ex(ht, &pos);
|
|
56
|
+
while (SUCCESS == zend_hash_get_current_data_ex(ht, (void **)&data, &pos)) {
|
|
57
|
+
char* string_key;
|
|
58
|
+
ulong num_index;
|
|
59
|
+
VALUE key = Qnil;
|
|
60
|
+
VALUE val = zval_to_value(*data);
|
|
61
|
+
|
|
62
|
+
switch(zend_hash_get_current_key_ex(ht, &string_key, NULL, &num_index, 0, &pos)) {
|
|
63
|
+
case HASH_KEY_IS_STRING:
|
|
64
|
+
key = rb_str_new_cstr(string_key);
|
|
65
|
+
break;
|
|
66
|
+
case HASH_KEY_IS_LONG:
|
|
67
|
+
key = LONG2NUM(num_index);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
rb_hash_aset(ret, key, val);
|
|
72
|
+
zend_hash_move_forward_ex(ht, &pos);
|
|
73
|
+
}
|
|
74
|
+
return ret;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static VALUE zval_to_value_object(zval *z)
|
|
78
|
+
{
|
|
79
|
+
// class name
|
|
80
|
+
const char *name = "";
|
|
81
|
+
zend_uint name_len = 0;
|
|
82
|
+
int dup;
|
|
83
|
+
dup = zend_get_object_classname(z, &name, &name_len TSRMLS_CC);
|
|
84
|
+
VALUE v_name = rb_str_new(name, name_len);
|
|
85
|
+
|
|
86
|
+
// class
|
|
87
|
+
VALUE class = rb_php_class_get(rb_cPHPClass, v_name);
|
|
88
|
+
|
|
89
|
+
// object
|
|
90
|
+
VALUE obj = Qnil;
|
|
91
|
+
if (is_exception_zval(z)) {
|
|
92
|
+
// exception object
|
|
93
|
+
zval *z_message = zend_read_property(zend_exception_get_default(TSRMLS_C), z, "message", sizeof("message")-1, 0 TSRMLS_CC);
|
|
94
|
+
|
|
95
|
+
obj = rb_exc_new2(rb_ePHPExceptionObject, Z_STRVAL_P(z_message));
|
|
96
|
+
|
|
97
|
+
rb_iv_set(obj, "php_class", class);
|
|
98
|
+
} else {
|
|
99
|
+
// normal object
|
|
100
|
+
obj = rb_obj_alloc(rb_cPHPObject);
|
|
101
|
+
|
|
102
|
+
rb_iv_set(obj, "php_class", class);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// resource
|
|
106
|
+
PHPNativeResource *p = ALLOC(PHPNativeResource);
|
|
107
|
+
p->ce = get_zend_class_entry(class);
|
|
108
|
+
p->zobj = z;
|
|
109
|
+
VALUE resource = Data_Wrap_Struct(CLASS_OF(obj), 0, php_native_resource_delete, p);
|
|
110
|
+
rb_iv_set(obj, "php_native_resource", resource);
|
|
111
|
+
|
|
112
|
+
return obj;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
VALUE zval_to_value(zval *z)
|
|
117
|
+
{
|
|
118
|
+
if (z) {
|
|
119
|
+
switch(Z_TYPE_P(z)) {
|
|
120
|
+
case IS_NULL:
|
|
121
|
+
return Qnil;
|
|
122
|
+
case IS_BOOL:
|
|
123
|
+
return (zval_is_true(z)) ? Qtrue : Qfalse;
|
|
124
|
+
case IS_LONG:
|
|
125
|
+
return INT2NUM(Z_LVAL_P(z));
|
|
126
|
+
case IS_DOUBLE:
|
|
127
|
+
return DBL2NUM(Z_DVAL_P(z));
|
|
128
|
+
case IS_ARRAY:
|
|
129
|
+
case IS_CONSTANT_ARRAY:{
|
|
130
|
+
HashTable* ht = Z_ARRVAL_P(z);
|
|
131
|
+
|
|
132
|
+
if (0 == zend_hash_num_elements(ht)) {
|
|
133
|
+
return rb_ary_new();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (is_array_convertable(ht)) {
|
|
137
|
+
return zval_to_value_array(ht);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return zval_to_value_hash(ht);
|
|
141
|
+
}
|
|
142
|
+
case IS_OBJECT:
|
|
143
|
+
case IS_RESOURCE:
|
|
144
|
+
case IS_CONSTANT:
|
|
145
|
+
return zval_to_value_object(z);
|
|
146
|
+
case IS_STRING:
|
|
147
|
+
return rb_str_new(Z_STRVAL_P(z), Z_STRLEN_P(z));
|
|
148
|
+
default:
|
|
149
|
+
return Qnil;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return Qnil;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
data/ext/php_vm_z2v.h
ADDED
data/sample/class.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH << File.expand_path(__FILE__+"/../../ext/")
|
|
4
|
+
require "php_vm"
|
|
5
|
+
|
|
6
|
+
PHPVM.exec <<EOS
|
|
7
|
+
class HelloClass
|
|
8
|
+
{
|
|
9
|
+
public function __construct($name)
|
|
10
|
+
{
|
|
11
|
+
$this->name = $name;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// instance
|
|
16
|
+
|
|
17
|
+
public function instanceGetHello()
|
|
18
|
+
{
|
|
19
|
+
return "Hello {$this->name}!!";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public function instanceSayHello()
|
|
23
|
+
{
|
|
24
|
+
var_dump($this->instanceGetHello());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// static
|
|
29
|
+
|
|
30
|
+
public static function classGetHello($name)
|
|
31
|
+
{
|
|
32
|
+
return "Hello {$name}!!";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static function classSayHello($name)
|
|
36
|
+
{
|
|
37
|
+
var_dump(self::classGetHello($name));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
EOS
|
|
41
|
+
|
|
42
|
+
HelloClass = PHPVM::getClass("HelloClass")
|
|
43
|
+
|
|
44
|
+
puts "[class]"
|
|
45
|
+
puts HelloClass
|
|
46
|
+
puts HelloClass.name
|
|
47
|
+
puts ""
|
|
48
|
+
|
|
49
|
+
puts "[instance method]"
|
|
50
|
+
h = HelloClass.new("instance world")
|
|
51
|
+
h.instanceSayHello
|
|
52
|
+
p h.instanceGetHello
|
|
53
|
+
puts ""
|
|
54
|
+
|
|
55
|
+
puts "[class method]"
|
|
56
|
+
HelloClass.classSayHello("class world")
|
|
57
|
+
p HelloClass.classGetHello("class world")
|
data/sample/exec.rb
ADDED
data/sample/require.php
ADDED
data/sample/require.rb
ADDED
data/sample/version.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: php_vm
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Yoshida Tetsuya
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-12-23 00:00:00.000000000 Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: php_vm is a native bridge between Ruby and PHP.
|
|
15
|
+
email:
|
|
16
|
+
- yoshida.eth0@gmail.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions:
|
|
19
|
+
- ext/extconf.rb
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- ext/extconf.rb
|
|
23
|
+
- ext/php_vm.c
|
|
24
|
+
- ext/php_vm.h
|
|
25
|
+
- ext/php_vm_v2z.c
|
|
26
|
+
- ext/php_vm_v2z.h
|
|
27
|
+
- ext/php_vm_z2v.c
|
|
28
|
+
- ext/php_vm_z2v.h
|
|
29
|
+
- sample/class.rb
|
|
30
|
+
- sample/exec.rb
|
|
31
|
+
- sample/exec_raise_exception.rb
|
|
32
|
+
- sample/require.php
|
|
33
|
+
- sample/require.rb
|
|
34
|
+
- sample/version.rb
|
|
35
|
+
homepage: ''
|
|
36
|
+
licenses: []
|
|
37
|
+
post_install_message:
|
|
38
|
+
rdoc_options: []
|
|
39
|
+
require_paths:
|
|
40
|
+
- lib
|
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
|
+
none: false
|
|
43
|
+
requirements:
|
|
44
|
+
- - ! '>='
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
|
+
none: false
|
|
49
|
+
requirements:
|
|
50
|
+
- - ! '>='
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
requirements: []
|
|
54
|
+
rubyforge_project:
|
|
55
|
+
rubygems_version: 1.8.23
|
|
56
|
+
signing_key:
|
|
57
|
+
specification_version: 3
|
|
58
|
+
summary: php_vm is a native bridge between Ruby and PHP.
|
|
59
|
+
test_files: []
|