-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathphp_object.cpp
More file actions
181 lines (144 loc) · 4.92 KB
/
php_object.cpp
File metadata and controls
181 lines (144 loc) · 4.92 KB
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
/**
* PhpObject.cpp
*
* Class that wraps around an ecmascript object and makes it available to PHP userspace.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2015 - 2025 Copernica B.V.
*/
/**
* Dependencies
*/
#include "php_object.h"
#include "scope.h"
#include "fromphp.h"
#include "php_variable.h"
#include "php_iterator.h"
#include "php_exception.h"
#include "names.h"
/**
* Start namespace
*/
namespace JS {
/**
* Retrieve a property
* @param name Name of the property
* @return The requested property
*/
Php::Value PhpObject::__get(const Php::Value &name) const
{
// scope for the call
Scope scope(_core);
// get the object in a local variable
v8::Local<v8::Object> object(_object.Get(_core->isolate()).As<v8::Object>());
// get the property value
auto property = object->Get(scope, FromPhp(_core->isolate(), 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 PhpVariable(_core->isolate(), property.ToLocalChecked());
}
/**
* Change a property
* @param name Name of the property
* @param property New value for the property
*/
void PhpObject::__set(const Php::Value &name, const Php::Value &property)
{
// scope for the call
Scope scope(_core);
// get the object in a local variable
v8::Local<v8::Object> object(_object.Get(_core->isolate()).As<v8::Object>());
// convert the value to a ecmascript value and store it (we explicitly want to ignore the return-value)
object->Set(scope, FromPhp(_core->isolate(), name), FromPhp(_core->isolate(), property)).Check();
}
/**
* Check if a property is set
* @param name Name of the property
* @return Is the property set
*/
bool PhpObject::__isset(const Php::Value &name)
{
// scope for the call
Scope scope(_core);
// get the object in a local variable
v8::Local<v8::Object> object(_object.Get(_core->isolate()).As<v8::Object>());
// check if the object has the requested property
auto result = object->Has(scope, FromPhp(_core->isolate(), name));
// check for success
return result.IsJust() && result.FromJust();
}
/**
* 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 PhpObject::__call(const char *name, Php::Parameters ¶ms)
{
// scope for the call
Scope scope(_core);
// get the object in a local variable
v8::Local<v8::Object> object(_object.Get(_core->isolate()).As<v8::Object>());
// construct the method name
auto methodname = v8::String::NewFromUtf8(_core->isolate(), name);
if (methodname.IsEmpty()) throw Php::Exception("invalid method name");
// variables to store property
v8::Local<v8::Value> property;
// do the checks
if (!object->Get(scope, methodname.ToLocalChecked()).ToLocal(&property)) throw Php::Exception("no such property");
// it must be a function
if (!property->IsFunction()) throw Php::Exception("not a method");
// convert to a function
v8::Local<v8::Function> method = property.As<v8::Function>();
// we need the parameters
std::vector<v8::Local<v8::Value>> args;
// convert the parameters
for (size_t i = 0; i < params.size(); ++i)
{
// set a parameter
args.push_back(FromPhp(_core->isolate(), params[i]));
}
// catch any errors that occur while either compiling or running the script
v8::TryCatch catcher(_core->isolate());
// the result
auto result = method->Call(scope, object, args.size(), args.data());
// no exception
if (!catcher.HasCaught()) return result.IsEmpty() ? Php::Value(nullptr) : PhpVariable(_core->isolate(), result.ToLocalChecked());
// pass this exception on to PHP userspace
throw PhpException(_core->isolate(), catcher);
}
/**
* Cast to a string
* @return The result of the string conversion
*/
Php::Value PhpObject::__toString()
{
// scope for the call
Scope scope(_core);
// get the object in a local variable
v8::Local<v8::Object> object(_object.Get(_core->isolate()).As<v8::Object>());
// convert to string and then to php
auto result = object->ToString(scope);
// if not set
if (result.IsEmpty()) return nullptr;
// convert to php space
return PhpVariable(_core->isolate(), result.ToLocalChecked());
}
/**
* Retrieve the iterator
* @return The iterator
*/
Php::Iterator *PhpObject::getIterator()
{
// scope for the call
Scope scope(_core);
// get the object in a local variable
v8::Local<v8::Object> object(_object.Get(_core->isolate()).As<v8::Object>());
// create a new iterator instance, cleaned up by PHP-CPP
return new PhpIterator(this, _core, object);
}
/**
* End namespace
*/
}