2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/ext/reflection/ext_reflection.h"
20 #include "hphp/runtime/base/array-init.h"
21 #include "hphp/runtime/base/externals.h"
22 #include "hphp/runtime/base/mixed-array.h"
23 #include "hphp/runtime/base/runtime-option.h"
24 #include "hphp/runtime/base/string-util.h"
25 #include "hphp/runtime/base/tv-refcount.h"
26 #include "hphp/runtime/base/type-structure.h"
27 #include "hphp/runtime/base/type-variant.h"
28 #include "hphp/runtime/vm/jit/translator-inline.h"
29 #include "hphp/runtime/vm/native-data.h"
31 #include "hphp/runtime/ext/debugger/ext_debugger.h"
32 #include "hphp/runtime/ext/std/ext_std_closure.h"
33 #include "hphp/runtime/ext/collections/ext_collections-set.h"
34 #include "hphp/runtime/ext/std/ext_std_misc.h"
35 #include "hphp/runtime/ext/string/ext_string.h"
36 #include "hphp/runtime/ext/extension-registry.h"
38 #include "hphp/parser/parser.h"
39 #include "hphp/system/systemlib.h"
41 #include "hphp/runtime/vm/native-prop-handler.h"
44 #include <boost/algorithm/string/predicate.hpp>
48 ///////////////////////////////////////////////////////////////////////////////
56 s_constants("constants"),
57 s_constructor("constructor"),
58 s_functions("functions"),
62 s_protected("protected"),
68 s_modifiers("modifiers"),
70 s_prototype("prototype"),
74 s_nullable("nullable"),
76 s_is_optional("is_optional"),
77 s_is_variadic("is_variadic"),
79 s_defaultValue("defaultValue"),
80 s_defaultText("defaultText"),
83 s_abstract("abstract"),
84 s_instantiable("instantiable"),
85 s_internal("internal"),
86 s_is_async("is_async"),
87 s_is_closure("is_closure"),
88 s_is_generator("is_generator"),
90 s_static_variables("static_variables"),
91 s_extension("extension"),
92 s_interfaces("interfaces"),
94 s_interface("interface"),
97 s_properties("properties"),
98 s_private_properties("private_properties"),
99 s_properties_index("properties_index"),
100 s_private_properties_index("private_properties_index"),
101 s_attributes("attributes"),
102 s_function("function"),
103 s_trait_aliases("trait_aliases"),
105 s___invoke("__invoke"),
106 s_return_type("return_type"),
107 s_accessible("accessible"),
108 s_reflectionexception("ReflectionException"),
109 s_reflectionextension("ReflectionExtension"),
110 s_type_hint("type_hint"),
111 s_type_hint_builtin("type_hint_builtin"),
112 s_type_hint_nullable("type_hint_nullable");
114 Class
* Reflection::s_ReflectionExceptionClass
= nullptr;
115 Class
* Reflection::s_ReflectionExtensionClass
= nullptr;
117 Class
* get_cls(const Variant
& class_or_object
) {
118 if (class_or_object
.is(KindOfObject
)) {
119 return class_or_object
.toCObjRef()->getVMClass();
122 return Unit::loadClass(class_or_object
.toString().get());
125 const Func
* get_method_func(const Class
* cls
, const String
& meth_name
) {
126 const Func
* func
= cls
->lookupMethod(meth_name
.get());
128 if (cls
->attrs() & (AttrInterface
| AttrAbstract
| AttrTrait
)) {
129 const Class::InterfaceMap
& ifaces
= cls
->allInterfaces();
130 for (int i
= 0, size
= ifaces
.size(); i
< size
; i
++) {
131 func
= ifaces
[i
]->lookupMethod(meth_name
.get());
136 assert(func
== nullptr || func
->isMethod());
140 Variant
default_arg_from_php_code(const Func::ParamInfo
& fpi
,
142 assert(fpi
.hasDefaultValue());
143 if (fpi
.hasScalarDefaultValue()) {
144 // Most of the time the default value is scalar, so we can
145 // avoid evaling in the common case
146 return tvAsVariant((TypedValue
*)&fpi
.defaultValue
);
148 // Eval PHP code to get default value. Note that access of
149 // undefined class constants can cause the eval() to
150 // fatal. Zend lets such fatals propagate, so don't bother catching
152 return g_context
->getEvaledArg(
154 // We use cls() instead of implCls() because we want the namespace and
155 // class context for which the closure is scoped, not that of the Closure
156 // subclass (which, among other things, is always globally namespaced).
157 func
->cls() ? func
->cls()->nameStr() : func
->nameStr(),
163 Array
HHVM_FUNCTION(hphp_get_extension_info
, const String
& name
) {
166 Extension
*ext
= ExtensionRegistry::get(name
);
168 ret
.set(s_name
, name
);
169 ret
.set(s_version
, ext
? ext
->getVersion() : "");
170 ret
.set(s_info
, empty_string_variant_ref
);
171 ret
.set(s_ini
, Array::Create());
172 ret
.set(s_constants
, Array::Create());
173 ret
.set(s_functions
, Array::Create());
174 ret
.set(s_classes
, Array::Create());
179 int get_modifiers(Attr attrs
, bool cls
) {
180 int php_modifier
= 0;
181 if (attrs
& AttrAbstract
) php_modifier
|= cls
? 0x20 : 0x02;
182 if (attrs
& AttrFinal
) php_modifier
|= cls
? 0x40 : 0x04;
183 if (attrs
& AttrStatic
) php_modifier
|= 0x01;
184 if (!cls
) { // AttrPublic bits are not valid on class (have other meaning)
185 if (attrs
& AttrPublic
) php_modifier
|= 0x100;
186 if (attrs
& AttrProtected
) php_modifier
|= 0x200;
187 if (attrs
& AttrPrivate
) php_modifier
|= 0x400;
193 static Attr
attrs_from_modifiers(int php_modifier
, bool cls
) {
194 Attr attrs
= (Attr
) 0;
195 if (php_modifier
& (cls
? 0x20 : 0x02)) {
196 attrs
= (Attr
)(attrs
| AttrAbstract
);
198 if (php_modifier
& (cls
? 0x40 : 0x04)) {
199 attrs
= (Attr
)(attrs
| AttrFinal
);
201 if (php_modifier
& 0x01) { attrs
= (Attr
)(attrs
| AttrStatic
); }
202 if (!cls
) { // AttrPublic bits are not valid on class (have other meaning)
203 if (php_modifier
& 0x100) { attrs
= (Attr
)(attrs
| AttrPublic
); }
204 if (php_modifier
& 0x200) { attrs
= (Attr
)(attrs
| AttrProtected
); }
205 if (php_modifier
& 0x400) { attrs
= (Attr
)(attrs
| AttrPrivate
); }
210 static void set_attrs(Array
& ret
, int modifiers
) {
211 if (modifiers
& 0x100) {
212 ret
.set(s_access
, VarNR(s_public
).tv());
213 ret
.set(s_accessible
, true_varNR
.tv());
214 } else if (modifiers
& 0x200) {
215 ret
.set(s_access
, VarNR(s_protected
).tv());
216 ret
.set(s_accessible
, false_varNR
.tv());
217 } else if (modifiers
& 0x400) {
218 ret
.set(s_access
, VarNR(s_private
).tv());
219 ret
.set(s_accessible
, false_varNR
.tv());
223 ret
.set(s_modifiers
, make_tv
<KindOfInt64
>(modifiers
));
224 if (modifiers
& 0x1) {
225 ret
.set(s_static
, true_varNR
.tv());
227 if (modifiers
& 0x44) {
228 ret
.set(s_final
, true_varNR
.tv());
230 if (modifiers
& 0x22) {
231 ret
.set(s_abstract
, true_varNR
.tv());
235 static void set_empty_doc_comment(Array
& ret
) {
236 ret
.set(s_doc
, false_varNR
.tv());
239 static void set_doc_comment(Array
& ret
,
240 const StringData
* comment
,
242 if (comment
== nullptr || comment
->empty()) {
243 set_empty_doc_comment(ret
);
244 } else if (isBuiltin
&& !HHVM_FUNCTION(hphp_debugger_attached
)) {
245 set_empty_doc_comment(ret
);
247 assertx(!comment
->isRefCounted());
248 ret
.set(s_doc
, make_tv
<KindOfPersistentString
>(comment
));
252 static void set_instance_prop_info(Array
& ret
,
253 const Class::Prop
* prop
,
254 const Variant
& default_val
) {
255 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(prop
->name
));
256 ret
.set(s_default
, true_varNR
.tv());
257 ret
.set(s_defaultValue
, default_val
);
258 set_attrs(ret
, get_modifiers(prop
->attrs
, false) & ~0x66);
259 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
260 set_doc_comment(ret
, prop
->docComment
, prop
->cls
->isBuiltin());
262 if (prop
->typeConstraint
&& prop
->typeConstraint
->size()) {
263 ret
.set(s_type
, make_tv
<KindOfPersistentString
>(prop
->typeConstraint
));
265 ret
.set(s_type
, false_varNR
.tv());
269 static void set_dyn_prop_info(
272 const StringData
* className
) {
273 ret
.set(s_name
, name
);
274 set_attrs(ret
, get_modifiers(AttrPublic
, false) & ~0x66);
275 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(className
));
276 set_empty_doc_comment(ret
);
277 ret
.set(s_type
, false_varNR
.tv());
280 static void set_static_prop_info(Array
&ret
, const Class::SProp
* prop
) {
281 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(prop
->name
));
282 ret
.set(s_default
, true_varNR
.tv());
283 ret
.set(s_defaultValue
, prop
->val
);
284 set_attrs(ret
, get_modifiers(prop
->attrs
, false) & ~0x66);
285 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
286 set_doc_comment(ret
, prop
->docComment
, prop
->cls
->isBuiltin());
287 if (prop
->typeConstraint
&& prop
->typeConstraint
->size()) {
288 ret
.set(s_type
, make_tv
<KindOfPersistentString
>(prop
->typeConstraint
));
290 ret
.set(s_type
, false_varNR
.tv());
294 static bool resolveConstant(const char *p
, int64_t len
, Variant
&cns
) {
296 while (len
&& (*p
== ' ')) {
301 while (len
&& (p
[len
-1] == ' ')) {
305 String
cname(p
, len
, CopyString
);
307 if (!f_defined(cname
)) {
312 cns
= f_constant(cname
);
316 bool resolveDefaultParameterConstant(const char *value
, int64_t valueLen
,
318 const char *p
= value
;
319 const char *e
= value
+ valueLen
;
324 while ((s
= strchr(p
, '|'))) {
326 if (!resolveConstant(p
, s
- p
, cns
)) {
329 lval
|= cns
.toInt64();
332 if (!resolveConstant(p
, e
- p
, cns
)) {
336 cns
= cns
.toInt64() | lval
;
341 static bool isConstructor(const Func
* func
) {
342 PreClass
* pcls
= func
->preClass();
343 if (!pcls
|| (pcls
->attrs() & AttrInterface
)) { return false; }
344 if (func
->implCls()) { return func
== func
->implCls()->getCtor(); }
345 if (0 == strcasecmp("__construct", func
->name()->data())) { return true; }
346 /* A same named function is not a constructor in a trait */
347 if (pcls
->attrs() & AttrTrait
) return false;
348 return pcls
->name()->isame(func
->name());
351 static const Class
* get_prototype_class_from_interfaces(const Class
*cls
,
353 // only looks at the interfaces if the method is public
354 if (!func
->isPublic()) return nullptr;
355 const Class::InterfaceMap
& interfaces
= cls
->allInterfaces();
356 for (unsigned int i
= 0, size
= interfaces
.size(); i
< size
; i
++) {
357 const Class
* iface
= interfaces
[i
];
358 if (iface
->preClass()->hasMethod(func
->name())) return iface
;
363 Variant
HHVM_FUNCTION(hphp_invoke
, const String
& name
, const Variant
& params
) {
364 return invoke(name
.data(), params
);
367 static const StaticString
s_invoke_not_instanceof_error(
368 "Given object is not an instance of the class this method was declared in"
371 static const StaticString
s_invoke_non_object(
372 "Non-object passed to Invoke()"
375 Variant
HHVM_FUNCTION(hphp_invoke_method
, const Variant
& obj
,
378 const Variant
& params
) {
380 return invoke_static_method(cls
, name
, params
);
383 if (!obj
.is(KindOfObject
)) {
384 Reflection::ThrowReflectionExceptionObject(s_invoke_non_object
);
387 auto const providedClass
= Unit::loadClass(cls
.get());
388 if (!providedClass
) {
389 raise_error("Call to undefined method %s::%s()", cls
.data(), name
.data());
391 auto const selectedFunc
= providedClass
->lookupMethod(name
.get());
393 raise_error("Call to undefined method %s::%s()", cls
.data(), name
.data());
396 auto const objData
= obj
.toCObjRef().get();
397 auto const implementingClass
= selectedFunc
->implCls();
398 if (!objData
->instanceof(implementingClass
)) {
399 Reflection::ThrowReflectionExceptionObject(s_invoke_not_instanceof_error
);
402 // Get the CallCtx this way instead of using vm_decode_function() because
403 // vm_decode_function() has no way to specify a class independent from the
404 // class::function being called.
405 // Note that this breaks the rules for name lookup (for protected and private)
406 // but that's okay because so does Zend's implementation.
408 ctx
.cls
= providedClass
;
410 ctx
.invName
= nullptr;
411 ctx
.func
= selectedFunc
;
413 return Variant::attach(
414 g_context
->invokeFunc(ctx
, params
)
418 Object
HHVM_FUNCTION(hphp_create_object
, const String
& name
,
419 const Variant
& params
) {
420 return Object::attach(g_context
->createObject(name
.get(), params
));
423 Object
HHVM_FUNCTION(hphp_create_object_without_constructor
,
424 const String
& name
) {
425 return Object::attach(
426 g_context
->createObject(name
.get(), init_null_variant
, false)
430 Variant
HHVM_FUNCTION(hphp_get_property
, const Object
& obj
, const String
& cls
,
431 const String
& prop
) {
432 /* It's possible to get a ReflectionProperty for a property which
433 * no longer exists. Silentyly fail to match PHP5 behavior
435 return obj
->o_get(prop
, false /* error */, cls
);
438 void HHVM_FUNCTION(hphp_set_property
, const Object
& obj
, const String
& cls
,
439 const String
& prop
, const Variant
& value
) {
440 if (!cls
.empty() && RuntimeOption::EvalAuthoritativeMode
) {
442 "We've already made many assumptions about private variables. "
443 "You can't change accessibility in Whole Program mode"
448 * This interface can be used to clear memo caches, but we don't want to allow
449 * setting the memo cache values to arbitrary values. HHBBC and the JIT make
450 * aggressive assumptions about the layout and values of the caches to improve
451 * performance. So, if the property being set is a memo cache, we'll allow
452 * resetting it to an empty value, but nothing else.
454 * Furthermore, existing PHP code assumes that the memo cache stores arrays,
455 * not dicts, so for backwards compatibility, we'll allow null or any empty
456 * array-like value to mean clear.
458 auto const isMultiMemo
= prop
.slice().endsWith("$multi$memoize_cache");
459 auto const isSingleMemo
= prop
.slice().endsWith("$single$memoize_cache");
460 auto const isGuardedSingleMemo
=
461 prop
.slice().endsWith("$guarded_single$memoize_cache");
463 prop
.slice().endsWith("$guarded_single$memoize_cache$guard");
466 // Allow setting the guard to false only. Clear out the associated cache at
468 auto const tv
= value
.asTypedValue();
469 if (tv
->m_type
!= KindOfBoolean
|| tv
->m_data
.num
) {
470 raise_error("Reflection can only reset memoize caches");
472 obj
->o_set(prop
, false_varNR
, cls
);
474 prop
.slice().subpiece(0, prop
.length() - 6),
481 if (isMultiMemo
|| isSingleMemo
|| isGuardedSingleMemo
) {
482 auto const tv
= value
.asTypedValue();
483 if (tv
->m_type
!= KindOfNull
&&
484 (!isArrayLikeType(tv
->m_type
) || tv
->m_data
.parr
->size() != 0)) {
485 raise_error("Reflection can only reset memoize caches");
487 // Reset to empty value. Depending on the type of the memo cache, this might
488 // be null or an empty dict.
492 cellAsCVarRef(make_tv
<KindOfPersistentDict
>(staticEmptyDictArray())),
495 } else if (isSingleMemo
|| isGuardedSingleMemo
) {
496 obj
->o_set(prop
, init_null_variant
, cls
);
497 if (isGuardedSingleMemo
) {
498 // If there's a guard, reset it to false as well.
499 obj
->o_set(folly::sformat("{}$guard", prop
), false_varNR
, cls
);
505 obj
->o_set(prop
, value
, cls
);
508 Variant
HHVM_FUNCTION(hphp_get_static_property
, const String
& cls
,
511 auto const sd
= cls
.get();
512 auto const class_
= Unit::lookupClass(sd
);
514 raise_error("Non-existent class %s", sd
->data());
518 auto const lookup
= class_
->getSProp(
519 force
? class_
: arGetContextClass(vmfp()),
523 raise_error("Class %s does not have a property named %s",
524 sd
->data(), prop
.get()->data());
526 if (!lookup
.accessible
) {
527 raise_error("Invalid access to class %s's property %s",
528 sd
->data(), prop
.get()->data());
530 return tvAsVariant(lookup
.prop
);
533 void HHVM_FUNCTION(hphp_set_static_property
, const String
& cls
,
535 const Variant
& value
,
537 if (RuntimeOption::EvalAuthoritativeMode
) {
538 raise_error("Setting static properties through reflection is not "
539 "allowed in RepoAuthoritative mode");
541 auto const sd
= cls
.get();
542 auto const class_
= Unit::lookupClass(sd
);
544 if (!class_
) raise_error("Non-existent class %s", sd
->data());
548 auto const lookup
= class_
->getSProp(
549 force
? class_
: arGetContextClass(vmfp()),
553 raise_error("Class %s does not have a property named %s",
554 cls
.get()->data(), prop
.get()->data());
556 if (!lookup
.accessible
) {
557 raise_error("Invalid access to class %s's property %s",
558 sd
->data(), prop
.get()->data());
562 * Like in hphp_set_property(), this interface can be used to clear memo
563 * caches, but we don't want to allow setting the memo cache values to
564 * arbitrary values. HHBBC and the JIT make aggressive assumptions about the
565 * layout and values of the caches to improve performance. So, if the property
566 * being set is a memo cache, we'll allow resetting it to an empty value, but
569 * Furthermore, existing PHP code assumes that the memo cache stores arrays,
570 * not dicts, so for backwards compatibility, we'll allow null or any empty
571 * array-like value to mean clear.
573 auto const isMultiMemo
= prop
.slice().endsWith("$multi$memoize_cache");
574 auto const isSingleMemo
= prop
.slice().endsWith("$single$memoize_cache");
575 auto const isGuardedSingleMemo
=
576 prop
.slice().endsWith("$guarded_single$memoize_cache");
578 prop
.slice().endsWith("$guarded_single$memoize_cache$guard");
581 // Allow setting the guard to false only. Clear out the associated cache at
583 auto const tv
= value
.asTypedValue();
584 if (tv
->m_type
!= KindOfBoolean
|| tv
->m_data
.num
) {
585 raise_error("Reflection can only reset memoize caches");
587 cellSet(make_tv
<KindOfBoolean
>(false), *lookup
.prop
);
589 auto const cacheLookup
= class_
->getSProp(
590 force
? class_
: arGetContextClass(vmfp()),
591 String
{prop
.slice().subpiece(0, prop
.length() - 6)}.get()
593 if (cacheLookup
.prop
) {
594 cellSet(make_tv
<KindOfNull
>(), *cacheLookup
.prop
);
599 if (isMultiMemo
|| isSingleMemo
|| isGuardedSingleMemo
) {
600 auto const tv
= value
.asTypedValue();
601 if (tv
->m_type
!= KindOfNull
&&
602 (!isArrayLikeType(tv
->m_type
) || tv
->m_data
.parr
->size() != 0)) {
603 raise_error("Reflection can only reset memoize caches");
605 // Reset to empty value. Depending on the type of the memo cache, this might
606 // be null or an empty dict.
609 make_tv
<KindOfPersistentDict
>(staticEmptyDictArray()),
612 } else if (isSingleMemo
|| isGuardedSingleMemo
) {
613 cellSet(make_tv
<KindOfNull
>(), *lookup
.prop
);
614 if (isGuardedSingleMemo
) {
615 // If there's a guard, reset it to false as well.
616 auto const guardLookup
= class_
->getSProp(
617 force
? class_
: arGetContextClass(vmfp()),
618 String
{folly::sformat("{}$guard", prop
)}.get()
620 if (guardLookup
.prop
) {
621 cellSet(make_tv
<KindOfBoolean
>(false), *guardLookup
.prop
);
628 tvAsVariant(lookup
.prop
) = value
;
632 * cls_or_obj: the name of a class or an instance of the class;
633 * cns_name: the name of the type constant of the class;
635 * If the type constant exists and is not abstract, this function
636 * returns the shape representing the type associated with the type
639 Array
HHVM_FUNCTION(type_structure
,
640 const Variant
& cls_or_obj
, const Variant
& cns_name
) {
641 auto const cns_sd
= cns_name
.getStringDataOrNull();
643 auto name
= cls_or_obj
.toString();
645 auto const typeAlias
= Unit::loadTypeAlias(name
.get());
648 raise_error("Non-existent type alias %s", name
.get()->data());
651 auto const typeStructure
= typeAlias
->typeStructure
;
652 assertx(!typeStructure
.empty());
653 assertx(typeStructure
.isDArray());
656 bool persistent
= true;
657 resolved
= TypeStructure::resolve(name
, typeStructure
, persistent
);
658 } catch (Exception
& e
) {
659 raise_error("resolving type alias %s failed. "
660 "Have you declared all classes in the type alias",
663 assertx(!resolved
.empty());
664 assertx(resolved
.isDArray());
668 auto const cls
= get_cls(cls_or_obj
);
671 raise_error("Non-existent class %s", cls_or_obj
.toString().get()->data());
674 auto const cls_sd
= cls
->name();
675 auto typeCns
= cls
->clsCnsGet(cns_sd
, true);
676 if (typeCns
.m_type
== KindOfUninit
) {
677 if (cls
->hasTypeConstant(cns_sd
, true)) {
678 raise_error("Type constant %s::%s is abstract",
679 cls_sd
->data(), cns_sd
->data());
681 raise_error("Non-existent type constant %s::%s",
682 cls_sd
->data(), cns_sd
->data());
686 assertx(isArrayType(typeCns
.m_type
));
687 assertx(typeCns
.m_data
.parr
->isDArray());
688 assertx(typeCns
.m_data
.parr
->isStatic());
689 return Array::attach(typeCns
.m_data
.parr
);
692 String
HHVM_FUNCTION(hphp_get_original_class_name
, const String
& name
) {
693 Class
* cls
= Unit::loadClass(name
.get());
694 if (!cls
) return empty_string();
695 return cls
->nameStr();
699 void Reflection::ThrowReflectionExceptionObject(const Variant
& message
) {
700 Object inst
{s_ReflectionExceptionClass
};
702 g_context
->invokeFunc(s_ReflectionExceptionClass
->getCtor(),
703 make_packed_array(message
),
710 /////////////////////////////////////////////////////////////////////////////
711 // class ReflectionFuncHandle
713 const StaticString
s_ReflectionFuncHandle("ReflectionFuncHandle");
715 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getFileName
) {
716 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
717 if (func
->isBuiltin()) {
720 auto file
= func
->unit()->filepath()->data();
721 if (!file
) { file
= ""; }
722 if (file
[0] != '/') {
723 return String(RuntimeOption::SourceRoot
+ file
);
729 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getStartLine
) {
730 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
731 if (func
->isBuiltin()) {
734 return func
->line1();
737 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getEndLine
) {
738 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
739 if (func
->isBuiltin()) {
742 return func
->line2();
745 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getDocComment
) {
746 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
747 auto const comment
= func
->docComment();
748 if (comment
== nullptr || comment
->empty()) {
750 } else if (func
->isBuiltin() && !HHVM_FUNCTION(hphp_debugger_attached
)) {
753 auto ret
= const_cast<StringData
*>(comment
);
759 static Array
get_function_static_variables(const Func
* func
) {
760 auto const& staticVars
= func
->staticVars();
762 auto size
= staticVars
.size();
763 ArrayInit
ai(size
, ArrayInit::Mixed
{});
765 for (size_t i
= 0; i
< staticVars
.size(); ++i
) {
766 const Func::SVInfo
&sv
= staticVars
[i
];
767 auto const staticLocalData
= rds::bindStaticLocal(func
, sv
.name
);
768 // FIXME: this should not require variant hops
771 staticLocalData
.isInit()
772 ? tvAsCVarRef(staticLocalData
.get()->ref
.tv())
779 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getStaticVariables
) {
780 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
781 return get_function_static_variables(func
);
784 static String
HHVM_METHOD(ReflectionFunctionAbstract
, getName
) {
785 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
786 auto ret
= const_cast<StringData
*>(func
->name());
790 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isHack
) {
791 if (RuntimeOption::EnableHipHopSyntax
) {
794 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
795 return func
->unit()->isHHFile();
798 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isInternal
) {
799 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
800 return func
->isBuiltin();
803 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isGenerator
) {
804 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
805 return func
->isGenerator();
808 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isAsync
) {
809 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
810 return func
->isAsync();
813 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isVariadic
) {
814 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
815 return func
->hasVariadicCaptureParam();
818 static bool HHVM_METHOD(ReflectionFunctionAbstract
, returnsReference
) {
819 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
820 return func
->attrs() & AttrReference
;
823 static int64_t HHVM_METHOD(ReflectionFunctionAbstract
, getNumberOfParameters
) {
824 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
825 return func
->numParams();
828 // If we are in <?php and in PHP 7 mode w.r.t. scalar types
829 ALWAYS_INLINE
static bool isPhpTypeHintEnabled(const Func
* func
) {
830 return (!(func
->unit()->isHHFile() || RuntimeOption::EnableHipHopSyntax
) &&
831 RuntimeOption::PHP7_ScalarTypes
836 static Array
get_function_param_info(const Func
* func
) {
837 const Func::ParamInfoVec
& params
= func
->params();
838 PackedArrayInit
ai(func
->numParams());
840 for (int i
= 0; i
< func
->numParams(); ++i
) {
841 Array param
= Array::Create();
842 const Func::ParamInfo
& fpi
= params
[i
];
844 param
.set(s_index
, make_tv
<KindOfInt64
>(i
));
845 param
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->localNames()[i
]));
847 auto const nonExtendedConstraint
=
848 fpi
.typeConstraint
.hasConstraint() &&
849 !fpi
.typeConstraint
.isExtended();
850 auto const type
= nonExtendedConstraint
851 ? fpi
.typeConstraint
.typeName()
852 : staticEmptyString();
854 param
.set(s_type
, make_tv
<KindOfPersistentString
>(type
));
855 const StringData
* typeHint
= fpi
.userType
857 : staticEmptyString();
858 param
.set(s_type_hint
, make_tv
<KindOfPersistentString
>(typeHint
));
860 std::string
phpTypeHint(isPhpTypeHintEnabled(func
) ? typeHint
->toCppString() : "");
862 if (!phpTypeHint
.empty() && phpTypeHint
[0] == '?') {
863 phpTypeHint
= phpTypeHint
.substr(1);
864 param
.set(s_type_hint
, phpTypeHint
);
867 // callable typehint considered builtin; stdclass typehint is not
869 fpi
.typeConstraint
.isCallable() ||
870 (fpi
.typeConstraint
.underlyingDataType() &&
871 fpi
.typeConstraint
.underlyingDataType() != KindOfObject
874 param
.set(s_type_hint_builtin
, true_varNR
.tv());
875 // If we are in <?php and in PHP 7 mode w.r.t. scalar types, then we want
876 // the types to come back as PHP 7 style scalar types, not HH\ style
878 if (!phpTypeHint
.empty() && boost::starts_with(phpTypeHint
, "HH\\")) {
879 phpTypeHint
= phpTypeHint
.substr(3);
880 param
.set(s_type_hint
, phpTypeHint
);
883 param
.set(s_type_hint_builtin
, false_varNR
.tv());
885 param
.set(s_function
, make_tv
<KindOfPersistentString
>(func
->name()));
886 if (func
->preClass()) {
889 make_tv
<KindOfPersistentString
>(
890 func
->implCls() ? func
->implCls()->name()
891 : func
->preClass()->name()
895 if (!nonExtendedConstraint
|| fpi
.typeConstraint
.isNullable()) {
896 param
.set(s_nullable
, true_varNR
.tv());
897 param
.set(s_type_hint_nullable
, true_varNR
.tv());
899 param
.set(s_type_hint_nullable
, false_varNR
.tv());
903 Variant v
= default_arg_from_php_code(fpi
, func
);
904 param
.set(s_default
, v
);
905 param
.set(s_defaultText
, make_tv
<KindOfPersistentString
>(fpi
.phpCode
));
908 if (func
->byRef(i
)) {
909 param
.set(s_ref
, true_varNR
.tv());
911 if (fpi
.isVariadic()) {
912 param
.set(s_is_variadic
, true_varNR
.tv());
915 Array userAttrs
= Array::Create();
916 for (auto it
= fpi
.userAttributes
.begin();
917 it
!= fpi
.userAttributes
.end(); ++it
) {
918 userAttrs
.set(StrNR(it
->first
), it
->second
);
920 param
.set(s_attributes
, VarNR(userAttrs
).tv());
922 ai
.append(VarNR(param
).tv());
925 auto arr
= ai
.toArray();
927 bool isOptional
= true;
928 for (int i
= func
->numParams() - 1; i
>= 0; i
--) {
929 auto& param
= asArrRef(arr
.lvalAt(i
));
931 isOptional
= isOptional
&& (param
.exists(s_default
) ||
932 param
.exists(s_is_variadic
));
933 param
.set(s_is_optional
, isOptional
);
938 // helper for getParameters
939 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getParamInfo
) {
940 // FIXME: each parameter info should be HNI with a handle to the
942 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
943 return get_function_param_info(func
);
946 // helper for getReturnTypeText
947 static String
HHVM_METHOD(ReflectionFunctionAbstract
, getReturnTypeHint
) {
948 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
949 auto retTypeSD
= func
->returnUserType();
950 if (retTypeSD
&& retTypeSD
->size()) {
951 auto ret
= const_cast<StringData
*>(retTypeSD
);
957 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getRetTypeInfo
) {
958 Array retTypeInfo
= Array::Create();
959 auto name
= HHVM_MN(ReflectionFunctionAbstract
, getReturnTypeHint
)(this_
);
960 if (name
&& !name
.empty()) {
961 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
962 auto retType
= func
->returnTypeConstraint();
963 if (retType
.isNullable()) {
964 retTypeInfo
.set(s_type_hint_nullable
, true_varNR
.tv());
965 if (isPhpTypeHintEnabled(func
)) {
966 name
= name
.substr(1); //removes '?' - e.g. ?int -> int
969 retTypeInfo
.set(s_type_hint_nullable
, false_varNR
.tv());
973 retType
.isCallable() || // callable type hint is considered builtin
974 (retType
.underlyingDataType() &&
975 retType
.underlyingDataType() != KindOfObject
978 retTypeInfo
.set(s_type_hint_builtin
, true_varNR
.tv());
979 // If we are in <?php and in PHP 7 mode w.r.t. scalar types, then we want
980 // the types to come back as PHP 7 style scalar types, not HH\ style
982 if (isPhpTypeHintEnabled(func
) && boost::starts_with(name
.toCppString(), "HH\\")) {
983 name
= name
.substr(3);
986 retTypeInfo
.set(s_type_hint_builtin
, false_varNR
.tv());
989 name
= staticEmptyString();
990 retTypeInfo
.set(s_type_hint_nullable
, false_varNR
.tv());
991 retTypeInfo
.set(s_type_hint_builtin
, false_varNR
.tv());
993 retTypeInfo
.set(s_type_hint
, name
);
998 static Array
get_function_user_attributes(const Func
* func
) {
999 auto userAttrs
= func
->userAttributes();
1001 ArrayInit
ai(userAttrs
.size(), ArrayInit::Mixed
{});
1002 for (auto it
= userAttrs
.begin(); it
!= userAttrs
.end(); ++it
) {
1003 ai
.set(VarNR::MakeKey(StrNR(it
->first
).asString()).tv(), it
->second
);
1005 return ai
.toArray();
1008 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getAttributes
) {
1009 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1010 return get_function_user_attributes(func
);
1013 // ------------------------- class ReflectionMethod
1015 // helper for __construct
1016 static bool HHVM_METHOD(ReflectionMethod
, __init
,
1017 const Variant
& cls_or_object
, const String
& meth_name
) {
1018 auto const cls
= get_cls(cls_or_object
);
1019 if (!cls
|| meth_name
.isNull()) {
1020 // caller raises exception
1023 auto const func
= get_method_func(cls
, meth_name
);
1025 // caller raises exception
1028 assert(func
->isMethod());
1029 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
1033 static bool HHVM_METHOD(ReflectionMethod
, isFinal
) {
1034 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1035 return func
->attrs() & AttrFinal
;
1038 static bool HHVM_METHOD(ReflectionMethod
, isAbstract
) {
1039 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1040 return func
->attrs() & AttrAbstract
;
1043 static bool HHVM_METHOD(ReflectionMethod
, isPublic
) {
1044 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1045 return func
->attrs() & AttrPublic
;
1048 static bool HHVM_METHOD(ReflectionMethod
, isProtected
) {
1049 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1050 return func
->attrs() & AttrProtected
;
1053 static bool HHVM_METHOD(ReflectionMethod
, isPrivate
) {
1054 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1055 return func
->attrs() & AttrPrivate
;
1058 static bool HHVM_METHOD(ReflectionMethod
, isStatic
) {
1059 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1060 return func
->attrs() & AttrStatic
;
1063 static bool HHVM_METHOD(ReflectionMethod
, isConstructor
) {
1064 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1065 return isConstructor(func
);
1068 static int HHVM_METHOD(ReflectionMethod
, getModifiers
) {
1069 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1070 return get_modifiers(func
->attrs(), false);
1073 // private helper for getPrototype
1074 static String
HHVM_METHOD(ReflectionMethod
, getPrototypeClassname
) {
1075 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1076 const Class
*prototypeCls
= nullptr;
1077 if (func
->baseCls() != nullptr && func
->baseCls() != func
->implCls()) {
1078 prototypeCls
= func
->baseCls();
1079 const Class
*result
= get_prototype_class_from_interfaces(
1080 prototypeCls
, func
);
1081 if (result
) { prototypeCls
= result
; }
1082 } else if (func
->isMethod()) {
1083 // lookup the prototype in the interfaces
1084 prototypeCls
= get_prototype_class_from_interfaces(func
->implCls(), func
);
1087 auto ret
= const_cast<StringData
*>(prototypeCls
->name());
1093 // private helper for getDeclaringClass
1094 static String
HHVM_METHOD(ReflectionMethod
, getDeclaringClassname
) {
1095 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1096 auto ret
= const_cast<StringData
*>(func
->implCls()->name());
1100 // ------------------------- class ReflectionFunction
1102 // helper for __construct
1103 static bool HHVM_METHOD(ReflectionFunction
, __initName
, const String
& name
) {
1104 if (name
.isNull()) { return false; }
1105 const Func
* func
= Unit::loadFunc(name
.get());
1106 if (!func
) { return false; }
1107 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
1111 // helper for __construct
1112 static bool HHVM_METHOD(ReflectionFunction
, __initClosure
,
1113 const Object
& closure
) {
1114 auto const cls
= get_cls(closure
);
1116 if (!cls
) { return false; }
1117 const Func
* func
= cls
->lookupMethod(s___invoke
.get());
1119 // caller raises exception
1122 assert(func
->isClosureBody());
1123 assert(func
->implCls()->isScopedClosure());
1124 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
1128 const StaticString
s_ExpectedClosureInstance("Expected closure instance");
1130 // helper for getClosureScopeClass
1131 static Variant
HHVM_METHOD(ReflectionFunction
, getClosureScopeClassname
,
1132 const Object
& closure
) {
1133 if (!closure
->instanceof(c_Closure::classof())) {
1134 SystemLib::throwExceptionObject(s_ExpectedClosureInstance
);
1136 if (auto scope
= c_Closure::fromObject(closure
.get())->getScope()) {
1137 return String(const_cast<StringData
*>(scope
->name()));
1139 return init_null_variant
;
1142 static Variant
HHVM_METHOD(ReflectionFunction
, getClosureThisObject
,
1143 const Object
& closure
) {
1144 if (!closure
->instanceof(c_Closure::classof())) {
1145 SystemLib::throwExceptionObject(s_ExpectedClosureInstance
);
1147 auto const clos
= c_Closure::fromObject(closure
.get());
1148 if (clos
->hasThis()) {
1149 return Object
{clos
->getThis()};
1151 return init_null_variant
;
1154 // helper for getStaticVariables
1155 static Array
HHVM_METHOD(ReflectionFunction
, getClosureUseVariables
,
1156 const Object
& closure
) {
1157 auto const cls
= get_cls(closure
);
1159 MixedArrayInit
ai(cls
->numDeclProperties());
1160 auto propVal
= closure
->propVec();
1161 for (auto const& prop
: cls
->declProperties()) {
1162 // Closure static locals are represented as special instance properties
1163 // with a mangled name.
1164 if (prop
.name
->data()[0] == '8') {
1165 static const char prefix
[] = "86static_";
1166 assert(0 == strncmp(prop
.name
->data(), prefix
, sizeof prefix
- 1));
1167 String
strippedName(prop
.name
->data() + sizeof prefix
- 1,
1168 prop
.name
->size() - sizeof prefix
+ 1,
1170 ai
.setUnknownKey(VarNR(strippedName
), tvAsCVarRef(propVal
));
1172 ai
.setWithRef(StrNR(prop
.name
), *propVal
);
1176 return ai
.toArray();
1179 /////////////////////////////////////////////////////////////////////////////
1180 // class ReflectionClass
1182 const StaticString
s_ReflectionClassHandle("ReflectionClassHandle");
1184 // helper for __construct
1185 static String
HHVM_METHOD(ReflectionClass
, __init
, const String
& name
) {
1186 return ReflectionClassHandle::Get(this_
)->init(name
);
1189 static String
HHVM_METHOD(ReflectionClass
, getName
) {
1190 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1191 return cls
->nameStr();
1194 static String
HHVM_METHOD(ReflectionClass
, getParentName
) {
1195 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1196 return cls
->parentStr();
1199 static bool HHVM_METHOD(ReflectionClass
, isHack
) {
1200 if (RuntimeOption::EnableHipHopSyntax
) {
1203 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1204 return cls
->preClass()->unit()->isHHFile();
1207 static bool HHVM_METHOD(ReflectionClass
, isInternal
) {
1208 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1209 return cls
->attrs() & AttrBuiltin
;
1212 static bool HHVM_METHOD(ReflectionClass
, isInstantiable
) {
1213 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1214 return !(cls
->attrs() & (AttrAbstract
| AttrInterface
| AttrTrait
| AttrEnum
))
1215 && (cls
->getCtor()->attrs() & AttrPublic
);
1218 static bool HHVM_METHOD(ReflectionClass
, isFinal
) {
1219 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1220 return cls
->attrs() & AttrFinal
;
1223 static bool HHVM_METHOD(ReflectionClass
, isAbstract
) {
1224 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1225 return cls
->attrs() & AttrAbstract
;
1228 static bool HHVM_METHOD(ReflectionClass
, isInterface
) {
1229 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1230 return cls
->attrs() & AttrInterface
;
1233 static bool HHVM_METHOD(ReflectionClass
, isTrait
) {
1234 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1235 return cls
->attrs() & AttrTrait
;
1238 static bool HHVM_METHOD(ReflectionClass
, isEnum
) {
1239 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1240 return cls
->attrs() & AttrEnum
;
1243 static int HHVM_METHOD(ReflectionClass
, getModifiers
) {
1244 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1245 return get_modifiers(cls
->attrs(), true);
1248 static Variant
HHVM_METHOD(ReflectionClass
, getFileName
) {
1249 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1250 if (cls
->attrs() & AttrBuiltin
) {
1253 auto file
= cls
->preClass()->unit()->filepath()->data();
1254 if (!file
) { file
= ""; }
1255 if (file
[0] != '/') {
1256 return String(RuntimeOption::SourceRoot
+ file
);
1258 return String(file
);
1262 static Variant
HHVM_METHOD(ReflectionClass
, getStartLine
) {
1263 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1264 if (cls
->isBuiltin()) {
1267 return cls
->preClass()->line1();
1270 static Variant
HHVM_METHOD(ReflectionClass
, getEndLine
) {
1271 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1272 if (cls
->isBuiltin()) {
1275 return cls
->preClass()->line2();
1278 static Variant
HHVM_METHOD(ReflectionClass
, getDocComment
) {
1279 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1280 auto const pcls
= cls
->preClass();
1281 auto const comment
= pcls
->docComment();
1282 if (comment
== nullptr || comment
->empty()) {
1284 } else if (pcls
->isBuiltin() && !HHVM_FUNCTION(hphp_debugger_attached
)) {
1287 auto ret
= const_cast<StringData
*>(comment
);
1292 static Array
HHVM_METHOD(ReflectionClass
, getRequirementNames
) {
1293 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1294 if (!(cls
->attrs() & (AttrTrait
| AttrInterface
))) {
1295 // requirements are applied to abstract/concrete classes when they use
1296 // a trait / implement an interface
1297 return empty_array();
1300 auto const& requirements
= cls
->allRequirements();
1301 auto numReqs
= requirements
.size();
1303 return empty_array();
1306 PackedArrayInit
pai(numReqs
);
1307 for (int i
= 0; i
< numReqs
; ++i
) {
1308 auto const& req
= requirements
[i
];
1309 pai
.append(Variant
{const_cast<StringData
*>(req
->name())});
1311 return pai
.toArray();
1314 static Array
HHVM_METHOD(ReflectionClass
, getInterfaceNames
) {
1315 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1317 auto st
= req::make
<c_Set
>();
1318 auto const& allIfaces
= cls
->allInterfaces();
1319 st
->reserve(allIfaces
.size());
1321 for (auto const& interface
: cls
->declInterfaces()) {
1322 st
->add(const_cast<StringData
*>(interface
->name()));
1324 if (allIfaces
.size() > cls
->declInterfaces().size()) {
1325 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1326 auto const& interface
= allIfaces
[i
];
1327 st
->add(const_cast<StringData
*>(interface
->name()));
1331 PackedArrayInit
ai(st
->size());
1332 for (ArrayIter
iter(st
.get()); iter
; ++iter
) {
1333 ai
.append(iter
.secondValPlus());
1335 return ai
.toArray();
1338 static Array
HHVM_METHOD(ReflectionClass
, getTraitNames
) {
1339 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1340 auto const& traits
= cls
->preClass()->usedTraits();
1341 PackedArrayInit
ai(traits
.size());
1342 for (const StringData
* traitName
: traits
) {
1343 ai
.append(Variant
{const_cast<StringData
*>(traitName
)});
1345 return ai
.toArray();
1348 static Array
get_trait_alias_info(const Class
* cls
) {
1349 auto const& aliases
= cls
->traitAliases();
1351 if (aliases
.size()) {
1352 ArrayInit
ai(aliases
.size(), ArrayInit::Map
{});
1354 for (auto const& namePair
: aliases
) {
1355 ai
.set(StrNR(namePair
.first
), VarNR(namePair
.second
).tv());
1357 return ai
.toArray();
1359 // Even if we have alias rules, if we're in repo mode, they will be applied
1360 // during the trait flattening step, and we won't populate traitAliases()
1362 auto const& rules
= cls
->preClass()->traitAliasRules();
1364 ArrayInit
ai(rules
.size(), ArrayInit::Map
{});
1366 for (auto const& rule
: rules
) {
1367 auto namePair
= rule
.asNamePair();
1368 ai
.set(StrNR(namePair
.first
), VarNR(namePair
.second
).tv());
1370 return ai
.toArray();
1374 static Array
HHVM_METHOD(ReflectionClass
, getTraitAliases
) {
1375 return get_trait_alias_info(ReflectionClassHandle::GetClassFor(this_
));
1378 static bool HHVM_METHOD(ReflectionClass
, hasMethod
, const String
& name
) {
1379 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1380 return (get_method_func(cls
, name
) != nullptr);
1383 // helper for getMethods: returns a Set
1384 static Object
HHVM_METHOD(ReflectionClass
, getMethodOrder
, int64_t filter
) {
1385 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1386 Attr mask
= attrs_from_modifiers(filter
, false);
1388 // At each step, we fetch from the PreClass is important because the
1389 // order in which getMethods returns matters
1390 req::StringISet visitedMethods
;
1391 auto st
= req::make
<c_Set
>();
1392 st
->reserve(cls
->numMethods());
1394 auto add
= [&] (const Func
* m
) {
1395 if (m
->isGenerated()) return;
1396 if (visitedMethods
.count(m
->nameStr())) return;
1398 visitedMethods
.insert(m
->nameStr());
1399 if (m
->attrs() & mask
) {
1400 st
->add(HHVM_FN(strtolower
)(m
->nameStr()).get());
1404 std::function
<void(const Class
*)> collect
;
1405 std::function
<void(const Class
*)> collectInterface
;
1407 collect
= [&] (const Class
* clas
) {
1410 auto const methods
= clas
->preClass()->methods();
1411 auto const numMethods
= clas
->preClass()->numMethods();
1413 auto numDeclMethods
= clas
->preClass()->numDeclMethods();
1414 if (numDeclMethods
== -1) numDeclMethods
= numMethods
;
1416 // Add declared methods.
1417 for (Slot i
= 0; i
< numDeclMethods
; ++i
) {
1421 // Recurse; we need to order the parent's methods before our trait methods.
1422 collect(clas
->parent());
1424 for (Slot i
= numDeclMethods
; i
< numMethods
; ++i
) {
1425 // For repo mode, where trait methods are flattened at compile-time.
1428 for (Slot i
= clas
->traitsBeginIdx(); i
< clas
->traitsEndIdx(); ++i
) {
1429 // For non-repo mode, where they are added at Class-creation time.
1430 add(clas
->getMethod(i
));
1434 collectInterface
= [&] (const Class
* iface
) {
1437 size_t const numMethods
= iface
->preClass()->numMethods();
1438 Func
* const* methods
= iface
->preClass()->methods();
1439 for (Slot i
= 0; i
< numMethods
; ++i
) {
1443 for (auto const& parentIface
: iface
->declInterfaces()) {
1444 collectInterface(parentIface
.get());
1446 auto const& allIfaces
= iface
->allInterfaces();
1447 if (allIfaces
.size() > iface
->declInterfaces().size()) {
1448 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1449 collectInterface(allIfaces
[i
].get());
1454 collect(const_cast<Class
*>(cls
));
1456 // concrete classes should already have all of their methods present
1457 if (((AttrPublic
| AttrAbstract
| AttrStatic
) & mask
) &&
1458 cls
->attrs() & (AttrInterface
| AttrAbstract
| AttrTrait
)) {
1459 for (auto const& interface
: cls
->declInterfaces()) {
1460 collectInterface(interface
.get());
1462 auto const& allIfaces
= cls
->allInterfaces();
1463 if (allIfaces
.size() > cls
->declInterfaces().size()) {
1464 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1465 auto const& interface
= allIfaces
[i
];
1466 collectInterface(interface
.get());
1470 return Object(std::move(st
));
1473 static bool HHVM_METHOD(ReflectionClass
, hasConstant
, const String
& name
) {
1474 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1475 return cls
->hasConstant(name
.get());
1478 static Variant
HHVM_METHOD(ReflectionClass
, getConstant
, const String
& name
) {
1479 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1480 auto value
= cls
->clsCnsGet(name
.get());
1481 return (value
.m_type
== KindOfUninit
) ? false_varNR
: cellAsCVarRef(value
);
1485 void addClassConstantNames(const Class
* cls
,
1486 const req::ptr
<c_Set
>& st
,
1488 assert(cls
&& st
&& (st
->size() < limit
));
1490 auto numConsts
= cls
->numConstants();
1492 const Class::Const
* consts
= cls
->constants();
1493 for (size_t i
= 0; i
< numConsts
; i
++) {
1494 if (consts
[i
].cls
== cls
&& !consts
[i
].isAbstract() &&
1495 !consts
[i
].isType()) {
1496 st
->add(const_cast<StringData
*>(consts
[i
].name
.get()));
1499 if ((st
->size() < limit
) && cls
->parent()) {
1500 addClassConstantNames(cls
->parent(), st
, limit
);
1503 auto const& allIfaces
= cls
->allInterfaces();
1504 auto const numIfaces
= allIfaces
.size();
1505 for (int i
= 0; i
< numIfaces
&& (st
->size() < limit
); ++i
) {
1506 addClassConstantNames(allIfaces
[i
].get(), st
, limit
);
1510 // helper for getConstants
1511 static Array
HHVM_METHOD(ReflectionClass
, getOrderedConstants
) {
1512 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1514 size_t numConsts
= cls
->numConstants();
1516 return Array::Create();
1519 auto st
= req::make
<c_Set
>();
1520 st
->reserve(numConsts
);
1522 addClassConstantNames(cls
, st
, numConsts
);
1523 assert(st
->size() <= numConsts
);
1525 ArrayInit
ai(numConsts
, ArrayInit::Mixed
{});
1526 for (ArrayIter
iter(st
.get()); iter
; ++iter
) {
1527 auto constName
= iter
.first().getStringData();
1528 Cell value
= cls
->clsCnsGet(constName
);
1529 assert(value
.m_type
!= KindOfUninit
);
1530 ai
.add(constName
, cellAsCVarRef(value
));
1532 return ai
.toArray();
1535 // helper for getAbstractConstantNames
1536 static Array
HHVM_METHOD(ReflectionClass
, getOrderedAbstractConstants
) {
1537 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1539 size_t numConsts
= cls
->numConstants();
1541 return Array::Create();
1544 auto st
= req::make
<c_Set
>();
1545 st
->reserve(numConsts
);
1547 const Class::Const
* consts
= cls
->constants();
1548 for (size_t i
= 0; i
< numConsts
; i
++) {
1549 if (consts
[i
].isAbstract() && !consts
[i
].isType()) {
1550 st
->add(const_cast<StringData
*>(consts
[i
].name
.get()));
1554 assert(st
->size() <= numConsts
);
1555 return st
->toArray();
1560 // helper for getTypeConstants/hasTypeConstant
1561 static Array
HHVM_METHOD(ReflectionClass
, getOrderedTypeConstants
) {
1562 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1564 size_t numConsts
= cls
->numConstants();
1566 return Array::Create();
1569 auto st
= req::make
<c_Set
>();
1570 st
->reserve(numConsts
);
1572 const Class::Const
* consts
= cls
->constants();
1573 for (size_t i
= 0; i
< numConsts
; i
++) {
1574 if (consts
[i
].isType()) {
1575 st
->add(const_cast<StringData
*>(consts
[i
].name
.get()));
1579 assert(st
->size() <= numConsts
);
1580 return st
->toArray();
1583 static Array
HHVM_METHOD(ReflectionClass
, getAttributes
) {
1584 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1585 // UserAttributes are stored exclusively on the PreClass.
1586 auto const pcls
= cls
->preClass();
1588 auto userAttrs
= pcls
->userAttributes();
1589 ArrayInit
ai(userAttrs
.size(), ArrayInit::Mixed
{});
1591 for (auto it
= userAttrs
.begin(); it
!= userAttrs
.end(); ++it
) {
1592 ai
.set(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
1594 return ai
.toArray();
1597 static Array
HHVM_METHOD(ReflectionClass
, getAttributesRecursive
) {
1598 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1600 Array ret
= Array::Create(); // no reasonable idea about sizing
1602 // UserAttributes are stored in the PreClass, so we must walk the parent
1603 // chain to get all of them; attribute specifications from child classes
1604 // win over parents.
1606 // const pointer to Class => pointer to a (const) Class
1607 Class
* currentCls
= const_cast<Class
*>(cls
);
1609 auto const pcls
= currentCls
->preClass();
1610 for (auto it
= pcls
->userAttributes().begin();
1611 it
!= pcls
->userAttributes().end(); ++it
) {
1612 if (!ret
.exists(StrNR(it
->first
))) {
1613 ret
.add(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
1616 } while ((currentCls
= currentCls
->parent()));
1621 static Array
HHVM_METHOD(ReflectionClass
, getClassPropertyInfo
) {
1623 * FIXME: This implementation is pretty horrible and should be rewritten
1624 * when ReflectionProperty is ported.
1626 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1628 auto arrProp
= Array::Create();
1629 auto arrPriv
= Array::Create();
1630 auto arrIdx
= Array::Create();
1631 auto arrPrivIdx
= Array::Create();
1633 auto const properties
= cls
->declProperties();
1636 auto const& propInitVec
= cls
->getPropData()
1637 ? *cls
->getPropData()
1638 : cls
->declPropInit();
1640 auto const nProps
= cls
->numDeclProperties();
1642 for (Slot i
= 0; i
< nProps
; ++i
) {
1643 auto const& prop
= properties
[i
];
1644 auto const& default_val
= tvAsCVarRef(&propInitVec
[i
]);
1645 auto info
= Array::Create();
1646 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
1647 if (prop
.cls
== cls
) {
1648 set_instance_prop_info(info
, &prop
, default_val
);
1649 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
1650 arrPrivIdx
.set(StrNR(prop
.name
), prop
.idx
);
1654 set_instance_prop_info(info
, &prop
, default_val
);
1655 arrProp
.set(StrNR(prop
.name
), VarNR(info
).tv());
1656 arrIdx
.set(StrNR(prop
.name
), prop
.idx
);
1659 for (auto const& prop
: cls
->staticProperties()) {
1660 auto info
= Array::Create();
1661 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
1662 if (prop
.cls
== cls
) {
1663 set_static_prop_info(info
, &prop
);
1664 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
1665 arrPrivIdx
.set(StrNR(prop
.name
), prop
.idx
);
1669 set_static_prop_info(info
, &prop
);
1670 arrProp
.set(StrNR(prop
.name
), VarNR(info
).tv());
1671 arrIdx
.set(StrNR(prop
.name
), prop
.idx
);
1674 ArrayInit
ret(4, ArrayInit::Mixed
{});
1675 ret
.set(s_properties
, VarNR(arrProp
).tv());
1676 ret
.set(s_private_properties
, VarNR(arrPriv
).tv());
1677 ret
.set(s_properties_index
, VarNR(arrIdx
).tv());
1678 ret
.set(s_private_properties_index
, VarNR(arrPrivIdx
).tv());
1679 return ret
.toArray();
1682 static Array
HHVM_METHOD(ReflectionClass
, getDynamicPropertyInfos
,
1683 const Object
& obj
) {
1684 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1685 auto obj_data
= obj
.get();
1686 assert(obj_data
->getVMClass() == cls
);
1687 if (!obj_data
->hasDynProps()) {
1688 return empty_array();
1691 auto const dynPropArray
= obj_data
->dynPropArray().get();
1692 ArrayInit
ret(dynPropArray
->size(), ArrayInit::Mixed
{});
1693 for (ArrayIter
it(dynPropArray
); !it
.end(); it
.next()) {
1694 Array info
= Array::Create();
1695 set_dyn_prop_info(info
, it
.first(), cls
->name());
1696 ret
.setValidKey(*it
.first().asTypedValue(), VarNR(info
).tv());
1698 return ret
.toArray();
1701 static String
HHVM_METHOD(ReflectionClass
, getConstructorName
) {
1702 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1703 auto ctor
= cls
->getDeclaredCtor();
1704 if (!ctor
) { return String(); }
1705 auto ret
= const_cast<StringData
*>(ctor
->name());
1709 void ReflectionClassHandle::wakeup(const Variant
& content
, ObjectData
* obj
) {
1710 if (!content
.isString()) {
1711 throw Exception("Native data of ReflectionClass should be a class name");
1714 String clsName
= content
.toString();
1715 String result
= init(clsName
);
1716 if (result
.empty()) {
1717 auto msg
= folly::format("Class {} does not exist", clsName
).str();
1718 Reflection::ThrowReflectionExceptionObject(String(msg
));
1721 // It is possible that $name does not get serialized. If a class derives
1722 // from ReflectionClass and the return value of its __sleep() function does
1723 // not contain 'name', $name gets ignored. So, we restore $name here.
1724 obj
->setProp(nullptr, s_name
.get(), make_tv
<KindOfString
>(result
.get()));
1727 static Variant
reflection_extension_name_get(const Object
& this_
) {
1728 assertx(Reflection::s_ReflectionExtensionClass
);
1729 auto const name
= this_
->getProp(
1730 Reflection::s_ReflectionExtensionClass
,
1733 return tvCastToString(name
.tv());
1736 static Native::PropAccessor reflection_extension_Accessors
[] = {
1737 {"name", reflection_extension_name_get
,
1738 nullptr, nullptr, nullptr}, // name is read only
1739 {nullptr, nullptr, nullptr, nullptr, nullptr}
1742 static Native::PropAccessorMap reflection_extension_accessorsMap
1743 ((Native::PropAccessor
*)reflection_extension_Accessors
);
1745 struct reflection_extension_PropHandler
:
1746 Native::MapPropHandler
<reflection_extension_PropHandler
> {
1748 static constexpr Native::PropAccessorMap
& map
=
1749 reflection_extension_accessorsMap
;
1752 /////////////////////////////////////////////////////////////////////////////
1753 // class ReflectionTypeConstant
1755 const StaticString
s_ReflectionConstHandle("ReflectionConstHandle");
1757 // helper for __construct
1758 static bool HHVM_METHOD(ReflectionTypeConstant
, __init
,
1759 const Variant
& cls_or_obj
, const String
& const_name
) {
1760 auto const cls
= get_cls(cls_or_obj
);
1761 if (!cls
|| const_name
.isNull()) {
1762 // caller raises exception
1766 size_t numConsts
= cls
->numConstants();
1767 const Class::Const
* consts
= cls
->constants();
1769 for (size_t i
= 0; i
< numConsts
; i
++) {
1770 if (const_name
.same(consts
[i
].name
) && consts
[i
].isType()) {
1771 auto handle
= ReflectionConstHandle::Get(this_
);
1772 handle
->setConst(&consts
[i
]);
1773 handle
->setClass(cls
);
1778 // caller raises exception
1782 static String
HHVM_METHOD(ReflectionTypeConstant
, getName
) {
1783 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1784 auto ret
= const_cast<StringData
*>(cns
->name
.get());
1788 static bool HHVM_METHOD(ReflectionTypeConstant
, isAbstract
) {
1789 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1790 return cns
->isAbstract();
1793 // helper for getAssignedTypeText
1794 static String
HHVM_METHOD(ReflectionTypeConstant
, getAssignedTypeHint
) {
1795 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1797 if (isStringType(cns
->val
.m_type
)) {
1798 return String(cns
->val
.m_data
.pstr
);
1801 if (isArrayLikeType(cns
->val
.m_type
)) {
1802 auto const cls
= cns
->cls
;
1803 // go to the preclass to find the unresolved TypeStructure to get
1804 // the original assigned type text
1805 auto const preCls
= cls
->preClass();
1806 auto typeCns
= preCls
->lookupConstant(cns
->name
);
1807 assert(typeCns
->isType());
1808 assert(!typeCns
->isAbstract());
1809 assert(isArrayLikeType(typeCns
->val().m_type
));
1810 return TypeStructure::toString(Array::attach(typeCns
->val().m_data
.parr
));
1816 // private helper for getDeclaringClass
1817 static String
HHVM_METHOD(ReflectionTypeConstant
, getDeclaringClassname
) {
1818 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1819 auto cls
= cns
->cls
;
1820 auto ret
= const_cast<StringData
*>(cls
->name());
1824 // private helper for getClass
1825 static String
HHVM_METHOD(ReflectionTypeConstant
, getClassname
) {
1826 auto const cls
= ReflectionConstHandle::GetClassFor(this_
);
1827 auto ret
= const_cast<StringData
*>(cls
->name());
1831 /////////////////////////////////////////////////////////////////////////////
1832 // class ReflectionProperty
1834 const StaticString
s_ReflectionPropHandle("ReflectionPropHandle");
1835 const StaticString
s_ReflectionSPropHandle("ReflectionSPropHandle");
1837 // helper for __construct:
1838 // returns -1 if class not defined;
1839 // returns -2 if class::property not found (then caller raises exception);
1840 // returns the info array for ReflectionProperty if successfully initialized.
1841 static Variant
HHVM_METHOD(ReflectionProperty
, __init
,
1842 const Variant
& cls_or_obj
, const String
& prop_name
) {
1843 auto const cls
= get_cls(cls_or_obj
);
1845 // caller raises exception
1848 if (prop_name
.isNull()) {
1853 auto const& propInitVec
= cls
->getPropData()
1854 ? *cls
->getPropData()
1855 : cls
->declPropInit();
1857 auto const nProps
= cls
->numDeclProperties();
1858 auto const properties
= cls
->declProperties();
1860 // index for the candidate property
1862 const Class::Prop
* cProp
= nullptr;
1864 for (Slot i
= 0; i
< nProps
; i
++) {
1865 auto const& prop
= properties
[i
];
1866 if (prop_name
.same(prop
.name
)) {
1867 if (cls
== prop
.cls
.get()) {
1868 // found match for the exact child class
1872 } else if (!(prop
.attrs
& AttrPrivate
)) {
1873 // only inherit non-private properties
1880 if (cProp
!= nullptr) {
1881 ReflectionPropHandle::Get(this_
)->setProp(cProp
);
1882 auto info
= Array::Create();
1883 auto const& default_val
= tvAsCVarRef(&propInitVec
[cInd
]);
1884 set_instance_prop_info(info
, cProp
, default_val
);
1885 return Variant(info
);
1888 // for static property
1889 const Class::SProp
* cSProp
= nullptr;
1891 for (auto const& sprop
: cls
->staticProperties()) {
1892 if (prop_name
.same(sprop
.name
)) {
1893 if (cls
== sprop
.cls
.get()) {
1896 } else if (!(sprop
.attrs
& AttrPrivate
)) {
1901 if (cSProp
!= nullptr) {
1902 ReflectionSPropHandle::Get(this_
)->setSProp(cSProp
);
1903 auto info
= Array::Create();
1904 set_static_prop_info(info
, cSProp
);
1905 return Variant(info
);
1908 // check for dynamic properties
1909 if (cls_or_obj
.is(KindOfObject
)) {
1910 auto obj
= cls_or_obj
.toCObjRef().get();
1911 assert(cls
== obj
->getVMClass());
1912 if (obj
->hasDynProps()) {
1913 auto const dynPropArray
= obj
->dynPropArray().get();
1914 for (ArrayIter
it(dynPropArray
); !it
.end(); it
.next()) {
1915 if (prop_name
.same(it
.first().getStringData())) {
1916 auto info
= Array::Create();
1917 set_dyn_prop_info(info
, it
.first(), cls
->name());
1918 return Variant(info
);
1924 // caller raises exception
1928 /////////////////////////////////////////////////////////////////////////////
1929 // class ReflectionTypeAlias
1931 const StaticString
s_ReflectionTypeAliasHandle("ReflectionTypeAliasHandle");
1933 // helper for __construct:
1934 // caller throws exception when return value is false
1935 static String
HHVM_METHOD(ReflectionTypeAlias
, __init
, const String
& name
) {
1936 auto const typeAliasReq
= Unit::loadTypeAlias(name
.get());
1938 if (!typeAliasReq
) {
1939 return empty_string();
1942 ReflectionTypeAliasHandle::Get(this_
)->setTypeAliasReq(typeAliasReq
);
1943 return String::attach(const_cast<StringData
*>(typeAliasReq
->name
.get()));
1946 static Array
HHVM_METHOD(ReflectionTypeAlias
, getTypeStructure
) {
1947 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasReqFor(this_
);
1949 auto const typeStructure
= req
->typeStructure
;
1950 assertx(!typeStructure
.empty());
1951 assertx(typeStructure
.isDArray());
1952 return typeStructure
;
1955 static String
HHVM_METHOD(ReflectionTypeAlias
, getAssignedTypeText
) {
1956 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasReqFor(this_
);
1958 auto const typeStructure
= req
->typeStructure
;
1959 assertx(!typeStructure
.empty());
1960 assertx(typeStructure
.isDArray());
1961 return TypeStructure::toString(typeStructure
);
1964 static Array
HHVM_METHOD(ReflectionTypeAlias
, getAttributes
) {
1965 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasReqFor(this_
);
1967 auto const userAttrs
= req
->userAttrs
;
1969 ArrayInit
ai(userAttrs
.size(), ArrayInit::Mixed
{});
1970 for (auto& attr
: userAttrs
) {
1971 ai
.set(StrNR(attr
.first
), tvAsCVarRef(&attr
.second
));
1973 return ai
.toArray();
1976 ///////////////////////////////////////////////////////////////////////////////
1977 struct ReflectionExtension final
: Extension
{
1978 ReflectionExtension() : Extension("reflection", "$Id$") { }
1979 void moduleInit() override
{
1980 HHVM_FE(hphp_create_object
);
1981 HHVM_FE(hphp_create_object_without_constructor
);
1982 HHVM_FE(hphp_get_extension_info
);
1983 HHVM_FE(hphp_get_original_class_name
);
1984 HHVM_FE(hphp_get_property
);
1985 HHVM_FE(hphp_get_static_property
);
1986 HHVM_FE(hphp_invoke
);
1987 HHVM_FE(hphp_invoke_method
);
1988 HHVM_FE(hphp_set_property
);
1989 HHVM_FE(hphp_set_static_property
);
1990 HHVM_FALIAS(HH
\\type_structure
, type_structure
);
1992 HHVM_ME(ReflectionFunctionAbstract
, getName
);
1993 HHVM_ME(ReflectionFunctionAbstract
, isHack
);
1994 HHVM_ME(ReflectionFunctionAbstract
, isInternal
);
1995 HHVM_ME(ReflectionFunctionAbstract
, isGenerator
);
1996 HHVM_ME(ReflectionFunctionAbstract
, isAsync
);
1997 HHVM_ME(ReflectionFunctionAbstract
, isVariadic
);
1998 HHVM_ME(ReflectionFunctionAbstract
, getFileName
);
1999 HHVM_ME(ReflectionFunctionAbstract
, getStartLine
);
2000 HHVM_ME(ReflectionFunctionAbstract
, getEndLine
);
2001 HHVM_ME(ReflectionFunctionAbstract
, getDocComment
);
2002 HHVM_ME(ReflectionFunctionAbstract
, getStaticVariables
);
2003 HHVM_ME(ReflectionFunctionAbstract
, returnsReference
);
2004 HHVM_ME(ReflectionFunctionAbstract
, getReturnTypeHint
);
2005 HHVM_ME(ReflectionFunctionAbstract
, getNumberOfParameters
);
2006 HHVM_ME(ReflectionFunctionAbstract
, getParamInfo
);
2007 HHVM_ME(ReflectionFunctionAbstract
, getAttributes
);
2008 HHVM_ME(ReflectionFunctionAbstract
, getRetTypeInfo
);
2010 HHVM_ME(ReflectionMethod
, __init
);
2011 HHVM_ME(ReflectionMethod
, isFinal
);
2012 HHVM_ME(ReflectionMethod
, isAbstract
);
2013 HHVM_ME(ReflectionMethod
, isPublic
);
2014 HHVM_ME(ReflectionMethod
, isProtected
);
2015 HHVM_ME(ReflectionMethod
, isPrivate
);
2016 HHVM_ME(ReflectionMethod
, isStatic
);
2017 HHVM_ME(ReflectionMethod
, isConstructor
);
2018 HHVM_ME(ReflectionMethod
, getModifiers
);
2019 HHVM_ME(ReflectionMethod
, getPrototypeClassname
);
2020 HHVM_ME(ReflectionMethod
, getDeclaringClassname
);
2022 HHVM_ME(ReflectionFunction
, __initName
);
2023 HHVM_ME(ReflectionFunction
, __initClosure
);
2024 HHVM_ME(ReflectionFunction
, getClosureUseVariables
);
2025 HHVM_ME(ReflectionFunction
, getClosureScopeClassname
);
2026 HHVM_ME(ReflectionFunction
, getClosureThisObject
);
2028 HHVM_ME(ReflectionTypeConstant
, __init
);
2029 HHVM_ME(ReflectionTypeConstant
, getName
);
2030 HHVM_ME(ReflectionTypeConstant
, isAbstract
);
2031 HHVM_ME(ReflectionTypeConstant
, getAssignedTypeHint
);
2032 HHVM_ME(ReflectionTypeConstant
, getDeclaringClassname
);
2033 HHVM_ME(ReflectionTypeConstant
, getClassname
);
2035 HHVM_ME(ReflectionProperty
, __init
);
2037 HHVM_ME(ReflectionTypeAlias
, __init
);
2038 HHVM_ME(ReflectionTypeAlias
, getTypeStructure
);
2039 HHVM_ME(ReflectionTypeAlias
, getAttributes
);
2040 HHVM_ME(ReflectionTypeAlias
, getAssignedTypeText
);
2042 HHVM_ME(ReflectionClass
, __init
);
2043 HHVM_ME(ReflectionClass
, getName
);
2044 HHVM_ME(ReflectionClass
, getParentName
);
2045 HHVM_ME(ReflectionClass
, isHack
);
2046 HHVM_ME(ReflectionClass
, isInternal
);
2047 HHVM_ME(ReflectionClass
, isInstantiable
);
2048 HHVM_ME(ReflectionClass
, isInterface
);
2049 HHVM_ME(ReflectionClass
, isTrait
);
2050 HHVM_ME(ReflectionClass
, isEnum
);
2051 HHVM_ME(ReflectionClass
, isAbstract
);
2052 HHVM_ME(ReflectionClass
, isFinal
);
2053 HHVM_ME(ReflectionClass
, getModifiers
);
2054 HHVM_ME(ReflectionClass
, getFileName
);
2055 HHVM_ME(ReflectionClass
, getStartLine
);
2056 HHVM_ME(ReflectionClass
, getEndLine
);
2057 HHVM_ME(ReflectionClass
, getDocComment
);
2058 HHVM_ME(ReflectionClass
, getInterfaceNames
);
2059 HHVM_ME(ReflectionClass
, getRequirementNames
);
2060 HHVM_ME(ReflectionClass
, getTraitNames
);
2061 HHVM_ME(ReflectionClass
, getTraitAliases
);
2063 HHVM_ME(ReflectionClass
, hasMethod
);
2064 HHVM_ME(ReflectionClass
, getMethodOrder
);
2066 HHVM_ME(ReflectionClass
, hasConstant
);
2067 HHVM_ME(ReflectionClass
, getConstant
);
2068 HHVM_ME(ReflectionClass
, getOrderedConstants
);
2069 HHVM_ME(ReflectionClass
, getOrderedAbstractConstants
);
2070 HHVM_ME(ReflectionClass
, getOrderedTypeConstants
);
2072 HHVM_ME(ReflectionClass
, getAttributes
);
2073 HHVM_ME(ReflectionClass
, getAttributesRecursive
);
2075 HHVM_ME(ReflectionClass
, getClassPropertyInfo
);
2076 HHVM_ME(ReflectionClass
, getDynamicPropertyInfos
);
2077 HHVM_ME(ReflectionClass
, getConstructorName
);
2079 Native::registerNativeDataInfo
<ReflectionFuncHandle
>(
2080 s_ReflectionFuncHandle
.get());
2081 Native::registerNativeDataInfo
<ReflectionClassHandle
>(
2082 s_ReflectionClassHandle
.get());
2083 Native::registerNativeDataInfo
<ReflectionConstHandle
>(
2084 s_ReflectionConstHandle
.get());
2085 Native::registerNativeDataInfo
<ReflectionPropHandle
>(
2086 s_ReflectionPropHandle
.get());
2087 Native::registerNativeDataInfo
<ReflectionSPropHandle
>(
2088 s_ReflectionSPropHandle
.get());
2089 Native::registerNativeDataInfo
<ReflectionTypeAliasHandle
>(
2090 s_ReflectionTypeAliasHandle
.get(), Native::NO_SWEEP
);
2092 Native::registerNativePropHandler
2093 <reflection_extension_PropHandler
>(s_reflectionextension
);
2096 loadSystemlib("reflection-classes");
2097 loadSystemlib("reflection-internals-functions");
2098 loadSystemlib("reflection_hni");
2100 Reflection::s_ReflectionExceptionClass
=
2101 Unit::lookupClass(s_reflectionexception
.get());
2102 assertx(Reflection::s_ReflectionExceptionClass
);
2103 Reflection::s_ReflectionExtensionClass
=
2104 Unit::lookupClass(s_reflectionextension
.get());
2105 assertx(Reflection::s_ReflectionExtensionClass
);
2107 } s_reflection_extension
;
2109 ///////////////////////////////////////////////////////////////////////////////
2111 namespace DebuggerReflection
{
2113 static bool set_debugger_source_info(Array
&ret
, const char *file
, int line1
,
2115 if (!file
) file
= "";
2116 if (file
[0] != '/') {
2117 ret
.set(s_file
, String(RuntimeOption::SourceRoot
+ file
));
2119 ret
.set(s_file
, file
);
2121 ret
.set(s_line1
, make_tv
<KindOfInt64
>(line1
));
2122 ret
.set(s_line2
, make_tv
<KindOfInt64
>(line2
));
2123 return file
&& *file
;
2126 static void set_debugger_return_type_constraint(Array
&ret
, const StringData
* retType
) {
2127 if (retType
&& retType
->size()) {
2128 assertx(!retType
->isRefCounted());
2129 ret
.set(s_return_type
, make_tv
<KindOfPersistentString
>(retType
));
2131 ret
.set(s_return_type
, false_varNR
.tv());
2135 static void set_debugger_reflection_method_prototype_info(Array
& ret
,
2137 const Class
*prototypeCls
= nullptr;
2138 if (func
->baseCls() != nullptr && func
->baseCls() != func
->implCls()) {
2139 prototypeCls
= func
->baseCls();
2140 const Class
*result
= get_prototype_class_from_interfaces(
2141 prototypeCls
, func
);
2142 if (result
) prototypeCls
= result
;
2143 } else if (func
->isMethod()) {
2144 // lookup the prototype in the interfaces
2145 prototypeCls
= get_prototype_class_from_interfaces(func
->implCls(), func
);
2148 Array prototype
= Array::Create();
2149 prototype
.set(s_class
,
2150 make_tv
<KindOfPersistentString
>(prototypeCls
->name()));
2151 prototype
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2152 ret
.set(s_prototype
, prototype
);
2156 static void set_debugger_reflection_function_info(Array
& ret
,
2159 if (func
->attrs() & AttrReference
) {
2160 ret
.set(s_ref
, true_varNR
.tv());
2162 if (func
->isBuiltin()) {
2163 ret
.set(s_internal
, true_varNR
.tv());
2165 set_debugger_return_type_constraint(ret
, func
->returnUserType());
2168 set_doc_comment(ret
, func
->docComment(), func
->isBuiltin());
2171 ret
.set(s_params
, get_function_param_info(func
));
2174 ret
.set(s_static_variables
, get_function_static_variables(func
));
2177 ret
.set(s_attributes
, get_function_user_attributes(func
));
2179 ret
.set(s_is_async
, func
->isAsync());
2180 ret
.set(s_is_closure
, func
->isClosureBody());
2181 ret
.set(s_is_generator
, func
->isGenerator());
2184 static void set_debugger_reflection_method_info(Array
& ret
, const Func
* func
,
2186 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2187 set_attrs(ret
, get_modifiers(func
->attrs(), false));
2189 if (isConstructor(func
)) {
2190 ret
.set(s_constructor
, true_varNR
.tv());
2193 // If Func* is from a PreClass, it doesn't know about base classes etc.
2194 // Swap it out for the full version if possible.
2195 auto resolved_func
= func
->implCls()
2197 : cls
->lookupMethod(func
->name());
2199 if (!resolved_func
) {
2200 resolved_func
= func
;
2204 make_tv
<KindOfPersistentString
>(resolved_func
->implCls()->name()));
2205 set_debugger_reflection_function_info(ret
, resolved_func
);
2206 set_debugger_source_info(ret
, func
->unit()->filepath()->data(),
2207 func
->line1(), func
->line2());
2208 set_debugger_reflection_method_prototype_info(ret
, resolved_func
);
2211 Array
get_function_info(const String
& name
) {
2213 if (name
.get() == nullptr) return ret
;
2214 const Func
* func
= Unit::loadFunc(name
.get());
2215 if (!func
) return ret
;
2216 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2218 // setting parameters and static variables
2219 set_debugger_reflection_function_info(ret
, func
);
2220 set_debugger_source_info(ret
, func
->unit()->filepath()->data(),
2221 func
->line1(), func
->line2());
2225 Array
get_class_info(const String
& name
) {
2226 auto cls
= get_cls(name
);
2227 if (!cls
) return Array();
2230 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(cls
->name()));
2231 ret
.set(s_extension
, empty_string_variant_ref
);
2232 ret
.set(s_parent
, make_tv
<KindOfPersistentString
>(cls
->preClass()->parent()));
2236 Array arr
= Array::Create();
2237 for (auto const& interface
: cls
->declInterfaces()) {
2238 arr
.set(interface
->nameStr(), make_tv
<KindOfInt64
>(1));
2240 auto const& allIfaces
= cls
->allInterfaces();
2241 if (allIfaces
.size() > cls
->declInterfaces().size()) {
2242 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
2243 auto const& interface
= allIfaces
[i
];
2244 arr
.set(interface
->nameStr(), make_tv
<KindOfInt64
>(1));
2247 ret
.set(s_interfaces
, VarNR(arr
).tv());
2252 Array arr
= Array::Create();
2253 for (auto const& traitName
: cls
->preClass()->usedTraits()) {
2254 arr
.set(StrNR(traitName
), make_tv
<KindOfInt64
>(1));
2256 ret
.set(s_traits
, VarNR(arr
).tv());
2261 ret
.set(s_trait_aliases
, VarNR(get_trait_alias_info(cls
)).tv());
2266 if (cls
->attrs() & AttrBuiltin
) {
2267 ret
.set(s_internal
, true_varNR
.tv());
2269 if (cls
->attrs() & AttrFinal
) {
2270 ret
.set(s_final
, true_varNR
.tv());
2272 if (cls
->attrs() & AttrAbstract
) {
2273 ret
.set(s_abstract
, true_varNR
.tv());
2275 if (cls
->attrs() & AttrInterface
) {
2276 ret
.set(s_interface
, true_varNR
.tv());
2278 if (cls
->attrs() & AttrTrait
) {
2279 ret
.set(s_trait
, true_varNR
.tv());
2281 ret
.set(s_modifiers
, make_tv
<KindOfInt64
>(
2282 get_modifiers(cls
->attrs(), true))
2285 if (cls
->getCtor()->attrs() & AttrPublic
&&
2286 !(cls
->attrs() & AttrAbstract
) &&
2287 !(cls
->attrs() & AttrInterface
) &&
2288 !(cls
->attrs() & AttrTrait
)) {
2289 ret
.set(s_instantiable
, true_varNR
.tv());
2295 Array arr
= Array::Create();
2297 // Fetch from PreClass as:
2298 // - the order is important
2299 // - we want type profiling info
2300 // and neither of these are in the Class...
2301 Func
* const* methods
= cls
->preClass()->methods();
2302 size_t const numMethods
= cls
->preClass()->numMethods();
2303 for (Slot i
= 0; i
< numMethods
; ++i
) {
2304 const Func
* m
= methods
[i
];
2305 if (m
->isGenerated()) continue;
2307 auto lowerName
= HHVM_FN(strtolower
)(m
->nameStr());
2308 Array info
= Array::Create();
2309 set_debugger_reflection_method_info(info
, m
, cls
);
2310 arr
.set(lowerName
, VarNR(info
).tv());
2313 for (Slot i
= cls
->traitsBeginIdx(); i
< cls
->traitsEndIdx(); ++i
) {
2314 const Func
* m
= cls
->getMethod(i
);
2315 if (m
->isGenerated()) continue;
2317 auto lowerName
= HHVM_FN(strtolower
)(m
->nameStr());
2318 Array info
= Array::Create();
2319 set_debugger_reflection_method_info(info
, m
, cls
);
2320 arr
.set(lowerName
, VarNR(info
).tv());
2322 ret
.set(s_methods
, VarNR(arr
).tv());
2327 auto arr
= Array::Create();
2328 auto arrPriv
= Array::Create();
2329 auto arrIdx
= Array::Create();
2330 auto arrPrivIdx
= Array::Create();
2332 auto const properties
= cls
->declProperties();
2333 auto const& propInitVec
= cls
->declPropInit();
2334 auto const nProps
= cls
->numDeclProperties();
2336 for (Slot i
= 0; i
< nProps
; ++i
) {
2337 auto const& prop
= properties
[i
];
2338 auto const& default_val
= tvAsCVarRef(&propInitVec
[i
]);
2339 auto info
= Array::Create();
2340 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
2341 if (prop
.cls
== cls
) {
2342 set_instance_prop_info(info
, &prop
, default_val
);
2343 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
2344 arrPrivIdx
.set(StrNR(prop
.name
), prop
.idx
);
2348 set_instance_prop_info(info
, &prop
, default_val
);
2349 arr
.set(StrNR(prop
.name
), VarNR(info
).tv());
2350 arrIdx
.set(StrNR(prop
.name
), prop
.idx
);
2353 for (auto const& prop
: cls
->staticProperties()) {
2354 auto info
= Array::Create();
2355 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
2356 if (prop
.cls
== cls
) {
2357 set_static_prop_info(info
, &prop
);
2358 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
2359 arrPrivIdx
.set(StrNR(prop
.name
), prop
.idx
);
2363 set_static_prop_info(info
, &prop
);
2364 arr
.set(StrNR(prop
.name
), VarNR(info
).tv());
2365 arrIdx
.set(StrNR(prop
.name
), prop
.idx
);
2367 ret
.set(s_properties
, VarNR(arr
).tv());
2368 ret
.set(s_private_properties
, VarNR(arrPriv
).tv());
2369 ret
.set(s_properties_index
, VarNR(arrIdx
).tv());
2370 ret
.set(s_private_properties_index
, VarNR(arrPrivIdx
).tv());
2375 Array arr
= Array::Create();
2377 size_t numConsts
= cls
->numConstants();
2378 const Class::Const
* consts
= cls
->constants();
2380 for (size_t i
= 0; i
< numConsts
; i
++) {
2381 // Note: hphpc doesn't include inherited constants in
2382 // get_class_constants(), so mimic that behavior
2383 if (consts
[i
].cls
== cls
) {
2384 Cell value
= cls
->clsCnsGet(consts
[i
].name
);
2385 assert(value
.m_type
!= KindOfUninit
);
2386 arr
.set(StrNR(consts
[i
].name
), cellAsCVarRef(value
));
2390 ret
.set(s_constants
, VarNR(arr
).tv());
2394 const PreClass
* pcls
= cls
->preClass();
2395 set_debugger_source_info(ret
, pcls
->unit()->filepath()->data(),
2396 pcls
->line1(), pcls
->line2());
2397 set_doc_comment(ret
, pcls
->docComment(), pcls
->isBuiltin());
2402 Array arr
= Array::Create();
2403 const PreClass
* pcls
= cls
->preClass();
2404 for (auto it
= pcls
->userAttributes().begin();
2405 it
!= pcls
->userAttributes().end(); ++it
) {
2406 arr
.set(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
2408 ret
.set(s_attributes
, VarNR(arr
).tv());
2416 ///////////////////////////////////////////////////////////////////////////////