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/builtin-functions.h"
22 #include "hphp/runtime/base/file.h"
23 #include "hphp/runtime/base/runtime-option.h"
24 #include "hphp/runtime/base/string-hash-set.h"
25 #include "hphp/runtime/base/string-util.h"
26 #include "hphp/runtime/base/tv-refcount.h"
27 #include "hphp/runtime/base/type-structure.h"
28 #include "hphp/runtime/base/type-variant.h"
29 #include "hphp/runtime/base/unit-cache.h"
30 #include "hphp/runtime/base/vanilla-dict.h"
31 #include "hphp/runtime/vm/jit/translator-inline.h"
32 #include "hphp/runtime/vm/jit/translator-runtime.h"
33 #include "hphp/runtime/vm/native-data.h"
34 #include "hphp/runtime/vm/native-prop-handler.h"
36 #include "hphp/runtime/server/source-root-info.h"
38 #include "hphp/runtime/ext/debugger/ext_debugger.h"
39 #include "hphp/runtime/ext/std/ext_std_closure.h"
40 #include "hphp/runtime/ext/collections/ext_collections-set.h"
41 #include "hphp/runtime/ext/std/ext_std_misc.h"
42 #include "hphp/runtime/ext/string/ext_string.h"
43 #include "hphp/runtime/ext/extension-registry.h"
45 #include "hphp/system/systemlib.h"
48 #include <boost/algorithm/string/predicate.hpp>
52 ///////////////////////////////////////////////////////////////////////////////
60 s_constants("constants"),
61 s_constructor("constructor"),
62 s_functions("functions"),
66 s_protected("protected"),
72 s_modifiers("modifiers"),
74 s_prototype("prototype"),
77 s_readonly("readonly"),
80 s_nullable("nullable"),
82 s_is_optional("is_optional"),
83 s_is_variadic("is_variadic"),
85 s_defaultValue("defaultValue"),
86 s_defaultText("defaultText"),
89 s_abstract("abstract"),
90 s_instantiable("instantiable"),
91 s_internal("internal"),
92 s_is_async("is_async"),
93 s_is_closure("is_closure"),
94 s_is_generator("is_generator"),
96 s_static_variables("static_variables"),
97 s_extension("extension"),
98 s_interfaces("interfaces"),
100 s_interface("interface"),
102 s_methods("methods"),
103 s_properties("properties"),
104 s_private_properties("private_properties"),
105 s_properties_index("properties_index"),
106 s_private_properties_index("private_properties_index"),
107 s_attributes("attributes"),
108 s_function("function"),
109 s_trait_aliases("trait_aliases"),
111 s___invoke("__invoke"),
112 s_return_type("return_type"),
113 s_accessible("accessible"),
114 s_reflectionexception("ReflectionException"),
115 s_reflectionextension("ReflectionExtension"),
116 s_type_hint("type_hint"),
117 s_type_hint_builtin("type_hint_builtin"),
118 s_type_hint_nullable("type_hint_nullable"),
119 s_is_reified("is_reified"),
120 s_is_soft("is_soft"),
121 s_is_warn("is_warn");
123 Class
* Reflection::s_ReflectionExceptionClass
= nullptr;
124 Class
* Reflection::s_ReflectionExtensionClass
= nullptr;
126 Class
* get_cls(const Variant
& class_or_object
) {
127 if (class_or_object
.is(KindOfObject
)) {
128 return class_or_object
.asCObjRef()->getVMClass();
129 } else if (class_or_object
.isClass()) {
130 return class_or_object
.toClassVal();
133 return Class::load(class_or_object
.toString().get());
136 const Func
* get_method_func(const Class
* cls
, const String
& meth_name
) {
137 const Func
* func
= cls
->lookupMethod(meth_name
.get());
139 if (cls
->attrs() & (AttrInterface
| AttrAbstract
| AttrTrait
)) {
140 const Class::InterfaceMap
& ifaces
= cls
->allInterfaces();
141 for (int i
= 0, size
= ifaces
.size(); i
< size
; i
++) {
142 func
= ifaces
[i
]->lookupMethod(meth_name
.get());
147 assertx(func
== nullptr || func
->isMethod());
151 Variant
default_arg_from_php_code(const Func::ParamInfo
& fpi
,
152 const Func
* func
, unsigned argIdx
) {
153 assertx(fpi
.hasDefaultValue());
154 if (fpi
.hasScalarDefaultValue()) {
155 // Most of the time the default value is scalar, so we can
156 // avoid evaling in the common case
157 return tvAsVariant((TypedValue
*)&fpi
.defaultValue
);
159 // Eval PHP code to get the default value. Note that eval here can throw a
160 // fatal, e.g. due to the use of undefined class constants or static:: .
161 // When this happens, instead of fataling the execution, set the default
162 // value to null and raise a warning.
163 auto const on_eval_exn
= [&] {
164 raise_warning("Failed to eval default value of %s()'s $%s argument for "
165 "reflection, assigning NULL instead",
166 func
->fullNameStr().data(),
167 func
->localNames()[argIdx
]->data());
168 return init_null_variant
;
172 return g_context
->getEvaledArg(
174 // We use cls() instead of implCls() because we want the namespace and
175 // class context for which the closure is scoped, not that of the
176 // Closure subclass (which, among other things, is always globally
178 func
->cls() ? func
->cls()->nameStr() : func
->nameStr(),
181 } catch (const Exception
&) {
182 return on_eval_exn();
183 } catch (const Object
&) {
184 if (RO::EvalFixDefaultArgReflection
> 1) {
185 return on_eval_exn();
187 if (RO::EvalFixDefaultArgReflection
> 0) {
188 raise_notice("Evaluation of default arg initializer in func=%s, arg=%s "
189 "threw a PHP exception--this reflection call won't throw "
191 func
->fullNameStr().data(),
192 func
->localNames()[argIdx
]->data());
199 Array
HHVM_FUNCTION(hphp_get_extension_info
, const String
& name
) {
201 Extension
*ext
= ExtensionRegistry::get(name
);
203 return make_dict_array(
205 s_version
, ext
? ext
->getVersion() : "",
206 s_info
, empty_string(),
207 s_ini
, empty_dict_array(),
208 s_constants
, empty_dict_array(),
209 s_functions
, empty_dict_array(),
210 s_classes
, empty_dict_array()
214 int get_modifiers(Attr attrs
, bool cls
, bool prop
) {
215 int php_modifier
= 0;
217 // These bits have different meanings with properties
218 if (attrs
& AttrAbstract
) php_modifier
|= cls
? 0x20 : 0x02;
219 if (attrs
& AttrFinal
) php_modifier
|= cls
? 0x40 : 0x04;
221 if (!cls
) { // AttrPublic bits are not valid on class (have other meaning)
222 if (attrs
& AttrStatic
) php_modifier
|= 0x01;
223 if (attrs
& AttrPublic
) php_modifier
|= 0x100;
224 if (attrs
& AttrProtected
) php_modifier
|= 0x200;
225 if (attrs
& AttrPrivate
) php_modifier
|= 0x400;
231 static Attr
attrs_from_modifiers(int php_modifier
, bool cls
) {
232 Attr attrs
= (Attr
) 0;
233 if (php_modifier
& (cls
? 0x20 : 0x02)) {
234 attrs
= (Attr
)(attrs
| AttrAbstract
);
236 if (php_modifier
& (cls
? 0x40 : 0x04)) {
237 attrs
= (Attr
)(attrs
| AttrFinal
);
239 if (php_modifier
& 0x01) { attrs
= (Attr
)(attrs
| AttrStatic
); }
240 if (!cls
) { // AttrPublic bits are not valid on class (have other meaning)
241 if (php_modifier
& 0x100) { attrs
= (Attr
)(attrs
| AttrPublic
); }
242 if (php_modifier
& 0x200) { attrs
= (Attr
)(attrs
| AttrProtected
); }
243 if (php_modifier
& 0x400) { attrs
= (Attr
)(attrs
| AttrPrivate
); }
248 static void set_attrs(Array
& ret
, int modifiers
) {
249 if (modifiers
& 0x100) {
250 ret
.set(s_access
, VarNR(s_public
).tv());
251 ret
.set(s_accessible
, make_tv
<KindOfBoolean
>(true));
252 } else if (modifiers
& 0x200) {
253 ret
.set(s_access
, VarNR(s_protected
).tv());
254 ret
.set(s_accessible
, make_tv
<KindOfBoolean
>(false));
255 } else if (modifiers
& 0x400) {
256 ret
.set(s_access
, VarNR(s_private
).tv());
257 ret
.set(s_accessible
, make_tv
<KindOfBoolean
>(false));
261 ret
.set(s_modifiers
, make_tv
<KindOfInt64
>(modifiers
));
262 if (modifiers
& 0x1) {
263 ret
.set(s_static
, make_tv
<KindOfBoolean
>(true));
265 if (modifiers
& 0x44) {
266 ret
.set(s_final
, make_tv
<KindOfBoolean
>(true));
268 if (modifiers
& 0x22) {
269 ret
.set(s_abstract
, make_tv
<KindOfBoolean
>(true));
273 static void set_empty_doc_comment(Array
& ret
) {
274 ret
.set(s_doc
, make_tv
<KindOfBoolean
>(false));
277 static void set_doc_comment(Array
& ret
,
278 const StringData
* comment
,
280 assertx(ret
.isDict());
281 if (comment
== nullptr || comment
->empty()) {
282 set_empty_doc_comment(ret
);
283 } else if (isBuiltin
&& !HHVM_FUNCTION(hphp_debugger_attached
)) {
284 set_empty_doc_comment(ret
);
286 assertx(!comment
->isRefCounted());
287 ret
.set(s_doc
, make_tv
<KindOfPersistentString
>(comment
));
291 static void set_instance_prop_info(Array
& ret
,
292 const Class::Prop
* prop
,
293 TypedValue default_val
) {
294 assertx(ret
.isDict());
295 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(prop
->name
));
296 ret
.set(s_default
, make_tv
<KindOfBoolean
>(true));
297 ret
.set(s_defaultValue
, default_val
);
298 set_attrs(ret
, get_modifiers(prop
->attrs
, false, true) & ~0x66);
299 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
300 set_doc_comment(ret
, prop
->preProp
->docComment(), prop
->cls
->isBuiltin());
302 auto const user_type
= prop
->preProp
->userType();
303 if (user_type
&& user_type
->size()) {
304 ret
.set(s_type
, make_tv
<KindOfPersistentString
>(user_type
));
306 ret
.set(s_type
, make_tv
<KindOfBoolean
>(false));
310 static void set_dyn_prop_info(
313 const StringData
* className
) {
314 assertx(ret
.isDict());
315 ret
.set(s_name
, name
);
316 set_attrs(ret
, get_modifiers(AttrPublic
, false, true) & ~0x66);
317 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(className
));
318 set_empty_doc_comment(ret
);
319 ret
.set(s_type
, make_tv
<KindOfBoolean
>(false));
322 static void set_static_prop_info(Array
&ret
, const Class::SProp
* prop
) {
323 assertx(ret
.isDict());
324 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(prop
->name
));
325 ret
.set(s_default
, make_tv
<KindOfBoolean
>(true));
326 ret
.set(s_defaultValue
, prop
->val
);
327 set_attrs(ret
, get_modifiers(prop
->attrs
, false, true) & ~0x66);
328 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
329 set_doc_comment(ret
, prop
->preProp
->docComment(), prop
->cls
->isBuiltin());
330 auto const user_type
= prop
->preProp
->userType();
331 if (user_type
&& user_type
->size()) {
332 ret
.set(s_type
, make_tv
<KindOfPersistentString
>(user_type
));
334 ret
.set(s_type
, make_tv
<KindOfBoolean
>(false));
338 static bool resolveConstant(const char *p
, int64_t len
, Variant
&cns
) {
340 while (len
&& (*p
== ' ')) {
345 while (len
&& (p
[len
-1] == ' ')) {
349 String
cname(p
, len
, CopyString
);
351 if (!f_defined(cname
)) {
356 cns
= f_constant(cname
);
360 bool resolveDefaultParameterConstant(const char *value
, int64_t valueLen
,
362 const char *p
= value
;
363 const char *e
= value
+ valueLen
;
368 while ((s
= strchr(p
, '|'))) {
370 if (!resolveConstant(p
, s
- p
, cns
)) {
373 lval
|= cns
.toInt64();
376 if (!resolveConstant(p
, e
- p
, cns
)) {
380 cns
= cns
.toInt64() | lval
;
385 static bool isConstructor(const Func
* func
) {
386 PreClass
* pcls
= func
->preClass();
387 if (!pcls
|| (pcls
->attrs() & AttrInterface
)) { return false; }
388 if (func
->implCls()) { return func
== func
->implCls()->getCtor(); }
389 if (0 == strcasecmp("__construct", func
->name()->data())) { return true; }
390 /* A same named function is not a constructor in a trait */
391 if (pcls
->attrs() & AttrTrait
) return false;
392 return pcls
->name()->isame(func
->name());
395 static const Class
* get_prototype_class_from_interfaces(const Class
*cls
,
397 // only looks at the interfaces if the method is public
398 if (!func
->isPublic()) return nullptr;
399 const Class::InterfaceMap
& interfaces
= cls
->allInterfaces();
400 for (unsigned int i
= 0, size
= interfaces
.size(); i
< size
; i
++) {
401 const Class
* iface
= interfaces
[i
];
402 if (iface
->preClass()->hasMethod(func
->name())) return iface
;
407 Variant
HHVM_FUNCTION(hphp_invoke
, const String
& name
, const Variant
& params
) {
408 return invoke(name
, params
);
411 static const StaticString
s_invoke_not_instanceof_error(
412 "Given object is not an instance of the class this method was declared in"
415 static const StaticString
s_invoke_non_object(
416 "Non-object passed to Invoke()"
419 Variant
HHVM_FUNCTION(hphp_invoke_method
, const Variant
& obj
,
422 const Variant
& params
) {
424 return invoke_static_method(cls
, name
, params
);
427 if (!obj
.is(KindOfObject
)) {
428 Reflection::ThrowReflectionExceptionObject(s_invoke_non_object
);
431 auto const providedClass
= Class::load(cls
.get());
432 if (!providedClass
) {
433 raise_error("Call to undefined method %s::%s()", cls
.data(), name
.data());
435 auto const selectedFunc
= providedClass
->lookupMethod(name
.get());
437 raise_error("Call to undefined method %s::%s()", cls
.data(), name
.data());
440 auto const objData
= obj
.asCObjRef().get();
441 auto const implementingClass
= selectedFunc
->implCls();
442 if (!objData
->instanceof(implementingClass
)) {
443 Reflection::ThrowReflectionExceptionObject(s_invoke_not_instanceof_error
);
446 // Get the CallCtx this way instead of using vm_decode_function() because
447 // vm_decode_function() has no way to specify a class independent from the
448 // class::function being called.
449 // Note that this breaks the rules for name lookup (for protected and private)
450 // but that's okay because so does Zend's implementation.
452 ctx
.cls
= providedClass
;
454 ctx
.func
= selectedFunc
;
457 return Variant::attach(
458 g_context
->invokeFunc(ctx
, params
, RuntimeCoeffects::fixme())
462 Object
HHVM_FUNCTION(hphp_create_object
, const String
& name
,
463 const Variant
& params
) {
464 return Object::attach(g_context
->createObject(name
.get(), params
));
467 Object
HHVM_FUNCTION(hphp_create_object_without_constructor
,
468 const String
& name
) {
469 return Object::attach(
470 g_context
->createObject(name
.get(), init_null_variant
, false)
474 Variant
HHVM_FUNCTION(hphp_get_property
, const Object
& obj
, const String
& cls
,
475 const String
& prop
) {
476 /* It's possible to get a ReflectionProperty for a property which
477 * no longer exists. Silentyly fail to match PHP5 behavior
479 return obj
->o_get(prop
, false /* error */, cls
);
482 void HHVM_FUNCTION(hphp_set_property
, const Object
& obj
, const String
& cls
,
483 const String
& prop
, const Variant
& value
) {
484 if (!cls
.empty() && RuntimeOption::EvalAuthoritativeMode
) {
486 "We've already made many assumptions about private variables. "
487 "You can't change accessibility in Whole Program mode"
491 obj
->o_set(prop
, value
, cls
);
494 Variant
HHVM_FUNCTION(hphp_get_static_property
, const String
& cls
,
497 auto const sd
= cls
.get();
498 auto const class_
= Class::lookup(sd
);
500 raise_error("Non-existent class %s", sd
->data());
503 CoeffectsAutoGuard _2
;
505 auto const lookup
= class_
->getSPropIgnoreLateInit(
506 force
? class_
: arGetContextClass(vmfp()),
510 raise_error("Class %s does not have a property named %s",
511 sd
->data(), prop
.get()->data());
513 if (!lookup
.accessible
) {
514 raise_error("Invalid access to class %s's property %s",
515 sd
->data(), prop
.get()->data());
517 return tvAsVariant(lookup
.val
);
520 void HHVM_FUNCTION(hphp_set_static_property
, const String
& cls
,
522 const Variant
& value
,
524 if (RuntimeOption::EvalAuthoritativeMode
) {
525 raise_error("Setting static properties through reflection is not "
526 "allowed in RepoAuthoritative mode");
528 auto const sd
= cls
.get();
529 auto const class_
= Class::lookup(sd
);
531 if (!class_
) raise_error("Non-existent class %s", sd
->data());
534 CoeffectsAutoGuard _2
;
536 auto const lookup
= class_
->getSPropIgnoreLateInit(
537 force
? class_
: arGetContextClass(vmfp()),
541 raise_error("Class %s does not have a property named %s",
542 sd
->data(), prop
.get()->data());
544 if (!lookup
.accessible
) {
545 raise_error("Invalid access to class %s's property %s",
546 sd
->data(), prop
.get()->data());
548 if (lookup
.constant
) {
549 throw_cannot_modify_static_const_prop(sd
->data(), prop
.get()->data());
552 auto const& sprop
= class_
->staticProperties()[lookup
.slot
];
553 auto const& tc
= sprop
.typeConstraint
;
554 // TODO(T61738946): We can remove the temporary here once we no longer coerce
557 if (RuntimeOption::EvalCheckPropTypeHints
> 0 && tc
.isCheckable()) {
558 tc
.verifyStaticProperty(tmp
.asTypedValue(), class_
, sprop
.cls
, prop
.get());
560 tvAsVariant(lookup
.val
) = tmp
;
565 const StaticString
s_classname("classname");
567 Array
implTypeStructure(const Variant
& cls_or_obj
,
568 const Variant
& cns_name
,
570 SuppressClassConversionWarning suppressor
;
571 auto const cns_sd
= cns_name
.getStringDataOrNull();
573 auto name
= cls_or_obj
.toString();
575 auto const typeAlias
= TypeAlias::load(name
.get());
578 raise_error("Non-existent type alias %s", name
.get()->data());
581 auto const& preresolved
= typeAlias
->resolvedTypeStructure();
582 if (!preresolved
.isNull()) {
583 assertx(!preresolved
.empty());
584 assertx(preresolved
.isDict());
588 auto const& typeStructure
= typeAlias
->typeStructure();
589 assertx(!typeStructure
.empty());
590 assertx(typeStructure
.isDict());
593 bool persistent
= true;
594 resolved
= TypeStructure::resolve(name
, typeStructure
, persistent
);
595 } catch (Exception
& e
) {
596 raise_error("resolving type alias %s failed. "
597 "Have you declared all classes in the type alias",
600 assertx(!resolved
.empty());
601 assertx(resolved
.isDict());
605 auto const cls
= get_cls(cls_or_obj
);
608 raise_error("Class undefined: %s", cls_or_obj
.toString().get()->data());
611 auto const cls_sd
= cls
->name();
613 if (!cls
->hasTypeConstant(cns_sd
, true)) {
614 raise_error("Non-existent type constant %s::%s",
615 cls_sd
->data(), cns_sd
->data());
618 auto ad
= jit::loadClsTypeCnsHelper(cls
, cns_sd
, no_throw
);
619 return Array::attach(ad
);
625 * cls_or_obj: the name of a class or an instance of the class;
626 * cns_name: the name of the type constant of the class;
628 * If the type constant exists and is not abstract, this function
629 * returns the shape representing the type associated with the type
632 Array
HHVM_FUNCTION(type_structure
,
633 const Variant
& cls_or_obj
, const Variant
& cns_name
) {
634 return implTypeStructure(cls_or_obj
, cns_name
, false);
637 Array
HHVM_FUNCTION(type_structure_no_throw
,
638 const Variant
& cls_or_obj
, const Variant
& cns_name
) {
639 return implTypeStructure(cls_or_obj
, cns_name
, true);
642 String
HHVM_FUNCTION(type_structure_classname
,
643 const Variant
& cls_or_obj
, const Variant
& cns_name
) {
644 auto const ts
= implTypeStructure(cls_or_obj
, cns_name
, false);
645 auto const classname
= ts
->get(s_classname
.get(), true);
646 assertx(isStringType(type(classname
)));
647 assertx(val(classname
).pstr
->isStatic());
648 return String::attach(val(classname
).pstr
);
652 void Reflection::ThrowReflectionExceptionObject(const Variant
& message
) {
653 Object inst
{s_ReflectionExceptionClass
};
655 g_context
->invokeFunc(s_ReflectionExceptionClass
->getCtor(),
656 make_vec_array(message
),
663 /////////////////////////////////////////////////////////////////////////////
664 // class ReflectionFuncHandle
666 const StaticString
s_ReflectionFuncHandle("ReflectionFuncHandle");
668 static TypedValue
HHVM_METHOD(ReflectionFunctionAbstract
, getFileName
) {
669 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
670 if (func
->isBuiltin()) {
671 return make_tv
<KindOfBoolean
>(false);
673 auto file
= func
->unit()->filepath();
674 if (!file
) file
= staticEmptyString();
675 if (file
->data()[0] != '/') {
676 auto path
= SourceRootInfo::RelativeToPhpRoot(StrNR(file
));
677 return make_tv
<KindOfString
>(path
.detach());
679 assertx(!file
->isRefCounted());
680 return make_tv
<KindOfPersistentString
>(file
);
683 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getStartLine
) {
684 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
685 if (func
->isBuiltin()) {
688 return func
->line1();
691 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getEndLine
) {
692 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
693 if (func
->isBuiltin()) {
696 return func
->line2();
699 static TypedValue
HHVM_METHOD(ReflectionFunctionAbstract
, getDocComment
) {
700 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
701 auto const comment
= func
->docComment();
702 if (comment
== nullptr || comment
->empty()) {
703 return make_tv
<KindOfBoolean
>(false);
705 assertx(!comment
->isRefCounted());
706 return make_tv
<KindOfPersistentString
>(const_cast<StringData
*>(comment
));
710 static String
HHVM_METHOD(ReflectionFunctionAbstract
, getName
) {
711 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
712 auto ret
= const_cast<StringData
*>(func
->name());
716 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isHack
) {
720 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isInternal
) {
721 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
722 return func
->isBuiltin();
725 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isGenerator
) {
726 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
727 return func
->isGenerator();
730 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isAsync
) {
731 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
732 return func
->isAsync();
735 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isInternalToModule
) {
736 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
737 return func
->attrs() & AttrInternal
;
740 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isVariadic
) {
741 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
742 return func
->hasVariadicCaptureParam();
745 static int64_t HHVM_METHOD(ReflectionFunctionAbstract
, getNumberOfParameters
) {
746 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
747 return func
->numParams();
751 static Array
get_function_param_info(const Func
* func
) {
752 const Func::ParamInfoVec
& params
= func
->params();
753 VecInit
ai(func
->numParams());
755 for (int i
= 0; i
< func
->numParams(); ++i
) {
756 Array param
= Array::CreateDict();
757 const Func::ParamInfo
& fpi
= params
[i
];
759 param
.set(s_index
, make_tv
<KindOfInt64
>(i
));
760 param
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->localNames()[i
]));
762 auto const nonExtendedConstraint
=
763 fpi
.typeConstraint
.hasConstraint() &&
764 !fpi
.typeConstraint
.isExtended();
765 auto const type
= nonExtendedConstraint
766 ? fpi
.typeConstraint
.typeName()
767 : staticEmptyString();
769 param
.set(s_type
, make_tv
<KindOfPersistentString
>(type
));
770 const StringData
* typeHint
= fpi
.userType
772 : staticEmptyString();
773 param
.set(s_type_hint
, make_tv
<KindOfPersistentString
>(typeHint
));
775 // callable typehint considered builtin; stdclass typehint is not
777 fpi
.typeConstraint
.isCallable() ||
778 (fpi
.typeConstraint
.underlyingDataType() &&
779 fpi
.typeConstraint
.underlyingDataType() != KindOfObject
782 param
.set(s_type_hint_builtin
, make_tv
<KindOfBoolean
>(true));
784 param
.set(s_type_hint_builtin
, make_tv
<KindOfBoolean
>(false));
786 param
.set(s_function
, make_tv
<KindOfPersistentString
>(func
->name()));
787 if (func
->preClass()) {
790 make_tv
<KindOfPersistentString
>(
791 func
->implCls() ? func
->implCls()->name()
792 : func
->preClass()->name()
796 if (!nonExtendedConstraint
|| fpi
.typeConstraint
.isNullable()) {
797 param
.set(s_nullable
, make_tv
<KindOfBoolean
>(true));
798 param
.set(s_type_hint_nullable
, make_tv
<KindOfBoolean
>(true));
800 param
.set(s_type_hint_nullable
, make_tv
<KindOfBoolean
>(false));
804 Variant v
= default_arg_from_php_code(fpi
, func
, i
);
805 param
.set(s_default
, v
);
806 param
.set(s_defaultText
, make_tv
<KindOfPersistentString
>(fpi
.phpCode
));
809 if (func
->isInOut(i
)) {
810 param
.set(s_inout
, make_tv
<KindOfBoolean
>(true));
812 if (func
->isReadonly(i
)) {
813 param
.set(s_readonly
, make_tv
<KindOfBoolean
>(true));
815 if (fpi
.isVariadic()) {
816 param
.set(s_is_variadic
, make_tv
<KindOfBoolean
>(true));
819 DictInit
userAttrs(fpi
.userAttributes
.size());
820 for (auto const& attr
: fpi
.userAttributes
) {
821 userAttrs
.set(StrNR
{attr
.first
}, attr
.second
);
823 param
.set(s_attributes
, make_array_like_tv(userAttrs
.create()));
825 ai
.append(VarNR(param
).tv());
828 auto arr
= ai
.toArray();
830 bool isOptional
= true;
831 for (int i
= func
->numParams() - 1; i
>= 0; i
--) {
832 auto& param
= asArrRef(arr
.lval(i
));
834 isOptional
= isOptional
&& (param
.exists(s_default
) ||
835 param
.exists(s_is_variadic
));
836 param
.set(s_is_optional
, isOptional
);
841 // helper for getParameters
842 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getParamInfo
) {
843 // FIXME: each parameter info should be HNI with a handle to the
845 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
846 return get_function_param_info(func
);
849 // helper for getReturnTypeText
850 static String
HHVM_METHOD(ReflectionFunctionAbstract
, getReturnTypeHint
) {
851 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
852 auto retTypeSD
= func
->returnUserType();
853 if (retTypeSD
&& retTypeSD
->size()) {
854 auto ret
= const_cast<StringData
*>(retTypeSD
);
860 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getRetTypeInfo
) {
861 DictInit retTypeInfo
{3};
862 auto name
= HHVM_MN(ReflectionFunctionAbstract
, getReturnTypeHint
)(this_
);
863 if (name
&& !name
.empty()) {
864 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
865 auto retType
= func
->returnTypeConstraint();
866 if (retType
.isNullable()) {
867 retTypeInfo
.set(s_type_hint_nullable
, make_tv
<KindOfBoolean
>(true));
869 retTypeInfo
.set(s_type_hint_nullable
, make_tv
<KindOfBoolean
>(false));
873 retType
.isCallable() || // callable type hint is considered builtin
874 (retType
.underlyingDataType() &&
875 retType
.underlyingDataType() != KindOfObject
878 retTypeInfo
.set(s_type_hint_builtin
, make_tv
<KindOfBoolean
>(true));
880 retTypeInfo
.set(s_type_hint_builtin
, make_tv
<KindOfBoolean
>(false));
883 name
= staticEmptyString();
884 retTypeInfo
.set(s_type_hint_nullable
, make_tv
<KindOfBoolean
>(false));
885 retTypeInfo
.set(s_type_hint_builtin
, make_tv
<KindOfBoolean
>(false));
887 retTypeInfo
.set(s_type_hint
, name
);
888 return retTypeInfo
.toArray();
893 const Array
reified_generics_info_to_array(const ReifiedGenericsInfo
& info
) {
894 VecInit
arr(info
.m_typeParamInfo
.size());
895 for (auto tparam
: info
.m_typeParamInfo
) {
896 DictInit
tparamArr(3);
897 tparamArr
.set(s_is_reified
, make_tv
<KindOfBoolean
>(tparam
.m_isReified
));
898 tparamArr
.set(s_is_soft
, make_tv
<KindOfBoolean
>(tparam
.m_isSoft
));
899 tparamArr
.set(s_is_warn
, make_tv
<KindOfBoolean
>(tparam
.m_isWarn
));
900 arr
.append(tparamArr
.toArray());
902 return arr
.toArray();
907 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getReifiedTypeParamInfo
) {
908 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
909 return reified_generics_info_to_array(func
->getReifiedGenericsInfo());
912 const StaticString
s_pure("pure");
913 const StaticString
s_defaults("defaults");
915 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getCoeffects
) {
916 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
917 std::vector
<LowStringPtr
> result
;
918 for (auto const& name
: func
->staticCoeffectNames()) {
919 if (name
->equal(s_pure
.get())) continue;
920 result
.push_back(name
);
922 if (func
->staticCoeffectNames().empty()) {
923 result
.push_back(makeStaticString(s_defaults
.get()));
925 if (func
->hasCoeffectRules()) {
926 for (auto const& rule
: func
->getCoeffectRules()) {
927 auto const name
= rule
.toString(func
);
928 if (name
) result
.push_back(makeStaticString(*name
));
931 VecInit
arr(result
.size());
932 for (auto& name
: result
) arr
.append(make_tv
<KindOfPersistentString
>(name
));
933 return arr
.toArray();
936 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getModule
) {
937 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
938 auto const name
= func
->unit()->moduleName();
939 if (!name
) return init_null_variant
;
940 return String::attach(const_cast<StringData
*>(name
));
943 static bool HHVM_METHOD(ReflectionFunctionAbstract
, returnsReadonly
) {
944 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
945 return func
->attrs() & AttrReadonlyReturn
;
949 static Array
get_function_user_attributes(const Func
* func
) {
950 auto userAttrs
= func
->userAttributes();
952 DictInit
ai(userAttrs
.size());
953 for (auto it
= userAttrs
.begin(); it
!= userAttrs
.end(); ++it
) {
954 ai
.set(StrNR(it
->first
).asString(), it
->second
);
959 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getAttributesNamespaced
) {
960 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
961 return get_function_user_attributes(func
);
964 // ------------------------- class ReflectionMethod
966 // helper for __construct
967 static bool HHVM_METHOD(ReflectionMethod
, __init
,
968 const Variant
& cls_or_object
, const String
& meth_name
) {
969 auto const cls
= get_cls(cls_or_object
);
970 if (!cls
|| meth_name
.isNull()) {
971 // caller raises exception
974 auto const func
= get_method_func(cls
, meth_name
);
976 // caller raises exception
979 assertx(func
->isMethod());
980 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
984 static bool HHVM_METHOD(ReflectionMethod
, isFinal
) {
985 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
986 return func
->attrs() & AttrFinal
;
989 static bool HHVM_METHOD(ReflectionMethod
, isAbstract
) {
990 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
991 return func
->attrs() & AttrAbstract
;
994 static bool HHVM_METHOD(ReflectionMethod
, isPublic
) {
995 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
996 return func
->attrs() & AttrPublic
;
999 static bool HHVM_METHOD(ReflectionMethod
, isProtected
) {
1000 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1001 return func
->attrs() & AttrProtected
;
1004 static bool HHVM_METHOD(ReflectionMethod
, isPrivate
) {
1005 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1006 return func
->attrs() & AttrPrivate
;
1009 static bool HHVM_METHOD(ReflectionMethod
, isStatic
) {
1010 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1011 return func
->attrs() & AttrStatic
;
1014 static bool HHVM_METHOD(ReflectionMethod
, isStaticInPrologue
) {
1015 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1016 return func
->isStaticInPrologue();
1019 static bool HHVM_METHOD(ReflectionMethod
, isConstructor
) {
1020 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1021 return isConstructor(func
);
1024 static bool HHVM_METHOD(ReflectionMethod
, isReadonly
) {
1025 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1026 return func
->attrs() & AttrReadonlyThis
;
1029 static int64_t HHVM_METHOD(ReflectionMethod
, getModifiers
) {
1030 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1031 return get_modifiers(func
->attrs(), false, false);
1034 // private helper for getPrototype
1035 static String
HHVM_METHOD(ReflectionMethod
, getPrototypeClassname
) {
1036 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1037 const Class
*prototypeCls
= nullptr;
1038 if (func
->baseCls() != nullptr && func
->baseCls() != func
->implCls()) {
1039 prototypeCls
= func
->baseCls();
1040 const Class
*result
= get_prototype_class_from_interfaces(
1041 prototypeCls
, func
);
1042 if (result
) { prototypeCls
= result
; }
1043 } else if (func
->isMethod()) {
1044 // lookup the prototype in the interfaces
1045 prototypeCls
= get_prototype_class_from_interfaces(func
->implCls(), func
);
1048 auto ret
= const_cast<StringData
*>(prototypeCls
->name());
1054 // private helper for getDeclaringClass
1055 static String
HHVM_METHOD(ReflectionMethod
, getDeclaringClassname
) {
1056 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
1057 auto ret
= const_cast<StringData
*>(func
->implCls()->name());
1061 // ------------------------- class ReflectionFile
1063 const StaticString
s_ReflectionFileHandle("ReflectionFileHandle");
1065 // helper for __construct
1066 static String
HHVM_METHOD(ReflectionFile
, __init
, const String
& name
) {
1067 if (name
.isNull()) {
1068 Reflection::ThrowReflectionExceptionObject(
1069 "Tried to construct ReflectionFile but the name was null"
1073 const Unit
* unit
= lookupUnit(
1074 File::TranslatePath(name
).get(),
1077 Native::s_noNativeFuncs
,
1082 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1083 "File '{}' does not exist",
1088 ReflectionFileHandle::Get(this_
)->setUnit(unit
);
1090 return String::attach(const_cast<StringData
*>(unit
->filepath()));
1093 static Array
HHVM_METHOD(ReflectionFile
, getAttributesNamespaced
) {
1094 auto const unit
= ReflectionFileHandle::GetUnitFor(this_
);
1097 auto fileAttrs
= unit
->fileAttributes();
1098 DictInit
ai(fileAttrs
.size());
1100 for (auto it
= fileAttrs
.begin(); it
!= fileAttrs
.end(); ++it
) {
1101 ai
.set(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
1103 return ai
.toArray();
1106 // ------------------------- class ReflectionModule
1108 const StaticString
s_ReflectionModuleHandle("ReflectionModuleHandle");
1110 // helper for __construct
1111 static String
HHVM_METHOD(ReflectionModule
, __init
, const String
& name
) {
1112 if (name
.isNull()) {
1113 Reflection::ThrowReflectionExceptionObject(
1114 "Tried to construct ReflectionModule but the name was null"
1118 const Module
* module
= Module::lookup(name
.get());
1120 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1121 "Module '{}' does not exist",
1126 ReflectionModuleHandle::Get(this_
)->setModule(module
);
1127 return String::attach(const_cast<StringData
*>(module
->name
.get()));
1130 static Array
HHVM_METHOD(ReflectionModule
, getAttributesNamespaced
) {
1131 auto const module
= ReflectionModuleHandle::GetModuleFor(this_
);
1134 auto userAttrs
= module
->userAttributes
;
1135 DictInit
ai(userAttrs
.size());
1136 for (auto const& attr
: userAttrs
) {
1137 ai
.set(StrNR(attr
.first
), attr
.second
);
1139 return ai
.toArray();
1142 // ------------------------- class ReflectionFunction
1144 // helper for __construct
1145 static bool HHVM_METHOD(ReflectionFunction
, __initName
, const String
& name
) {
1146 if (name
.isNull()) { return false; }
1147 const Func
* func
= Func::load(name
.get());
1148 if (!func
) { return false; }
1149 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
1153 // helper for __construct
1154 static bool HHVM_METHOD(ReflectionFunction
, __initClosure
,
1155 const Object
& closure
) {
1156 auto const cls
= get_cls(closure
);
1158 if (!cls
) { return false; }
1159 const Func
* func
= cls
->lookupMethod(s___invoke
.get());
1161 // caller raises exception
1164 assertx(func
->isClosureBody());
1165 assertx(func
->implCls()->isScopedClosure());
1166 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
1170 const StaticString
s_ExpectedClosureInstance("Expected closure instance");
1172 // helper for getClosureScopeClass
1173 static Variant
HHVM_METHOD(ReflectionFunction
, getClosureScopeClassname
,
1174 const Object
& closure
) {
1175 if (!closure
->instanceof(c_Closure::classof())) {
1176 SystemLib::throwExceptionObject(s_ExpectedClosureInstance
);
1178 if (auto scope
= c_Closure::fromObject(closure
.get())->getScope()) {
1179 return String(const_cast<StringData
*>(scope
->name()));
1181 return init_null_variant
;
1184 static Variant
HHVM_METHOD(ReflectionFunction
, getClosureThisObject
,
1185 const Object
& closure
) {
1186 if (!closure
->instanceof(c_Closure::classof())) {
1187 SystemLib::throwExceptionObject(s_ExpectedClosureInstance
);
1189 auto const clos
= c_Closure::fromObject(closure
.get());
1190 if (clos
->hasThis()) {
1191 return Object
{clos
->getThis()};
1193 return init_null_variant
;
1196 /////////////////////////////////////////////////////////////////////////////
1197 // class ReflectionClass
1199 const StaticString
s_ReflectionClassHandle("ReflectionClassHandle");
1201 // helper for __construct
1202 static String
HHVM_METHOD(ReflectionClass
, __init
, const String
& name
) {
1203 return ReflectionClassHandle::Get(this_
)->init(name
);
1206 static String
HHVM_METHOD(ReflectionClass
, getName
) {
1207 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1208 return cls
->nameStr();
1211 static String
HHVM_METHOD(ReflectionClass
, getParentName
) {
1212 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1213 return cls
->parentStr();
1216 static bool HHVM_METHOD(ReflectionClass
, isHack
) {
1220 static bool HHVM_METHOD(ReflectionClass
, isInternal
) {
1221 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1222 return cls
->attrs() & AttrBuiltin
;
1225 static bool HHVM_METHOD(ReflectionClass
, isInstantiable
) {
1226 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1227 return !(cls
->attrs() & (AttrAbstract
| AttrInterface
| AttrTrait
| AttrEnum
|
1229 && (cls
->getCtor()->attrs() & AttrPublic
);
1232 static bool HHVM_METHOD(ReflectionClass
, isFinal
) {
1233 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1234 return cls
->attrs() & AttrFinal
;
1237 static bool HHVM_METHOD(ReflectionClass
, isInternalToModule
) {
1238 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1239 return cls
->attrs() & AttrInternal
;
1242 static bool HHVM_METHOD(ReflectionClass
, isAbstract
) {
1243 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1244 return cls
->attrs() & AttrAbstract
;
1247 static bool HHVM_METHOD(ReflectionClass
, isInterface
) {
1248 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1249 return cls
->attrs() & AttrInterface
;
1252 static bool HHVM_METHOD(ReflectionClass
, isTrait
) {
1253 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1254 return cls
->attrs() & AttrTrait
;
1257 static bool HHVM_METHOD(ReflectionClass
, isEnum
) {
1258 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1259 return cls
->attrs() & (AttrEnum
|AttrEnumClass
);
1262 static String
HHVM_METHOD(ReflectionClass
, getEnumUnderlyingType
) {
1263 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1264 if (!(cls
->attrs() & (AttrEnum
|AttrEnumClass
))) {
1265 Reflection::ThrowReflectionExceptionObject(
1266 "Trying to read the Enum-type of a non-Enum");
1269 // use the unresolved preclass type to yield the userland types
1270 return StrNR(cls
->preClass()->enumBaseTy().typeName());
1273 static int64_t HHVM_METHOD(ReflectionClass
, getModifiers
) {
1274 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1275 return get_modifiers(cls
->attrs(), true, false);
1278 static TypedValue
HHVM_METHOD(ReflectionClass
, getFileName
) {
1279 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1280 if (cls
->attrs() & AttrBuiltin
) {
1281 return make_tv
<KindOfBoolean
>(false);
1283 auto file
= cls
->preClass()->unit()->filepath();
1284 if (!file
) file
= staticEmptyString();
1285 if (file
->data()[0] != '/') {
1286 auto path
= SourceRootInfo::RelativeToPhpRoot(StrNR(file
));
1287 return make_tv
<KindOfString
>(path
.detach());
1289 assertx(!file
->isRefCounted());
1290 return make_tv
<KindOfPersistentString
>(file
);
1293 static Variant
HHVM_METHOD(ReflectionClass
, getStartLine
) {
1294 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1295 if (cls
->isBuiltin()) {
1298 return cls
->preClass()->line1();
1301 static Variant
HHVM_METHOD(ReflectionClass
, getEndLine
) {
1302 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1303 if (cls
->isBuiltin()) {
1306 return cls
->preClass()->line2();
1309 static TypedValue
HHVM_METHOD(ReflectionClass
, getDocComment
) {
1310 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1311 auto const pcls
= cls
->preClass();
1312 auto const comment
= pcls
->docComment();
1313 if (comment
== nullptr || comment
->empty()) {
1314 return make_tv
<KindOfBoolean
>(false);
1316 assertx(!comment
->isRefCounted());
1317 return make_tv
<KindOfPersistentString
>(const_cast<StringData
*>(comment
));
1321 static Array
HHVM_METHOD(ReflectionClass
, getRequirementNames
) {
1322 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1323 if (!(cls
->attrs() & (AttrTrait
| AttrInterface
))) {
1324 // requirements are applied to abstract/concrete classes when they use
1325 // a trait / implement an interface
1326 return empty_vec_array();
1329 auto const& requirements
= cls
->allRequirements();
1330 auto numReqs
= requirements
.size();
1332 return empty_vec_array();
1335 VecInit
pai(numReqs
);
1336 for (int i
= 0; i
< numReqs
; ++i
) {
1337 auto const& req
= requirements
[i
];
1338 pai
.append(Variant
{const_cast<StringData
*>(req
->name())});
1340 return pai
.toArray();
1343 static Array
HHVM_METHOD(ReflectionClass
, getInterfaceNames
) {
1344 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1346 auto st
= req::make
<c_Set
>();
1347 auto const& allIfaces
= cls
->allInterfaces();
1348 st
->reserve(allIfaces
.size());
1350 for (auto const& interface
: cls
->declInterfaces()) {
1351 st
->add(const_cast<StringData
*>(interface
->name()));
1353 if (allIfaces
.size() > cls
->declInterfaces().size()) {
1354 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1355 auto const& interface
= allIfaces
[i
];
1356 st
->add(const_cast<StringData
*>(interface
->name()));
1359 return st
->toVArray();
1362 static Array
HHVM_METHOD(ReflectionClass
, getTraitNames
) {
1363 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1364 auto const& traits
= cls
->preClass()->usedTraits();
1365 VecInit
ai(traits
.size());
1366 for (const StringData
* traitName
: traits
) {
1367 ai
.append(Variant
{const_cast<StringData
*>(traitName
)});
1369 return ai
.toArray();
1372 static Array
get_trait_alias_info(const Class
* cls
) {
1373 auto const& aliases
= cls
->traitAliases();
1375 if (aliases
.size()) {
1376 DictInit
ai(aliases
.size());
1378 for (auto const& namePair
: aliases
) {
1379 ai
.set(StrNR(namePair
.first
), VarNR(namePair
.second
).tv());
1381 return ai
.toArray();
1383 // Even if we have alias rules, if we're in repo mode, they will be applied
1384 // during the trait flattening step, and we won't populate traitAliases()
1386 auto const& rules
= cls
->preClass()->traitAliasRules();
1388 DictInit
ai(rules
.size());
1390 for (auto const& rule
: rules
) {
1391 auto namePair
= rule
.asNamePair();
1392 ai
.set(StrNR(namePair
.first
), VarNR(namePair
.second
).tv());
1394 return ai
.toArray();
1398 static Array
HHVM_METHOD(ReflectionClass
, getTraitAliases
) {
1399 return get_trait_alias_info(ReflectionClassHandle::GetClassFor(this_
));
1402 static bool HHVM_METHOD(ReflectionClass
, hasMethod
, const String
& name
) {
1403 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1404 return (get_method_func(cls
, name
) != nullptr);
1408 const Class
* get_class_from_name(const String
& name
) {
1409 auto const cls
= Class::load(name
.get());
1411 auto message
= folly::sformat(
1412 "class {} could not be loaded",
1415 Reflection::ThrowReflectionExceptionObject(message
);
1421 // helper for getMethods: returns a keyset
1422 static Array
HHVM_STATIC_METHOD(
1425 const String
& clsname
,
1427 auto const cls
= get_class_from_name(clsname
);
1428 Attr mask
= attrs_from_modifiers(filter
, false);
1430 // At each step, we fetch from the PreClass is important because the
1431 // order in which getMethods returns matters
1432 req::StringIFastSet visitedMethods
;
1433 req::StringIFastSet visitedInterfaces
;
1434 auto st
= Array::CreateKeyset();
1436 auto add
= [&] (const Func
* m
) {
1437 if (m
->isGenerated()) return;
1438 if (!visitedMethods
.insert(m
->nameStr()).second
) return;
1439 if (m
->attrs() & mask
) {
1440 st
.append(m
->nameStr().asString());
1444 std::function
<void(const Class
*)> collect
;
1445 std::function
<void(const Class
*)> collectInterface
;
1447 collect
= [&] (const Class
* clas
) {
1450 auto const methods
= clas
->preClass()->methods();
1451 auto const numMethods
= clas
->preClass()->numMethods();
1453 auto numDeclMethods
= clas
->preClass()->numDeclMethods();
1454 if (numDeclMethods
== -1) numDeclMethods
= numMethods
;
1456 // Add declared methods.
1457 for (Slot i
= 0; i
< numDeclMethods
; ++i
) {
1461 // Recurse; we need to order the parent's methods before our trait methods.
1462 collect(clas
->parent());
1464 for (Slot i
= numDeclMethods
; i
< numMethods
; ++i
) {
1465 // For repo mode, where trait methods are flattened at compile-time.
1468 for (Slot i
= clas
->traitsBeginIdx(); i
< clas
->traitsEndIdx(); ++i
) {
1469 // For non-repo mode, where they are added at Class-creation time.
1470 add(clas
->getMethod(i
));
1474 collectInterface
= [&] (const Class
* iface
) {
1476 if (!visitedInterfaces
.insert(iface
->nameStr()).second
) return;
1478 size_t const numMethods
= iface
->preClass()->numMethods();
1479 Func
* const* methods
= iface
->preClass()->methods();
1480 for (Slot i
= 0; i
< numMethods
; ++i
) {
1484 for (auto const& parentIface
: iface
->declInterfaces()) {
1485 collectInterface(parentIface
.get());
1487 auto const& allIfaces
= iface
->allInterfaces();
1488 if (allIfaces
.size() > iface
->declInterfaces().size()) {
1489 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1490 collectInterface(allIfaces
[i
].get());
1495 collect(const_cast<Class
*>(cls
));
1497 // concrete classes should already have all of their methods present
1498 if (((AttrPublic
| AttrAbstract
| AttrStatic
) & mask
) &&
1499 cls
->attrs() & (AttrInterface
| AttrAbstract
| AttrTrait
)) {
1500 for (auto const& interface
: cls
->declInterfaces()) {
1501 collectInterface(interface
.get());
1503 auto const& allIfaces
= cls
->allInterfaces();
1504 if (allIfaces
.size() > cls
->declInterfaces().size()) {
1505 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1506 auto const& interface
= allIfaces
[i
];
1507 collectInterface(interface
.get());
1514 static bool HHVM_METHOD(ReflectionClass
, hasConstant
, const String
& name
) {
1515 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1516 return cls
->hasConstant(name
.get());
1519 static TypedValue
HHVM_METHOD(ReflectionClass
, getConstant
, const String
& name
) {
1520 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1521 auto value
= cls
->clsCnsGet(name
.get());
1522 if (value
.m_type
== KindOfUninit
) return make_tv
<KindOfBoolean
>(false);
1528 void addClassConstantNames(const Class
* cls
,
1529 const req::ptr
<c_Set
>& st
,
1531 assertx(cls
&& st
&& (st
->size() < limit
));
1533 auto numConsts
= cls
->numConstants();
1535 const Class::Const
* consts
= cls
->constants();
1536 for (size_t i
= 0; i
< numConsts
; i
++) {
1537 if (consts
[i
].cls
== cls
&& !consts
[i
].isAbstractAndUninit()
1538 && consts
[i
].kind() == ConstModifiers::Kind::Value
) {
1539 st
->add(const_cast<StringData
*>(consts
[i
].name
.get()));
1543 auto const& allTraits
= cls
->usedTraitClasses();
1544 auto const numTraits
= allTraits
.size();
1545 for (int i
= 0; i
< numTraits
&& (st
->size() < limit
); ++i
) {
1546 addClassConstantNames(allTraits
[i
].get(), st
, limit
);
1549 if ((st
->size() < limit
) && cls
->parent()) {
1550 addClassConstantNames(cls
->parent(), st
, limit
);
1553 auto const& allIfaces
= cls
->allInterfaces();
1554 auto const numIfaces
= allIfaces
.size();
1555 for (int i
= 0; i
< numIfaces
&& (st
->size() < limit
); ++i
) {
1556 addClassConstantNames(allIfaces
[i
].get(), st
, limit
);
1560 // helper for getConstants
1561 static Array
HHVM_STATIC_METHOD(
1563 getOrderedConstants
,
1564 const String
& clsname
) {
1565 auto const cls
= get_class_from_name(clsname
);
1567 size_t numConsts
= cls
->numConstants();
1569 return empty_dict_array();
1572 auto st
= req::make
<c_Set
>();
1573 st
->reserve(numConsts
);
1575 addClassConstantNames(cls
, st
, numConsts
);
1576 assertx(st
->size() <= numConsts
);
1578 DictInit
ai(numConsts
);
1579 IterateV(st
->arrayData(), [&](TypedValue k
) {
1580 auto constName
= val(k
).pstr
;
1581 auto value
= cls
->clsCnsGet(constName
);
1582 assertx(type(value
) != KindOfUninit
);
1583 ai
.set(constName
, value
);
1585 return ai
.toArray();
1589 // helper for getOrdered*Constants
1590 template <typename Fn
>
1591 static Array
orderedConstantsHelper(const Class
* cls
, Fn filterFn
) {
1592 auto const numConsts
= cls
->numConstants();
1594 return empty_dict_array();
1597 auto st
= KeysetInit
{numConsts
};
1598 auto const consts
= cls
->constants();
1599 for (size_t i
= 0; i
< numConsts
; i
++) {
1600 auto const& konst
= consts
[i
];
1601 if (filterFn(konst
)) {
1602 st
.add(make_tv
<KindOfPersistentString
>(konst
.name
.get()));
1606 auto ret
= st
.create()->toDict(false /*copy*/);
1607 assertx(ret
->size() <= numConsts
);
1608 return Array::attach(std::move(ret
));
1612 static Array
HHVM_STATIC_METHOD(
1614 getOrderedAbstractConstants
,
1615 const String
& clsname
1617 return orderedConstantsHelper(
1618 get_class_from_name(clsname
),
1619 [](Class::Const c
) -> bool {
1620 return c
.isAbstractAndUninit() && c
.kind() == ConstModifiers::Kind::Value
;
1625 static Array
HHVM_STATIC_METHOD(
1627 getOrderedTypeConstants
,
1628 const String
& clsname
1630 return orderedConstantsHelper(
1631 get_class_from_name(clsname
),
1632 [](Class::Const c
) -> bool {
1633 return c
.kind() == ConstModifiers::Kind::Type
;
1638 static Array
HHVM_METHOD(ReflectionClass
, getAttributesNamespaced
) {
1639 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1640 // UserAttributes are stored exclusively on the PreClass.
1641 auto const pcls
= cls
->preClass();
1643 auto userAttrs
= pcls
->userAttributes();
1644 DictInit
ai(userAttrs
.size());
1645 for (auto const& attr
: userAttrs
) {
1646 ai
.set(StrNR(attr
.first
), attr
.second
);
1648 return ai
.toArray();
1651 static Array
HHVM_METHOD(ReflectionClass
, getAttributesRecursiveNamespaced
) {
1652 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1654 Array ret
= Array::CreateDict(); // no reasonable idea about sizing
1656 // UserAttributes are stored in the PreClass, so we must walk the parent
1657 // chain to get all of them; attribute specifications from child classes
1658 // win over parents.
1660 // const pointer to Class => pointer to a (const) Class
1661 Class
* currentCls
= const_cast<Class
*>(cls
);
1663 auto const pcls
= currentCls
->preClass();
1664 for (auto it
= pcls
->userAttributes().begin();
1665 it
!= pcls
->userAttributes().end(); ++it
) {
1666 if (!ret
.exists(StrNR(it
->first
))) {
1667 ret
.set(StrNR(it
->first
), it
->second
);
1670 } while ((currentCls
= currentCls
->parent()));
1675 static Array
HHVM_METHOD(ReflectionClass
, getReifiedTypeParamInfo
) {
1676 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1677 return reified_generics_info_to_array(cls
->getReifiedGenericsInfo());
1680 static Array
HHVM_STATIC_METHOD(
1682 getClassPropertyInfo
,
1683 const String
& clsname
) {
1685 * FIXME: This implementation is pretty horrible and should be rewritten
1686 * when ReflectionProperty is ported.
1688 auto const cls
= get_class_from_name(clsname
);
1689 auto const properties
= cls
->declProperties();
1691 auto const& propInitVec
= cls
->getPropData()
1692 ? *cls
->getPropData()
1693 : cls
->declPropInit();
1695 auto ret
= Array::CreateDict();
1696 for (auto const& declProp
: properties
) {
1697 auto slot
= declProp
.serializationIdx
;
1698 auto index
= cls
->propSlotToIndex(slot
);
1699 auto const& prop
= properties
[slot
];
1700 auto const default_val
= propInitVec
[index
].val
.tv();
1701 if (((prop
.attrs
& AttrPrivate
) == AttrPrivate
) && (prop
.cls
!= cls
)) {
1705 auto info
= Array::CreateDict();
1706 set_instance_prop_info(info
, &prop
, default_val
);
1707 ret
.set(StrNR(prop
.name
), VarNR(info
).tv());
1710 // static properties
1711 auto const sProperties
= cls
->staticProperties();
1712 for (auto const& sProp
: sProperties
) {
1713 auto slot
= sProp
.serializationIdx
;
1714 auto const& prop
= sProperties
[slot
];
1715 if (((prop
.attrs
& AttrPrivate
) == AttrPrivate
) && (prop
.cls
!= cls
)) {
1719 auto info
= Array::CreateDict();
1720 set_static_prop_info(info
, &prop
);
1721 ret
.set(StrNR(prop
.name
), VarNR(info
).tv());
1726 static Array
HHVM_METHOD(ReflectionClass
, getDynamicPropertyInfos
,
1727 const Object
& obj
) {
1728 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1729 auto obj_data
= obj
.get();
1730 assertx(obj_data
->getVMClass() == cls
);
1731 if (!obj_data
->hasDynProps()) {
1732 return empty_dict_array();
1735 auto const dynPropArray
= obj_data
->dynPropArray();
1736 DictInit ret
{dynPropArray
->size()};
1737 IterateKV(dynPropArray
.get(), [&](TypedValue k
, TypedValue
) {
1738 if (RuntimeOption::EvalNoticeOnReadDynamicProp
) {
1739 auto const key
= tvCastToString(k
);
1740 obj_data
->raiseReadDynamicProp(key
.get());
1742 auto info
= Array::CreateDict();
1743 set_dyn_prop_info(info
, k
, cls
->name());
1744 ret
.setValidKey(k
, VarNR(info
).tv());
1746 return ret
.toArray();
1749 static String
HHVM_METHOD(ReflectionClass
, getConstructorName
) {
1750 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1751 auto ctor
= cls
->getDeclaredCtor();
1752 if (!ctor
) { return String(); }
1753 auto ret
= const_cast<StringData
*>(ctor
->name());
1757 void ReflectionClassHandle::wakeup(const Variant
& content
, ObjectData
* obj
) {
1758 if (!content
.isString()) {
1759 throw Exception("Native data of ReflectionClass should be a class name");
1762 String clsName
= content
.toString();
1763 String result
= init(clsName
);
1764 if (result
.empty()) {
1765 auto msg
= folly::format("Class {} does not exist", clsName
).str();
1766 Reflection::ThrowReflectionExceptionObject(String(msg
));
1769 // It is possible that $name does not get serialized. If a class derives
1770 // from ReflectionClass and the return value of its __sleep() function does
1771 // not contain 'name', $name gets ignored. So, we restore $name here.
1772 obj
->setProp(nullptr, s_name
.get(), result
.asTypedValue());
1775 static Variant
reflection_extension_name_get(const Object
& this_
) {
1776 assertx(Reflection::s_ReflectionExtensionClass
);
1777 auto const name
= this_
->getProp(
1778 Reflection::s_ReflectionExtensionClass
,
1781 return tvCastToString(name
.tv());
1784 static Native::PropAccessor reflection_extension_Accessors
[] = {
1785 {"name", reflection_extension_name_get
,
1786 nullptr, nullptr, nullptr}, // name is read only
1787 {nullptr, nullptr, nullptr, nullptr, nullptr}
1790 static Native::PropAccessorMap reflection_extension_accessorsMap
1791 ((Native::PropAccessor
*)reflection_extension_Accessors
);
1793 struct reflection_extension_PropHandler
:
1794 Native::MapPropHandler
<reflection_extension_PropHandler
> {
1796 static constexpr Native::PropAccessorMap
& map
=
1797 reflection_extension_accessorsMap
;
1800 /////////////////////////////////////////////////////////////////////////////
1801 // class ReflectionTypeConstant
1803 const StaticString
s_ReflectionConstHandle("ReflectionConstHandle");
1805 // helper for __construct
1806 static bool HHVM_METHOD(ReflectionTypeConstant
, __init
,
1807 const Variant
& cls_or_obj
, const String
& const_name
) {
1808 auto const cls
= get_cls(cls_or_obj
);
1809 if (!cls
|| const_name
.isNull()) {
1810 // caller raises exception
1814 size_t numConsts
= cls
->numConstants();
1815 const Class::Const
* consts
= cls
->constants();
1817 for (size_t i
= 0; i
< numConsts
; i
++) {
1818 if (const_name
.same(consts
[i
].name
)
1819 && consts
[i
].kind() == ConstModifiers::Kind::Type
) {
1820 auto handle
= ReflectionConstHandle::Get(this_
);
1821 handle
->setConst(&consts
[i
]);
1822 handle
->setClass(cls
);
1827 // caller raises exception
1831 static String
HHVM_METHOD(ReflectionTypeConstant
, getName
) {
1832 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1833 auto ret
= const_cast<StringData
*>(cns
->name
.get());
1837 static bool HHVM_METHOD(ReflectionTypeConstant
, isAbstract
) {
1838 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1839 if (RO::EvalTypeconstAbstractDefaultReflectionIsAbstract
) {
1840 return cns
->isAbstract();
1842 return cns
->isAbstractAndUninit();
1846 // helper for getAssignedTypeText
1847 static String
HHVM_METHOD(ReflectionTypeConstant
, getAssignedTypeHint
) {
1848 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1850 if (isStringType(cns
->val
.m_type
)) {
1851 return String(cns
->val
.m_data
.pstr
);
1854 if (isArrayLikeType(cns
->val
.m_type
)) {
1855 auto const cls
= cns
->cls
;
1856 // go to the preclass to find the unresolved TypeStructure to get
1857 // the original assigned type text
1858 auto const preCls
= cls
->preClass();
1859 auto typeCns
= preCls
->lookupConstant(cns
->name
);
1860 assertx(typeCns
->kind() == ConstModifiers::Kind::Type
);
1861 assertx(!typeCns
->isAbstractAndUninit());
1862 assertx(isArrayLikeType(typeCns
->val().m_type
));
1863 return TypeStructure::toString(Array::attach(typeCns
->val().m_data
.parr
),
1864 TypeStructure::TSDisplayType::TSDisplayTypeReflection
);
1870 // private helper for getDeclaringClass
1871 static String
HHVM_METHOD(ReflectionTypeConstant
, getDeclaringClassname
) {
1872 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1873 auto cls
= cns
->cls
;
1874 auto ret
= const_cast<StringData
*>(cls
->name());
1878 // private helper for getClass
1879 static String
HHVM_METHOD(ReflectionTypeConstant
, getClassname
) {
1880 auto const cls
= ReflectionConstHandle::GetClassFor(this_
);
1881 auto ret
= const_cast<StringData
*>(cls
->name());
1885 /////////////////////////////////////////////////////////////////////////////
1886 // class ReflectionProperty
1888 const StaticString
s_ReflectionPropHandle("ReflectionPropHandle");
1890 static void HHVM_METHOD(ReflectionProperty
, __construct
,
1891 const Variant
& cls_or_obj
, const String
& prop_name
) {
1892 auto const cls
= get_cls(cls_or_obj
);
1894 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1895 "Class {} does not exist",
1896 cls_or_obj
.toString().toCppString()
1899 if (prop_name
.isNull()) {
1900 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1901 "Property {}:: does not exist",
1902 cls
->name()->toCppString()
1906 auto data
= Native::data
<ReflectionPropHandle
>(this_
);
1908 // is there a declared instance property?
1909 auto lookup
= cls
->getDeclPropSlot(cls
, prop_name
.get());
1910 auto propIdx
= lookup
.slot
;
1911 if (propIdx
!= kInvalidSlot
) {
1912 auto const prop
= &cls
->declProperties()[propIdx
];
1913 data
->setInstanceProp(prop
);
1914 this_
->setProp(nullptr, s_class
.get(),
1915 make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
1916 this_
->setProp(nullptr, s_name
.get(),
1917 make_tv
<KindOfPersistentString
>(prop
->name
));
1921 // is there a declared static property?
1922 lookup
= cls
->findSProp(cls
, prop_name
.get());
1923 propIdx
= lookup
.slot
;
1924 if (propIdx
!= kInvalidSlot
) {
1925 auto const prop
= &cls
->staticProperties()[propIdx
];
1926 data
->setStaticProp(prop
);
1927 this_
->setProp(nullptr, s_class
.get(),
1928 make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
1929 this_
->setProp(nullptr, s_name
.get(),
1930 make_tv
<KindOfPersistentString
>(prop
->name
));
1934 // is there a dynamic property?
1935 if (cls_or_obj
.is(KindOfObject
)) {
1936 auto obj
= cls_or_obj
.asCObjRef().get();
1937 assertx(cls
== obj
->getVMClass());
1938 if (obj
->getAttribute(ObjectData::HasDynPropArr
) &&
1939 obj
->dynPropArray().exists(
1940 obj
->dynPropArray().convertKey
<IntishCast::Cast
>(prop_name
))
1942 if (RuntimeOption::EvalNoticeOnReadDynamicProp
) {
1943 obj
->raiseReadDynamicProp(prop_name
.get());
1945 data
->setDynamicProp();
1946 this_
->setProp(nullptr, s_class
.get(),
1947 make_tv
<KindOfPersistentString
>(cls
->name()));
1948 this_
->setProp(nullptr, s_name
.get(), prop_name
.asTypedValue());
1953 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1954 "Property {}::{} does not exist",
1955 cls
->name()->toCppString(),
1956 prop_name
.toCppString()
1962 [[noreturn
]] void reflection_property_internal_error() {
1963 raise_fatal_error("Internal error: Failed to retrieve the reflection object");
1968 static bool HHVM_METHOD(ReflectionProperty
, isPublic
) {
1969 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1970 switch (data
->getType()) {
1971 case ReflectionPropHandle::Type::Instance
:
1972 return data
->getProp()->attrs
& AttrPublic
;
1973 case ReflectionPropHandle::Type::Static
:
1974 return data
->getSProp()->attrs
& AttrPublic
;
1975 case ReflectionPropHandle::Type::Dynamic
:
1978 reflection_property_internal_error();
1982 static bool HHVM_METHOD(ReflectionProperty
, isProtected
) {
1983 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1984 switch (data
->getType()) {
1985 case ReflectionPropHandle::Type::Instance
:
1986 return data
->getProp()->attrs
& AttrProtected
;
1987 case ReflectionPropHandle::Type::Static
:
1988 return data
->getSProp()->attrs
& AttrProtected
;
1989 case ReflectionPropHandle::Type::Dynamic
:
1992 reflection_property_internal_error();
1996 static bool HHVM_METHOD(ReflectionProperty
, isPrivate
) {
1997 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1998 switch (data
->getType()) {
1999 case ReflectionPropHandle::Type::Instance
:
2000 return data
->getProp()->attrs
& AttrPrivate
;
2001 case ReflectionPropHandle::Type::Static
:
2002 return data
->getSProp()->attrs
& AttrPrivate
;
2003 case ReflectionPropHandle::Type::Dynamic
:
2006 reflection_property_internal_error();
2010 static bool HHVM_METHOD(ReflectionProperty
, isStatic
) {
2011 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2012 switch (data
->getType()) {
2013 case ReflectionPropHandle::Type::Static
:
2015 case ReflectionPropHandle::Type::Instance
:
2016 case ReflectionPropHandle::Type::Dynamic
:
2019 reflection_property_internal_error();
2023 static bool HHVM_METHOD(ReflectionProperty
, isInternalToModule
) {
2024 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2025 switch (data
->getType()) {
2026 case ReflectionPropHandle::Type::Instance
:
2027 return data
->getProp()->attrs
& AttrInternal
;
2028 case ReflectionPropHandle::Type::Static
:
2029 return data
->getSProp()->attrs
& AttrInternal
;
2030 case ReflectionPropHandle::Type::Dynamic
:
2033 reflection_property_internal_error();
2037 static bool HHVM_METHOD(ReflectionProperty
, isDefault
) {
2038 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2039 switch (data
->getType()) {
2040 case ReflectionPropHandle::Type::Instance
:
2041 case ReflectionPropHandle::Type::Static
:
2043 case ReflectionPropHandle::Type::Dynamic
:
2046 reflection_property_internal_error();
2050 static int64_t HHVM_METHOD(ReflectionProperty
, getModifiers
) {
2051 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2052 switch (data
->getType()) {
2053 case ReflectionPropHandle::Type::Instance
:
2054 return get_modifiers(data
->getProp()->attrs
, false, true);
2055 case ReflectionPropHandle::Type::Static
:
2056 return get_modifiers(data
->getSProp()->attrs
, false, true);
2057 case ReflectionPropHandle::Type::Dynamic
:
2058 return get_modifiers(AttrPublic
, false, true);
2060 reflection_property_internal_error();
2064 static TypedValue
HHVM_METHOD(ReflectionProperty
, getDocComment
) {
2065 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2066 const StringData
*comment
= nullptr;
2067 switch (data
->getType()) {
2068 case ReflectionPropHandle::Type::Instance
:
2069 comment
= data
->getProp()->preProp
->docComment();
2071 case ReflectionPropHandle::Type::Static
:
2072 comment
= data
->getSProp()->preProp
->docComment();
2074 case ReflectionPropHandle::Type::Dynamic
:
2077 reflection_property_internal_error();
2079 if (comment
== nullptr || comment
->empty()) {
2080 return tvReturn(false);
2082 Variant vComment
{comment
, Variant::PersistentStrInit
{}};
2083 return tvReturn(std::move(vComment
));
2087 static String
HHVM_METHOD(ReflectionProperty
, getTypeText
) {
2088 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2089 const StringData
*type
= nullptr;
2090 switch (data
->getType()) {
2091 case ReflectionPropHandle::Type::Instance
:
2092 type
= data
->getProp()->preProp
->userType();
2094 case ReflectionPropHandle::Type::Static
:
2095 type
= data
->getSProp()->preProp
->userType();
2097 case ReflectionPropHandle::Type::Dynamic
:
2100 reflection_property_internal_error();
2102 if (type
== nullptr || type
->empty()) {
2103 return empty_string();
2109 static TypedValue
HHVM_METHOD(ReflectionProperty
, getDefaultValue
) {
2110 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2111 switch (data
->getType()) {
2112 case ReflectionPropHandle::Type::Instance
: {
2113 auto const prop
= data
->getProp();
2114 // We can't get propIdx from prop->idx (that's not what that is) or by
2115 // doing prop - prop->cls->declProperties().begin() (the prop can be in
2116 // the prop vector of a child class but it will always point to the class
2117 // it was declared in); so if we don't want to store propIdx we have to
2118 // look it up by name.
2119 auto cls
= prop
->cls
;
2120 auto lookup
= cls
->getDeclPropSlot(cls
, prop
->name
);
2121 auto propSlot
= lookup
.slot
;
2122 assertx(propSlot
!= kInvalidSlot
);
2123 auto propIndex
= cls
->propSlotToIndex(propSlot
);
2125 auto const& propInitVec
= cls
->getPropData()
2126 ? *cls
->getPropData()
2127 : cls
->declPropInit();
2128 auto val
= VarNR
{propInitVec
[propIndex
].val
.tv()};
2129 return tvReturn(val
);
2131 case ReflectionPropHandle::Type::Static
: {
2132 auto const prop
= data
->getSProp();
2133 prop
->cls
->initialize();
2134 return tvReturn(tvAsCVarRef(&prop
->val
));
2136 case ReflectionPropHandle::Type::Dynamic
:
2137 return make_tv
<KindOfNull
>();
2139 reflection_property_internal_error();
2143 static Array
HHVM_METHOD(ReflectionProperty
, getAttributesNamespaced
) {
2144 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2145 auto attrs
= Array::CreateDict();
2146 switch (data
->getType()) {
2147 case ReflectionPropHandle::Type::Instance
: {
2148 auto const prop
= data
->getProp()->preProp
;
2149 for (auto attr
: prop
->userAttributes()) {
2150 attrs
.set(StrNR(attr
.first
), attr
.second
);
2154 case ReflectionPropHandle::Type::Static
: {
2155 auto const prop
= data
->getSProp()->preProp
;
2156 for (auto attr
: prop
->userAttributes()) {
2157 attrs
.set(StrNR(attr
.first
), attr
.second
);
2161 case ReflectionPropHandle::Type::Dynamic
:
2164 reflection_property_internal_error();
2168 static bool HHVM_METHOD(ReflectionProperty
, isReadonly
) {
2169 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2170 switch (data
->getType()) {
2171 case ReflectionPropHandle::Type::Instance
:
2172 return data
->getProp()->attrs
& AttrIsReadonly
;
2173 case ReflectionPropHandle::Type::Static
:
2174 return data
->getSProp()->attrs
& AttrIsReadonly
;
2175 case ReflectionPropHandle::Type::Dynamic
:
2178 reflection_property_internal_error();
2182 /////////////////////////////////////////////////////////////////////////////
2183 // class ReflectionTypeAlias
2185 const StaticString
s_ReflectionTypeAliasHandle("ReflectionTypeAliasHandle");
2187 // helper for __construct:
2188 // caller throws exception when return value is false
2189 static String
HHVM_METHOD(ReflectionTypeAlias
, __init
, const String
& name
) {
2190 auto const typeAlias
= TypeAlias::load(name
.get());
2193 return empty_string();
2196 ReflectionTypeAliasHandle::Get(this_
)->setTypeAlias(typeAlias
);
2197 return String::attach(const_cast<StringData
*>(typeAlias
->name()));
2200 static Array
HHVM_METHOD(ReflectionTypeAlias
, getTypeStructure
) {
2201 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasFor(this_
);
2203 auto const typeStructure
= req
->typeStructure();
2204 assertx(!typeStructure
.empty());
2205 assertx(typeStructure
.isDict());
2206 return typeStructure
;
2209 static String
HHVM_METHOD(ReflectionTypeAlias
, getAssignedTypeText
) {
2210 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasFor(this_
);
2212 auto const typeStructure
= req
->typeStructure();
2213 assertx(!typeStructure
.empty());
2214 assertx(typeStructure
.isDict());
2215 return TypeStructure::toString(typeStructure
,
2216 TypeStructure::TSDisplayType::TSDisplayTypeReflection
);
2219 static Array
HHVM_METHOD(ReflectionTypeAlias
, getAttributesNamespaced
) {
2220 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasFor(this_
);
2222 auto const userAttrs
= req
->userAttrs();
2224 DictInit
ai(userAttrs
.size());
2225 for (auto& attr
: userAttrs
) {
2226 ai
.set(StrNR(attr
.first
), tvAsCVarRef(&attr
.second
));
2228 return ai
.toArray();
2231 static String
HHVM_METHOD(ReflectionTypeAlias
, getFileName
) {
2232 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasFor(this_
);
2234 auto file
= req
->unit()->filepath();
2235 if (!file
) file
= staticEmptyString();
2236 if (file
->data()[0] != '/') {
2237 return SourceRootInfo::RelativeToPhpRoot(StrNR(file
));
2239 return String::attach(const_cast<StringData
*>(file
));
2242 ///////////////////////////////////////////////////////////////////////////////
2243 struct ReflectionExtension final
: Extension
{
2244 ReflectionExtension() : Extension("reflection", "$Id$") { }
2245 void moduleInit() override
{
2246 HHVM_FE(hphp_create_object
);
2247 HHVM_FE(hphp_create_object_without_constructor
);
2248 HHVM_FE(hphp_get_extension_info
);
2249 HHVM_FE(hphp_get_property
);
2250 HHVM_FE(hphp_get_static_property
);
2251 HHVM_FE(hphp_invoke
);
2252 HHVM_FE(hphp_invoke_method
);
2253 HHVM_FE(hphp_set_property
);
2254 HHVM_FE(hphp_set_static_property
);
2255 HHVM_FALIAS(HH
\\type_structure
, type_structure
);
2256 HHVM_FALIAS(HH
\\type_structure_no_throw
, type_structure_no_throw
);
2257 HHVM_FALIAS(HH
\\type_structure_classname
, type_structure_classname
);
2259 HHVM_ME(ReflectionFunctionAbstract
, getName
);
2260 HHVM_ME(ReflectionFunctionAbstract
, isHack
);
2261 HHVM_ME(ReflectionFunctionAbstract
, isInternal
);
2262 HHVM_ME(ReflectionFunctionAbstract
, isGenerator
);
2263 HHVM_ME(ReflectionFunctionAbstract
, isAsync
);
2264 HHVM_ME(ReflectionFunctionAbstract
, isInternalToModule
);
2265 HHVM_ME(ReflectionFunctionAbstract
, isVariadic
);
2266 HHVM_ME(ReflectionFunctionAbstract
, getFileName
);
2267 HHVM_ME(ReflectionFunctionAbstract
, getStartLine
);
2268 HHVM_ME(ReflectionFunctionAbstract
, getEndLine
);
2269 HHVM_ME(ReflectionFunctionAbstract
, getDocComment
);
2270 HHVM_ME(ReflectionFunctionAbstract
, getReturnTypeHint
);
2271 HHVM_ME(ReflectionFunctionAbstract
, getNumberOfParameters
);
2272 HHVM_ME(ReflectionFunctionAbstract
, getParamInfo
);
2273 HHVM_ME(ReflectionFunctionAbstract
, getAttributesNamespaced
);
2274 HHVM_ME(ReflectionFunctionAbstract
, getRetTypeInfo
);
2275 HHVM_ME(ReflectionFunctionAbstract
, getReifiedTypeParamInfo
);
2276 HHVM_ME(ReflectionFunctionAbstract
, getCoeffects
);
2277 HHVM_ME(ReflectionFunctionAbstract
, getModule
);
2278 HHVM_ME(ReflectionFunctionAbstract
, returnsReadonly
);
2280 HHVM_ME(ReflectionMethod
, __init
);
2281 HHVM_ME(ReflectionMethod
, isFinal
);
2282 HHVM_ME(ReflectionMethod
, isAbstract
);
2283 HHVM_ME(ReflectionMethod
, isPublic
);
2284 HHVM_ME(ReflectionMethod
, isProtected
);
2285 HHVM_ME(ReflectionMethod
, isPrivate
);
2286 HHVM_ME(ReflectionMethod
, isStatic
);
2287 HHVM_ME(ReflectionMethod
, isStaticInPrologue
);
2288 HHVM_ME(ReflectionMethod
, isConstructor
);
2289 HHVM_ME(ReflectionMethod
, isReadonly
);
2290 HHVM_ME(ReflectionMethod
, getModifiers
);
2291 HHVM_ME(ReflectionMethod
, getPrototypeClassname
);
2292 HHVM_ME(ReflectionMethod
, getDeclaringClassname
);
2294 HHVM_ME(ReflectionFile
, __init
);
2295 HHVM_ME(ReflectionFile
, getAttributesNamespaced
);
2297 HHVM_ME(ReflectionFunction
, __initName
);
2298 HHVM_ME(ReflectionFunction
, __initClosure
);
2299 HHVM_ME(ReflectionFunction
, getClosureScopeClassname
);
2300 HHVM_ME(ReflectionFunction
, getClosureThisObject
);
2302 HHVM_ME(ReflectionModule
, __init
);
2303 HHVM_ME(ReflectionModule
, getAttributesNamespaced
);
2305 HHVM_ME(ReflectionTypeConstant
, __init
);
2306 HHVM_ME(ReflectionTypeConstant
, getName
);
2307 HHVM_ME(ReflectionTypeConstant
, isAbstract
);
2308 HHVM_ME(ReflectionTypeConstant
, getAssignedTypeHint
);
2309 HHVM_ME(ReflectionTypeConstant
, getDeclaringClassname
);
2310 HHVM_ME(ReflectionTypeConstant
, getClassname
);
2312 HHVM_ME(ReflectionProperty
, __construct
);
2313 HHVM_ME(ReflectionProperty
, isPublic
);
2314 HHVM_ME(ReflectionProperty
, isProtected
);
2315 HHVM_ME(ReflectionProperty
, isPrivate
);
2316 HHVM_ME(ReflectionProperty
, isStatic
);
2317 HHVM_ME(ReflectionProperty
, isInternalToModule
);
2318 HHVM_ME(ReflectionProperty
, isDefault
);
2319 HHVM_ME(ReflectionProperty
, isReadonly
);
2320 HHVM_ME(ReflectionProperty
, getModifiers
);
2321 HHVM_ME(ReflectionProperty
, getDocComment
);
2322 HHVM_ME(ReflectionProperty
, getTypeText
);
2323 HHVM_ME(ReflectionProperty
, getDefaultValue
);
2324 HHVM_ME(ReflectionProperty
, getAttributesNamespaced
);
2326 HHVM_ME(ReflectionTypeAlias
, __init
);
2327 HHVM_ME(ReflectionTypeAlias
, getTypeStructure
);
2328 HHVM_ME(ReflectionTypeAlias
, getAttributesNamespaced
);
2329 HHVM_ME(ReflectionTypeAlias
, getAssignedTypeText
);
2330 HHVM_ME(ReflectionTypeAlias
, getFileName
);
2332 HHVM_ME(ReflectionClass
, __init
);
2333 HHVM_ME(ReflectionClass
, getName
);
2334 HHVM_ME(ReflectionClass
, getParentName
);
2335 HHVM_ME(ReflectionClass
, isHack
);
2336 HHVM_ME(ReflectionClass
, isInternal
);
2337 HHVM_ME(ReflectionClass
, isInstantiable
);
2338 HHVM_ME(ReflectionClass
, isInterface
);
2339 HHVM_ME(ReflectionClass
, isTrait
);
2340 HHVM_ME(ReflectionClass
, isEnum
);
2341 HHVM_ME(ReflectionClass
, getEnumUnderlyingType
);
2342 HHVM_ME(ReflectionClass
, isAbstract
);
2343 HHVM_ME(ReflectionClass
, isFinal
);
2344 HHVM_ME(ReflectionClass
, isInternalToModule
);
2345 HHVM_ME(ReflectionClass
, getModifiers
);
2346 HHVM_ME(ReflectionClass
, getFileName
);
2347 HHVM_ME(ReflectionClass
, getStartLine
);
2348 HHVM_ME(ReflectionClass
, getEndLine
);
2349 HHVM_ME(ReflectionClass
, getDocComment
);
2350 HHVM_ME(ReflectionClass
, getInterfaceNames
);
2351 HHVM_ME(ReflectionClass
, getRequirementNames
);
2352 HHVM_ME(ReflectionClass
, getTraitNames
);
2353 HHVM_ME(ReflectionClass
, getTraitAliases
);
2355 HHVM_ME(ReflectionClass
, hasMethod
);
2356 HHVM_STATIC_ME(ReflectionClass
, getMethodOrder
);
2358 HHVM_ME(ReflectionClass
, hasConstant
);
2359 HHVM_ME(ReflectionClass
, getConstant
);
2360 HHVM_STATIC_ME(ReflectionClass
, getOrderedConstants
);
2361 HHVM_STATIC_ME(ReflectionClass
, getOrderedAbstractConstants
);
2362 HHVM_STATIC_ME(ReflectionClass
, getOrderedTypeConstants
);
2364 HHVM_ME(ReflectionClass
, getAttributesNamespaced
);
2365 HHVM_ME(ReflectionClass
, getAttributesRecursiveNamespaced
);
2367 HHVM_ME(ReflectionClass
, getReifiedTypeParamInfo
);
2369 HHVM_STATIC_ME(ReflectionClass
, getClassPropertyInfo
);
2370 HHVM_ME(ReflectionClass
, getDynamicPropertyInfos
);
2371 HHVM_ME(ReflectionClass
, getConstructorName
);
2373 Native::registerNativeDataInfo
<ReflectionFuncHandle
>(
2374 s_ReflectionFuncHandle
.get());
2375 Native::registerNativeDataInfo
<ReflectionClassHandle
>(
2376 s_ReflectionClassHandle
.get());
2377 Native::registerNativeDataInfo
<ReflectionConstHandle
>(
2378 s_ReflectionConstHandle
.get());
2379 Native::registerNativeDataInfo
<ReflectionPropHandle
>(
2380 s_ReflectionPropHandle
.get());
2381 Native::registerNativeDataInfo
<ReflectionFileHandle
>(
2382 s_ReflectionFileHandle
.get());
2383 Native::registerNativeDataInfo
<ReflectionModuleHandle
>(
2384 s_ReflectionModuleHandle
.get());
2385 Native::registerNativeDataInfo
<ReflectionTypeAliasHandle
>(
2386 s_ReflectionTypeAliasHandle
.get(), Native::NO_SWEEP
);
2388 Native::registerNativePropHandler
2389 <reflection_extension_PropHandler
>(s_reflectionextension
);
2392 loadSystemlib("reflection-classes");
2393 loadSystemlib("reflection-internals-functions");
2394 loadSystemlib("reflection_hni");
2396 Reflection::s_ReflectionExceptionClass
=
2397 Class::lookup(s_reflectionexception
.get());
2398 assertx(Reflection::s_ReflectionExceptionClass
);
2399 Reflection::s_ReflectionExtensionClass
=
2400 Class::lookup(s_reflectionextension
.get());
2401 assertx(Reflection::s_ReflectionExtensionClass
);
2403 } s_reflection_extension
;
2405 ///////////////////////////////////////////////////////////////////////////////
2407 namespace DebuggerReflection
{
2411 void set_debugger_source_info(Array
&ret
, const StringData
* file
, int line1
,
2413 if (!file
) file
= staticEmptyString();
2414 if (file
->data()[0] != '/') {
2415 ret
.set(s_file
, SourceRootInfo::RelativeToPhpRoot(StrNR(file
)));
2417 assertx(!file
->isRefCounted());
2418 ret
.set(s_file
, make_tv
<KindOfPersistentString
>(file
));
2420 ret
.set(s_line1
, make_tv
<KindOfInt64
>(line1
));
2421 ret
.set(s_line2
, make_tv
<KindOfInt64
>(line2
));
2426 static void set_debugger_return_type_constraint(Array
&ret
, const StringData
* retType
) {
2427 assertx(ret
.isDict());
2428 if (retType
&& retType
->size()) {
2429 assertx(!retType
->isRefCounted());
2430 ret
.set(s_return_type
, make_tv
<KindOfPersistentString
>(retType
));
2432 ret
.set(s_return_type
, make_tv
<KindOfBoolean
>(false));
2436 static void set_debugger_reflection_method_prototype_info(Array
& ret
,
2438 assertx(ret
.isDict());
2439 const Class
*prototypeCls
= nullptr;
2440 if (func
->baseCls() != nullptr && func
->baseCls() != func
->implCls()) {
2441 prototypeCls
= func
->baseCls();
2442 const Class
*result
= get_prototype_class_from_interfaces(
2443 prototypeCls
, func
);
2444 if (result
) prototypeCls
= result
;
2445 } else if (func
->isMethod()) {
2446 // lookup the prototype in the interfaces
2447 prototypeCls
= get_prototype_class_from_interfaces(func
->implCls(), func
);
2450 Array prototype
= Array::CreateDict();
2451 prototype
.set(s_class
,
2452 make_tv
<KindOfPersistentString
>(prototypeCls
->name()));
2453 prototype
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2454 ret
.set(s_prototype
, prototype
);
2458 static void set_debugger_reflection_function_info(Array
& ret
,
2460 assertx(ret
.isDict());
2462 if (func
->isBuiltin()) {
2463 ret
.set(s_internal
, make_tv
<KindOfBoolean
>(true));
2465 set_debugger_return_type_constraint(ret
, func
->returnUserType());
2468 set_doc_comment(ret
, func
->docComment(), func
->isBuiltin());
2471 ret
.set(s_params
, get_function_param_info(func
));
2474 ret
.set(s_attributes
, get_function_user_attributes(func
));
2476 ret
.set(s_is_async
, func
->isAsync());
2477 ret
.set(s_is_closure
, func
->isClosureBody());
2478 ret
.set(s_is_generator
, func
->isGenerator());
2481 static void set_debugger_reflection_method_info(Array
& ret
, const Func
* func
,
2483 assertx(ret
.isDict());
2484 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2485 set_attrs(ret
, get_modifiers(func
->attrs(), false, false));
2487 if (isConstructor(func
)) {
2488 ret
.set(s_constructor
, make_tv
<KindOfBoolean
>(true));
2491 // If Func* is from a PreClass, it doesn't know about base classes etc.
2492 // Swap it out for the full version if possible.
2493 auto resolved_func
= func
->implCls()
2495 : cls
->lookupMethod(func
->name());
2497 if (!resolved_func
) {
2498 resolved_func
= func
;
2502 make_tv
<KindOfPersistentString
>(resolved_func
->implCls()->name()));
2503 set_debugger_reflection_function_info(ret
, resolved_func
);
2504 set_debugger_source_info(ret
, func
->unit()->filepath(),
2505 func
->line1(), func
->line2());
2506 set_debugger_reflection_method_prototype_info(ret
, resolved_func
);
2509 Array
get_function_info(const String
& name
) {
2510 if (name
.get() == nullptr) return null_array
;
2511 const Func
* func
= Func::load(name
.get());
2512 if (!func
) return null_array
;
2513 auto ret
= Array::CreateDict();
2514 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2516 // setting parameters and static variables
2517 set_debugger_reflection_function_info(ret
, func
);
2518 set_debugger_source_info(ret
, func
->unit()->filepath(),
2519 func
->line1(), func
->line2());
2523 Array
get_class_info(const String
& name
) {
2524 auto cls
= get_cls(name
);
2525 if (!cls
) return null_array
;
2527 auto ret
= Array::CreateDict();
2528 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(cls
->name()));
2529 ret
.set(s_extension
, empty_string_tv());
2530 ret
.set(s_parent
, make_tv
<KindOfPersistentString
>(cls
->preClass()->parent()));
2534 auto const& allIfaces
= cls
->allInterfaces();
2535 DictInit
arr(allIfaces
.size());
2536 for (auto const& interface
: cls
->declInterfaces()) {
2537 arr
.set(interface
->nameStr(), make_tv
<KindOfInt64
>(1));
2539 if (allIfaces
.size() > cls
->declInterfaces().size()) {
2540 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
2541 auto const& interface
= allIfaces
[i
];
2542 arr
.set(interface
->nameStr(), make_tv
<KindOfInt64
>(1));
2545 ret
.set(s_interfaces
, make_array_like_tv(arr
.create()));
2550 auto const& traits
= cls
->preClass()->usedTraits();
2551 DictInit
arr(traits
.size());
2552 for (auto const& traitName
: traits
) {
2553 arr
.set(StrNR(traitName
), make_tv
<KindOfInt64
>(1));
2555 ret
.set(s_traits
, make_array_like_tv(arr
.create()));
2560 ret
.set(s_trait_aliases
, VarNR(get_trait_alias_info(cls
)).tv());
2565 if (cls
->attrs() & AttrBuiltin
) {
2566 ret
.set(s_internal
, make_tv
<KindOfBoolean
>(true));
2568 if (cls
->attrs() & AttrFinal
) {
2569 ret
.set(s_final
, make_tv
<KindOfBoolean
>(true));
2571 if (cls
->attrs() & AttrAbstract
) {
2572 ret
.set(s_abstract
, make_tv
<KindOfBoolean
>(true));
2574 if (cls
->attrs() & AttrInterface
) {
2575 ret
.set(s_interface
, make_tv
<KindOfBoolean
>(true));
2577 if (cls
->attrs() & AttrTrait
) {
2578 ret
.set(s_trait
, make_tv
<KindOfBoolean
>(true));
2580 ret
.set(s_modifiers
, make_tv
<KindOfInt64
>(
2581 get_modifiers(cls
->attrs(), true, false))
2584 if (cls
->getCtor()->attrs() & AttrPublic
&&
2585 !(cls
->attrs() & AttrAbstract
) &&
2586 !(cls
->attrs() & AttrInterface
) &&
2587 !(cls
->attrs() & AttrTrait
)) {
2588 ret
.set(s_instantiable
, make_tv
<KindOfBoolean
>(true));
2594 auto arr
= Array::CreateDict();
2596 // Fetch from PreClass as:
2597 // - the order is important
2598 // - we want type profiling info
2599 // and neither of these are in the Class...
2600 Func
* const* methods
= cls
->preClass()->methods();
2601 size_t const numMethods
= cls
->preClass()->numMethods();
2602 for (Slot i
= 0; i
< numMethods
; ++i
) {
2603 const Func
* m
= methods
[i
];
2604 if (m
->isGenerated()) continue;
2606 auto lowerName
= HHVM_FN(strtolower
)(m
->nameStr());
2607 auto info
= Array::CreateDict();
2608 set_debugger_reflection_method_info(info
, m
, cls
);
2609 arr
.set(lowerName
, VarNR(info
).tv());
2612 for (Slot i
= cls
->traitsBeginIdx(); i
< cls
->traitsEndIdx(); ++i
) {
2613 const Func
* m
= cls
->getMethod(i
);
2614 if (m
->isGenerated()) continue;
2616 auto lowerName
= HHVM_FN(strtolower
)(m
->nameStr());
2617 auto info
= Array::CreateDict();
2618 set_debugger_reflection_method_info(info
, m
, cls
);
2619 arr
.set(lowerName
, VarNR(info
).tv());
2621 ret
.set(s_methods
, VarNR(arr
).tv());
2626 auto arr
= Array::CreateDict();
2627 auto arrPriv
= Array::CreateDict();
2628 auto arrIdx
= Array::CreateDict();
2629 auto arrPrivIdx
= Array::CreateDict();
2631 auto const properties
= cls
->declProperties();
2632 auto const& propInitVec
= cls
->declPropInit();
2633 auto const nProps
= cls
->numDeclProperties();
2635 for (Slot slot
= 0; slot
< nProps
; ++slot
) {
2636 auto index
= cls
->propSlotToIndex(slot
);
2637 auto const& prop
= properties
[slot
];
2638 auto const default_val
= propInitVec
[index
].val
.tv();
2639 auto info
= Array::CreateDict();
2640 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
2641 if (prop
.cls
== cls
) {
2642 set_instance_prop_info(info
, &prop
, default_val
);
2643 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
2644 arrPrivIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2648 set_instance_prop_info(info
, &prop
, default_val
);
2649 arr
.set(StrNR(prop
.name
), VarNR(info
).tv());
2650 arrIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2653 for (auto const& prop
: cls
->staticProperties()) {
2654 auto info
= Array::CreateDict();
2655 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
2656 if (prop
.cls
== cls
) {
2657 set_static_prop_info(info
, &prop
);
2658 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
2659 arrPrivIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2663 set_static_prop_info(info
, &prop
);
2664 arr
.set(StrNR(prop
.name
), VarNR(info
).tv());
2665 arrIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2667 ret
.set(s_properties
, VarNR(arr
).tv());
2668 ret
.set(s_private_properties
, VarNR(arrPriv
).tv());
2669 ret
.set(s_properties_index
, VarNR(arrIdx
).tv());
2670 ret
.set(s_private_properties_index
, VarNR(arrPrivIdx
).tv());
2675 size_t numConsts
= cls
->numConstants();
2676 const Class::Const
* consts
= cls
->constants();
2677 DictInit
arr(numConsts
);
2678 for (size_t i
= 0; i
< numConsts
; i
++) {
2679 // Note: hphpc doesn't include inherited constants in
2680 // get_class_constants(), so mimic that behavior
2681 if (consts
[i
].cls
== cls
) {
2682 TypedValue value
= cls
->clsCnsGet(consts
[i
].name
);
2683 assertx(value
.m_type
!= KindOfUninit
);
2684 arr
.set(StrNR(consts
[i
].name
), value
);
2688 ret
.set(s_constants
, make_array_like_tv(arr
.create()));
2692 const PreClass
* pcls
= cls
->preClass();
2693 set_debugger_source_info(ret
, pcls
->unit()->filepath(),
2694 pcls
->line1(), pcls
->line2());
2695 set_doc_comment(ret
, pcls
->docComment(), pcls
->isBuiltin());
2700 const PreClass
* pcls
= cls
->preClass();
2701 auto const& attrs
= pcls
->userAttributes();
2702 DictInit arr
{attrs
.size()};
2703 for (auto const& attr
: attrs
) {
2704 arr
.set(StrNR(attr
.first
), attr
.second
);
2706 ret
.set(s_attributes
, make_array_like_tv(arr
.create()));
2714 ///////////////////////////////////////////////////////////////////////////////