-
Notifications
You must be signed in to change notification settings - Fork 25
/
jsobject.cpp
232 lines (203 loc) · 5.94 KB
/
jsobject.cpp
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/**
* jsobject.cpp
*
* Class that wraps around an ecmascript object
* and makes it available to PHP userspace.
*
* @copyright 2015 Copernica B.V.
*/
/**
* Dependencies
*/
#include "jsobject.h"
#include "value.h"
/**
* Start namespace
*/
namespace JS {
/**
* Constructor
*
* @param base The base that PHP-CPP insists on
* @param object The object to iterate
*/
JSObject::Iterator::Iterator(Php::Base *base, const Stack<v8::Object> &object) :
Php::Iterator(base),
_object(object),
_position(0)
{
// create a handle scope, so variables "fall out of scope" and "enter" the context
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(object->CreationContext());
// assign variables, this would normally be done inside
// the initializer list, but that way we can't create a
// HandleScope first and v8 refuses to work without one
_keys = _object->GetPropertyNames();
_size = _keys->Length();
}
/**
* Is the iterator still valid?
*
* @return is an element present at the current offset
*/
bool JSObject::Iterator::valid()
{
// we should not be out of bounds
return _position < _size;
}
/**
* Retrieve the current value
*
* @return value at current offset
*/
Php::Value JSObject::Iterator::current()
{
// create a handle scope, so variables "fall out of scope" and "enter" the context
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(_object->CreationContext());
// retrieve the current key, the value and convert it
return value(_object->Get(_keys->Get(_position)));
}
/**
* Retrieve the current key
*
* @return the current key
*/
Php::Value JSObject::Iterator::key()
{
// create a handle scope, so variables "fall out of scope" and "enter" the context
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(_object->CreationContext());
// retrieve the current key and convert it
return value(_keys->Get(_position));
}
/**
* Move ahead to the next item
*/
void JSObject::Iterator::next()
{
// move to the next position
++_position;
}
/**
* Start over at the beginning
*/
void JSObject::Iterator::rewind()
{
// move back to the beginning
_position = 0;
}
/**
* Constructor
*
* @param object The ecmascript object
*/
JSObject::JSObject(v8::Handle<v8::Object> object) :
_object(object)
{}
/**
* Retrieve a property
*
* @param name Name of the property
* @return The requested property
*/
Php::Value JSObject::__get(const Php::Value &name) const
{
// create a handle scope, so variables "fall out of scope", "enter" the context and retrieve the property
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(_object->CreationContext());
v8::Local<v8::Value> property(_object->Get(value(name)));
// if it does not exist, we fall back on the default behavior
if (property.IsEmpty()) return Php::Base::__get(name);
// convert the value to a PHP value
return value(property);
}
/**
* Change a property
*
* @param name Name of the property
* @param property New value for the property
*/
void JSObject::__set(const Php::Value &name, const Php::Value &property)
{
// create a handle scope, so variables "fall out of scope" and "enter" the context
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(_object->CreationContext());
// convert the value to a ecmascript value and store it
_object->Set(value(name), value(property));
}
/**
* Check if a property is set
*
* @param name Name of the property
* @return Is the property set
*/
bool JSObject::__isset(const Php::Value &name)
{
// create a handle scope, so variables "fall out of scope" and "enter" the context
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(_object->CreationContext());
// check if the object has the requested property
return _object->Has(value(name));
}
/**
* Call a function
*
* @param name Name of the function to call
* @param params The input parameters
* @return The result of the function call
*/
Php::Value JSObject::__call(const char *name, Php::Parameters ¶ms)
{
// create a handle scope, so variables "fall out of scope", "enter" the context and retrieve the value
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(_object->CreationContext());
v8::Local<v8::Function> function(_object->Get(value(Php::Value(name))).As<v8::Function>());
std::vector<v8::Local<v8::Value>> input;
// check whether the value actually exists
if (function.IsEmpty()) throw Php::Exception(std::string{ "No such method: " } + name);
// reserve space for the input values
input.reserve(params.size());
// fill all the elements
for (auto ¶m : params) input.push_back(value(param));
// execute the function and return the result
return value(function->Call(static_cast<v8::Local<v8::Object>>(_object), input.size(), input.data()));
}
/**
* Cast to a string
*
* @return The result of the string conversion
*/
Php::Value JSObject::__toString()
{
// create a handle scope, so variables "fall out of scope" and "enter" the context
v8::HandleScope scope(Isolate::get());
v8::Context::Scope context(_object->CreationContext());
// convert to string and then to php
return value(_object->ToString());
}
/**
* Retrieve the iterator
*
* @return The iterator
*/
Php::Iterator *JSObject::getIterator()
{
// create a new iterator instance
// it is cleaned up by PHP-CPP
return new Iterator(this, _object);
}
/**
* Retrieve the original ecmascript value
*
* @return original ecmascript value
*/
v8::Local<v8::Object> JSObject::object() const
{
// the stack has the original object
return _object;
}
/**
* End namespace
*/
}