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::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 StringData
* 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 StringData
* className
) {
121 registerNativePropHandler(
123 &nativePropHandlerGet
<T
>,
124 &nativePropHandlerSet
<T
>,
125 &nativePropHandlerIsset
<T
>,
126 &nativePropHandlerUnset
<T
>
131 void registerNativePropHandler(const String
& className
) {
132 registerNativePropHandler
<T
>(className
.get());
136 * Base prop handler class, to be extended by actual prop handlers.
137 * By default handlers are "noop", that can be overridden by
140 struct BasePropHandler
{
141 static Variant
getProp(const Object
& /*this_*/, const String
& /*name*/) {
142 return Native::prop_not_handled();
144 static Variant
setProp(const Object
& /*this_*/, const String
& /*name*/,
145 const Variant
& /*value*/) {
146 return Native::prop_not_handled();
148 static Variant
issetProp(const Object
& /*this_*/, const String
& /*name*/) {
149 return Native::prop_not_handled();
151 static Variant
unsetProp(const Object
& /*this_*/, const String
& /*name*/) {
152 return Native::prop_not_handled();
154 static bool isPropSupported(const String
& /*name*/, const String
& /*op*/) {
159 #define CHECK_ACCESSOR(accesor, opstr, classname, propname) \
161 raise_error("Cannot directly %s the property %s::$%s", \
162 opstr, classname->data(), propname.data()); \
166 * Base prop handler class, that uses `Native::PropAccessorMap`.
167 * Derived classes provide the handling map with accessors per each property.
169 template <class Derived
>
170 struct MapPropHandler
: BasePropHandler
{
172 static Variant
getProp(const Object
& this_
, const String
& name
) {
173 auto get
= Derived::map
.get(name
);
174 CHECK_ACCESSOR(get
, "get", this_
->getVMClass()->name(), name
)
178 static Variant
setProp(const Object
& this_
,
180 const Variant
& value
) {
181 auto set
= Derived::map
.set(name
);
182 CHECK_ACCESSOR(set
, "set", this_
->getVMClass()->name(), name
);
187 static Variant
issetProp(const Object
& this_
, const String
& name
) {
188 auto isset
= Derived::map
.isset(name
);
189 // If there is special `isset`, call it.
193 // Otherwise, fallback to `null` check of the result from `get`.
194 auto get
= Derived::map
.get(name
);
195 CHECK_ACCESSOR(get
, "get", this_
->getVMClass()->name(), name
)
196 return !get(this_
).isNull();
199 static Variant
unsetProp(const Object
& this_
, const String
& name
) {
200 auto unset
= Derived::map
.unset(name
);
201 CHECK_ACCESSOR(unset
, "unset", this_
->getVMClass()->name(), name
);
206 static bool isPropSupported(const String
& name
, const String
& /*op*/) {
207 return Derived::map
.isPropSupported(name
);
212 * An entry in the `PropAccessorMap`, contains handlers per property.
214 struct PropAccessor
{
216 Variant (*get
)(const Object
& this_
);
217 void (*set
)(const Object
& this_
, const Variant
& value
);
218 bool (*isset
)(const Object
& this_
);
219 void (*unset
)(const Object
& this_
);
223 size_t operator()(const PropAccessor
* pa
) const {
224 return hash_string_i(pa
->name
, strlen(pa
->name
));
229 bool operator()(const PropAccessor
* pa1
, const PropAccessor
* pa2
) const;
233 * Map-based handling of property accessors. Callers may organize handlers
234 * into a map with handling function per each property. Example:
236 * static Native::PropAccessor elementPropAccessors[] = {
237 * {"nodeValue", elementNodeValueGet, elementNodeValueSet, ...},
238 * {"localName", elementLocaleNameGet, nullptr, ...},
243 struct PropAccessorMap
:
244 private hphp_hash_set
<PropAccessor
*, hashNPA
, cmpNPA
> {
246 explicit PropAccessorMap(PropAccessor
* props
,
247 PropAccessorMap
*base
= nullptr);
249 bool isPropSupported(const String
& name
);
251 Variant (*get(const String
& name
))(const Object
& this_
);
253 void (*set(const String
& name
))(const Object
& this_
,
254 const Variant
& value
);
256 bool (*isset(const String
& name
))(const Object
& this_
);
257 void (*unset(const String
& name
))(const Object
& this_
);
260 const_iterator
lookupProp(const String
& name
);
264 * API methods to call at property resolution (from `object-data`).
265 * Example: Native::getProp(this, propName);
267 Variant
getProp(const Object
& obj
, const String
& name
);
268 Variant
setProp(const Object
& obj
, const String
& name
, const Variant
& value
);
269 Variant
issetProp(const Object
& obj
, const String
& name
);
270 Variant
unsetProp(const Object
& obj
, const String
& name
);
272 //////////////////////////////////////////////////////////////////////////////
273 } // namespace HPHP::Native
275 #endif // _incl_HPHP_RUNTIME_VM_NATIVE_PROP_HANDLER_H