2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #ifndef _incl_HPHP_RUNTIME_VM_NATIVE_PROP_HANDLER_H
17 #define _incl_HPHP_RUNTIME_VM_NATIVE_PROP_HANDLER_H
19 #include "hphp/runtime/ext/extension.h"
20 #include "hphp/util/hash-set.h"
22 namespace HPHP
{ namespace Native
{
23 //////////////////////////////////////////////////////////////////////////////
24 // Class NativePropHandler
26 struct NativePropHandler
{
27 typedef Variant (*GetFunc
)(const Object
& obj
, const String
& name
);
28 typedef Variant (*SetFunc
)(const Object
& obj
, const String
& name
,
29 const Variant
& value
);
30 typedef Variant (*IssetFunc
)(const Object
& obj
, const String
& name
);
31 typedef Variant (*UnsetFunc
)(const Object
& obj
, const String
& name
);
33 GetFunc get
; // native magic prop get
34 SetFunc set
; // native magic set
35 IssetFunc isset
; // native magic isset
36 UnsetFunc unset
; // native magic unset
39 // Sigil value to use in property resolution in case
40 // if the native accessor didn't handle the prop, and
41 // we should try user-level magic accessors.
42 ALWAYS_INLINE Variant
prop_not_handled() {
46 NativePropHandler
* getNativePropHandler(const StringData
* className
);
49 * Handler for a class with custom handling functions.
51 void registerNativePropHandler(const String
& className
,
52 NativePropHandler::GetFunc get
,
53 NativePropHandler::SetFunc set
,
54 NativePropHandler::IssetFunc isset
,
55 NativePropHandler::UnsetFunc unset
);
58 * Default implementations of the accessor hooks. A property handler
59 * class is supposed to implement `getProp`, `setProp`, `issetProp`,
60 * `unsetProp`, and `isPropSupported`. If a method cannot handle property,
61 * it should return sigil `Native::prop_not_handled` value.
65 * struct ElementPropHandler {
66 * static Variant getProp(const Object& this_, const String& name) {
73 // A guard to stop handling in case if the property is not supported
74 // for this operation, and we should go to the user-level magic hooks.
76 #define CHECK_NATIVE_PROP_SUPPORTED(name, op) \
77 if (!T::isPropSupported(name, op)) { \
78 return Native::prop_not_handled(); \
84 Variant
nativePropHandlerGet(const Object
& obj
, const String
& name
) {
85 CHECK_NATIVE_PROP_SUPPORTED(name
, "get")
86 return T::getProp(obj
, name
);
92 Variant
nativePropHandlerSet(const Object
& obj
,
94 const Variant
& value
) {
95 CHECK_NATIVE_PROP_SUPPORTED(name
, "set")
96 return T::setProp(obj
, name
, value
);
102 Variant
nativePropHandlerIsset(const Object
& obj
, const String
& name
) {
103 CHECK_NATIVE_PROP_SUPPORTED(name
, "isset")
104 return T::issetProp(obj
, name
);
107 // Default unsetProp.
110 Variant
nativePropHandlerUnset(const Object
& obj
, const String
& name
) {
111 CHECK_NATIVE_PROP_SUPPORTED(name
, "unset")
112 return T::unsetProp(obj
, name
);
116 * Default registering for a class name.
117 * Example: Native::registerNativePropHandler<HandlerClassName>(className);
120 void registerNativePropHandler(const String
& className
) {
121 registerNativePropHandler(
123 &nativePropHandlerGet
<T
>,
124 &nativePropHandlerSet
<T
>,
125 &nativePropHandlerIsset
<T
>,
126 &nativePropHandlerUnset
<T
>
131 * Base prop handler class, to be extended by actual prop handlers.
132 * By default handlers are "noop", that can be overridden by
135 struct BasePropHandler
{
136 static Variant
getProp(const Object
& /*this_*/, const String
& /*name*/) {
137 return Native::prop_not_handled();
139 static Variant
setProp(const Object
& /*this_*/, const String
& /*name*/,
140 const Variant
& /*value*/) {
141 return Native::prop_not_handled();
143 static Variant
issetProp(const Object
& /*this_*/, const String
& /*name*/) {
144 return Native::prop_not_handled();
146 static Variant
unsetProp(const Object
& /*this_*/, const String
& /*name*/) {
147 return Native::prop_not_handled();
149 static bool isPropSupported(const String
& /*name*/, const String
& /*op*/) {
154 #define CHECK_ACCESSOR(accesor, opstr, classname, propname) \
156 raise_error("Cannot directly %s the property %s::$%s", \
157 opstr, classname->data(), propname.data()); \
161 * Base prop handler class, that uses `Native::PropAccessorMap`.
162 * Derived classes provide the handling map with accessort per each property.
164 template <class Derived
>
165 struct MapPropHandler
: BasePropHandler
{
167 static Variant
getProp(const Object
& this_
, const String
& name
) {
168 auto get
= Derived::map
.get(name
);
169 CHECK_ACCESSOR(get
, "get", this_
->getVMClass()->name(), name
)
173 static Variant
setProp(const Object
& this_
,
175 const Variant
& value
) {
176 auto set
= Derived::map
.set(name
);
177 CHECK_ACCESSOR(set
, "set", this_
->getVMClass()->name(), name
);
182 static Variant
issetProp(const Object
& this_
, const String
& name
) {
183 auto isset
= Derived::map
.isset(name
);
184 // If there is special `isset`, call it.
188 // Otherwise, fallback to `null` check of the result from `get`.
189 auto get
= Derived::map
.get(name
);
190 CHECK_ACCESSOR(get
, "get", this_
->getVMClass()->name(), name
)
191 return !get(this_
).isNull();
194 static Variant
unsetProp(const Object
& this_
, const String
& name
) {
195 auto unset
= Derived::map
.unset(name
);
196 CHECK_ACCESSOR(unset
, "unset", this_
->getVMClass()->name(), name
);
201 static bool isPropSupported(const String
& name
, const String
& /*op*/) {
202 return Derived::map
.isPropSupported(name
);
207 * An entry in the `PropAccessorMap`, contains handlers per property.
209 struct PropAccessor
{
211 Variant (*get
)(const Object
& this_
);
212 void (*set
)(const Object
& this_
, const Variant
& value
);
213 bool (*isset
)(const Object
& this_
);
214 void (*unset
)(const Object
& this_
);
218 size_t operator()(const PropAccessor
* pa
) const {
219 return hash_string_i(pa
->name
, strlen(pa
->name
));
223 bool operator()(const PropAccessor
* pa1
,
224 const PropAccessor
* pa2
) const {
225 return strcasecmp(pa1
->name
, pa2
->name
) == 0;
230 * Map-based handling of property accessors. Callers may organize handlers
231 * into a map with handling function per each property. Example:
233 * static Native::PropAccessor elementPropAccessors[] = {
234 * {"nodeValue", elementNodeValueGet, elementNodeValueSet, ...},
235 * {"localName", elementLocaleNameGet, nullptr, ...},
240 struct PropAccessorMap
:
241 private hphp_hash_set
<PropAccessor
*, hashNPA
, cmpNPA
> {
243 explicit PropAccessorMap(PropAccessor
* props
,
244 PropAccessorMap
*base
= nullptr);
246 bool isPropSupported(const String
& name
);
248 Variant (*get(const String
& name
))(const Object
& this_
);
250 void (*set(const String
& name
))(const Object
& this_
,
251 const Variant
& value
);
253 bool (*isset(const String
& name
))(const Object
& this_
);
254 void (*unset(const String
& name
))(const Object
& this_
);
257 const_iterator
lookupProp(const String
& name
);
261 * API methods to call at property resolution (from `object-data`).
262 * Example: Native::getProp(this, propName);
264 Variant
getProp(const Object
& obj
, const String
& name
);
265 Variant
setProp(const Object
& obj
, const String
& name
, const Variant
& value
);
266 Variant
issetProp(const Object
& obj
, const String
& name
);
267 Variant
unsetProp(const Object
& obj
, const String
& name
);
269 inline bool isPropHandled(Variant
& propResult
) {
270 return propResult
.isInitialized();
273 //////////////////////////////////////////////////////////////////////////////
274 }} // namespace HPHP::Native
276 #endif // _incl_HPHP_RUNTIME_VM_NATIVE_PROP_HANDLER_H