Add internal identifier to functions, methods, properties and classes
[hiphop-php.git] / hphp / runtime / ext / reflection / ext_reflection.cpp
blob6b0caa3ae4004ec00b3b1ff57f4d81d29745589e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
47 #include <functional>
48 #include <boost/algorithm/string/predicate.hpp>
50 namespace HPHP {
52 ///////////////////////////////////////////////////////////////////////////////
54 const StaticString
55 s_name("name"),
56 s___name("__name"),
57 s_version("version"),
58 s_info("info"),
59 s_ini("ini"),
60 s_constants("constants"),
61 s_constructor("constructor"),
62 s_functions("functions"),
63 s_classes("classes"),
64 s_access("access"),
65 s_public("public"),
66 s_protected("protected"),
67 s_private("private"),
68 s_file("file"),
69 s_line1("line1"),
70 s_line2("line2"),
71 s_doc("doc"),
72 s_modifiers("modifiers"),
73 s_class("class"),
74 s_prototype("prototype"),
75 s_ref("ref"),
76 s_inout("inout"),
77 s_readonly("readonly"),
78 s_index("index"),
79 s_type("type"),
80 s_nullable("nullable"),
81 s_msg("msg"),
82 s_is_optional("is_optional"),
83 s_is_variadic("is_variadic"),
84 s_default("default"),
85 s_defaultValue("defaultValue"),
86 s_defaultText("defaultText"),
87 s_params("params"),
88 s_final("final"),
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"),
95 s_hphp("hphp"),
96 s_static_variables("static_variables"),
97 s_extension("extension"),
98 s_interfaces("interfaces"),
99 s_traits("traits"),
100 s_interface("interface"),
101 s_trait("trait"),
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"),
110 s_varg("varg"),
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());
138 if (!func) {
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());
143 if (func) { break; }
147 assertx(func == nullptr || func->isMethod());
148 return func;
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;
171 try {
172 return g_context->getEvaledArg(
173 fpi.phpCode,
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
177 // namespaced).
178 func->cls() ? func->cls()->nameStr() : func->nameStr(),
179 func->unit()
181 } catch (const Exception&) {
182 return on_eval_exn();
183 } catch (const Object&) {
184 if (RO::EvalFixDefaultArgReflection > 1) {
185 return on_eval_exn();
186 } else {
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 "
190 "in future HHVMs!",
191 func->fullNameStr().data(),
192 func->localNames()[argIdx]->data());
194 throw;
199 Array HHVM_FUNCTION(hphp_get_extension_info, const String& name) {
201 Extension *ext = ExtensionRegistry::get(name);
203 return make_dict_array(
204 s_name, name,
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;
216 if (!prop) {
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;
227 return php_modifier;
230 ALWAYS_INLINE
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); }
245 return attrs;
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));
258 } else {
259 assertx(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,
279 bool isBuiltin) {
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);
285 } else {
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));
305 } else {
306 ret.set(s_type, make_tv<KindOfBoolean>(false));
310 static void set_dyn_prop_info(
311 Array &ret,
312 TypedValue name,
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));
333 } else {
334 ret.set(s_type, make_tv<KindOfBoolean>(false));
338 static bool resolveConstant(const char *p, int64_t len, Variant &cns) {
339 // ltrim
340 while (len && (*p == ' ')) {
341 p++;
342 len--;
344 // rtrim
345 while (len && (p[len-1] == ' ')) {
346 len--;
349 String cname(p, len, CopyString);
351 if (!f_defined(cname)) {
352 cns = uninit_null();
353 return false;
356 cns = f_constant(cname);
357 return true;
360 bool resolveDefaultParameterConstant(const char *value, int64_t valueLen,
361 Variant &cns) {
362 const char *p = value;
363 const char *e = value + valueLen;
364 const char *s;
365 bool isLval = false;
366 int64_t lval = 0;
368 while ((s = strchr(p, '|'))) {
369 isLval = true;
370 if (!resolveConstant(p, s - p, cns)) {
371 return false;
373 lval |= cns.toInt64();
374 p = s + 1;
376 if (!resolveConstant(p, e - p, cns)) {
377 return false;
379 if (isLval) {
380 cns = cns.toInt64() | lval;
382 return true;
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,
396 const Func *func) {
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;
404 return nullptr;
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,
420 const String& cls,
421 const String& name,
422 const Variant& params) {
423 if (obj.isNull()) {
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());
436 if (!selectedFunc) {
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.
451 CallCtx ctx;
452 ctx.cls = providedClass;
453 ctx.this_ = objData;
454 ctx.func = selectedFunc;
455 ctx.dynamic = true;
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) {
485 raise_error(
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,
495 const String& prop,
496 bool force) {
497 auto const sd = cls.get();
498 auto const class_ = Class::lookup(sd);
499 if (!class_) {
500 raise_error("Non-existent class %s", sd->data());
502 VMRegAnchor _;
503 CoeffectsAutoGuard _2;
505 auto const lookup = class_->getSPropIgnoreLateInit(
506 force ? class_ : arGetContextClass(vmfp()),
507 prop.get()
509 if (!lookup.val) {
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,
521 const String& prop,
522 const Variant& value,
523 bool force) {
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());
533 VMRegAnchor _;
534 CoeffectsAutoGuard _2;
536 auto const lookup = class_->getSPropIgnoreLateInit(
537 force ? class_ : arGetContextClass(vmfp()),
538 prop.get()
540 if (!lookup.val) {
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
555 // class_meth types.
556 auto tmp = value;
557 if (RuntimeOption::EvalCheckPropTypeHints > 0 && tc.isCheckable()) {
558 tc.verifyStaticProperty(tmp.asTypedValue(), class_, sprop.cls, prop.get());
560 tvAsVariant(lookup.val) = tmp;
563 namespace {
565 const StaticString s_classname("classname");
567 Array implTypeStructure(const Variant& cls_or_obj,
568 const Variant& cns_name,
569 bool no_throw) {
570 SuppressClassConversionWarning suppressor;
571 auto const cns_sd = cns_name.getStringDataOrNull();
572 if (!cns_sd) {
573 auto name = cls_or_obj.toString();
575 auto const typeAlias = TypeAlias::load(name.get());
577 if (!typeAlias) {
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());
585 return preresolved;
588 auto const& typeStructure = typeAlias->typeStructure();
589 assertx(!typeStructure.empty());
590 assertx(typeStructure.isDict());
591 Array resolved;
592 try {
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",
598 name.get()->data());
600 assertx(!resolved.empty());
601 assertx(resolved.isDict());
602 return resolved;
605 auto const cls = get_cls(cls_or_obj);
607 if (!cls) {
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);
622 } // namespace
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
630 * constant.
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);
651 [[noreturn]]
652 void Reflection::ThrowReflectionExceptionObject(const Variant& message) {
653 Object inst{s_ReflectionExceptionClass};
654 tvDecRefGen(
655 g_context->invokeFunc(s_ReflectionExceptionClass->getCtor(),
656 make_vec_array(message),
657 inst.get())
659 throw_object(inst);
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()) {
686 return false;
688 return func->line1();
691 static Variant HHVM_METHOD(ReflectionFunctionAbstract, getEndLine) {
692 auto const func = ReflectionFuncHandle::GetFuncFor(this_);
693 if (func->isBuiltin()) {
694 return false;
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);
704 } else {
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());
713 return String(ret);
716 static bool HHVM_METHOD(ReflectionFunctionAbstract, isHack) {
717 return true;
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();
750 ALWAYS_INLINE
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
771 ? fpi.userType
772 : staticEmptyString();
773 param.set(s_type_hint, make_tv<KindOfPersistentString>(typeHint));
775 // callable typehint considered builtin; stdclass typehint is not
776 if (
777 fpi.typeConstraint.isCallable() ||
778 (fpi.typeConstraint.underlyingDataType() &&
779 fpi.typeConstraint.underlyingDataType() != KindOfObject
782 param.set(s_type_hint_builtin, make_tv<KindOfBoolean>(true));
783 } else {
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()) {
788 param.set(
789 s_class,
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));
799 } else {
800 param.set(s_type_hint_nullable, make_tv<KindOfBoolean>(false));
803 if (fpi.phpCode) {
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);
838 return arr;
841 // helper for getParameters
842 static Array HHVM_METHOD(ReflectionFunctionAbstract, getParamInfo) {
843 // FIXME: each parameter info should be HNI with a handle to the
844 // Func::ParamInfo
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);
855 return String(ret);
857 return String();
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));
868 } else {
869 retTypeInfo.set(s_type_hint_nullable, make_tv<KindOfBoolean>(false));
872 if (
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));
879 } else {
880 retTypeInfo.set(s_type_hint_builtin, make_tv<KindOfBoolean>(false));
882 } else {
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();
891 namespace {
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();
905 } // namespace
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;
948 ALWAYS_INLINE
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);
956 return ai.toArray();
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
972 return false;
974 auto const func = get_method_func(cls, meth_name);
975 if (!func) {
976 // caller raises exception
977 return false;
979 assertx(func->isMethod());
980 ReflectionFuncHandle::Get(this_)->setFunc(func);
981 return true;
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);
1047 if (prototypeCls) {
1048 auto ret = const_cast<StringData*>(prototypeCls->name());
1049 return String(ret);
1051 return String();
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());
1058 return String(ret);
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(),
1076 nullptr,
1077 Native::s_noNativeFuncs,
1078 false
1081 if (!unit) {
1082 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1083 "File '{}' does not exist",
1084 name
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_);
1095 assertx(unit);
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());
1119 if (!module) {
1120 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1121 "Module '{}' does not exist",
1122 name
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_);
1132 assertx(module);
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);
1150 return true;
1153 // helper for __construct
1154 static bool HHVM_METHOD(ReflectionFunction, __initClosure,
1155 const Object& closure) {
1156 auto const cls = get_cls(closure);
1157 assertx(cls);
1158 if (!cls) { return false; }
1159 const Func* func = cls->lookupMethod(s___invoke.get());
1160 if (!func) {
1161 // caller raises exception
1162 return false;
1164 assertx(func->isClosureBody());
1165 assertx(func->implCls()->isScopedClosure());
1166 ReflectionFuncHandle::Get(this_)->setFunc(func);
1167 return true;
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) {
1217 return true;
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 |
1228 AttrEnumClass))
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()) {
1296 return false;
1298 return cls->preClass()->line1();
1301 static Variant HHVM_METHOD(ReflectionClass, getEndLine) {
1302 auto const cls = ReflectionClassHandle::GetClassFor(this_);
1303 if (cls->isBuiltin()) {
1304 return false;
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);
1315 } else {
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();
1331 if (numReqs == 0) {
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();
1382 } else {
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()
1385 // on the Class.
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);
1407 namespace {
1408 const Class* get_class_from_name(const String& name) {
1409 auto const cls = Class::load(name.get());
1410 if (!cls) {
1411 auto message = folly::sformat(
1412 "class {} could not be loaded",
1413 name.toCppString()
1415 Reflection::ThrowReflectionExceptionObject(message);
1417 return cls;
1421 // helper for getMethods: returns a keyset
1422 static Array HHVM_STATIC_METHOD(
1423 ReflectionClass,
1424 getMethodOrder,
1425 const String& clsname,
1426 int64_t filter) {
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) {
1448 if (!clas) return;
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) {
1458 add(methods[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.
1466 add(methods[i]);
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) {
1475 if (!iface) return;
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) {
1481 add(methods[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());
1511 return st;
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);
1523 tvIncRefGen(value);
1524 return value;
1527 static
1528 void addClassConstantNames(const Class* cls,
1529 const req::ptr<c_Set>& st,
1530 size_t limit) {
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(
1562 ReflectionClass,
1563 getOrderedConstants,
1564 const String& clsname) {
1565 auto const cls = get_class_from_name(clsname);
1567 size_t numConsts = cls->numConstants();
1568 if (!numConsts) {
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();
1588 namespace {
1589 // helper for getOrdered*Constants
1590 template <typename Fn>
1591 static Array orderedConstantsHelper(const Class* cls, Fn filterFn) {
1592 auto const numConsts = cls->numConstants();
1593 if (!numConsts) {
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(
1613 ReflectionClass,
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(
1626 ReflectionClass,
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);
1662 do {
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()));
1672 return ret;
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(
1681 ReflectionClass,
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();
1690 cls->initialize();
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)) {
1702 continue;
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)) {
1716 continue;
1719 auto info = Array::CreateDict();
1720 set_static_prop_info(info, &prop);
1721 ret.set(StrNR(prop.name), VarNR(info).tv());
1723 return ret;
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());
1754 return String(ret);
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,
1779 s___name.get()
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
1811 return false;
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);
1823 return true;
1827 // caller raises exception
1828 return false;
1831 static String HHVM_METHOD(ReflectionTypeConstant, getName) {
1832 auto const cns = ReflectionConstHandle::GetConstFor(this_);
1833 auto ret = const_cast<StringData*>(cns->name.get());
1834 return String(ret);
1837 static bool HHVM_METHOD(ReflectionTypeConstant, isAbstract) {
1838 auto const cns = ReflectionConstHandle::GetConstFor(this_);
1839 if (RO::EvalTypeconstAbstractDefaultReflectionIsAbstract) {
1840 return cns->isAbstract();
1841 } else {
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);
1867 return String();
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());
1875 return String(ret);
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());
1882 return String(ret);
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);
1893 if (!cls) {
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));
1918 return;
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));
1931 return;
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());
1949 return;
1953 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1954 "Property {}::{} does not exist",
1955 cls->name()->toCppString(),
1956 prop_name.toCppString()
1960 namespace {
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:
1976 return true;
1977 default:
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:
1990 return false;
1991 default:
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:
2004 return false;
2005 default:
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:
2014 return true;
2015 case ReflectionPropHandle::Type::Instance:
2016 case ReflectionPropHandle::Type::Dynamic:
2017 return false;
2018 default:
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:
2031 return false;
2032 default:
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:
2042 return true;
2043 case ReflectionPropHandle::Type::Dynamic:
2044 return false;
2045 default:
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);
2059 default:
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();
2070 break;
2071 case ReflectionPropHandle::Type::Static:
2072 comment = data->getSProp()->preProp->docComment();
2073 break;
2074 case ReflectionPropHandle::Type::Dynamic:
2075 break;
2076 default:
2077 reflection_property_internal_error();
2079 if (comment == nullptr || comment->empty()) {
2080 return tvReturn(false);
2081 } else {
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();
2093 break;
2094 case ReflectionPropHandle::Type::Static:
2095 type = data->getSProp()->preProp->userType();
2096 break;
2097 case ReflectionPropHandle::Type::Dynamic:
2098 break;
2099 default:
2100 reflection_property_internal_error();
2102 if (type == nullptr || type->empty()) {
2103 return empty_string();
2104 } else {
2105 return StrNR(type);
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);
2124 cls->initialize();
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>();
2138 default:
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);
2152 return attrs;
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);
2159 return attrs;
2161 case ReflectionPropHandle::Type::Dynamic:
2162 return attrs;
2163 default:
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:
2176 return false;
2177 default:
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());
2192 if (!typeAlias) {
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_);
2202 assertx(req);
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_);
2211 assertx(req);
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_);
2221 assertx(req);
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_);
2233 assertx(req);
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);
2391 loadSystemlib();
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 {
2409 namespace {
2411 void set_debugger_source_info(Array &ret, const StringData* file, int line1,
2412 int line2) {
2413 if (!file) file = staticEmptyString();
2414 if (file->data()[0] != '/') {
2415 ret.set(s_file, SourceRootInfo::RelativeToPhpRoot(StrNR(file)));
2416 } else {
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));
2431 } else {
2432 ret.set(s_return_type, make_tv<KindOfBoolean>(false));
2436 static void set_debugger_reflection_method_prototype_info(Array& ret,
2437 const Func *func) {
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);
2449 if (prototypeCls) {
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,
2459 const Func* func) {
2460 assertx(ret.isDict());
2461 // return type
2462 if (func->isBuiltin()) {
2463 ret.set(s_internal, make_tv<KindOfBoolean>(true));
2465 set_debugger_return_type_constraint(ret, func->returnUserType());
2467 // doc comments
2468 set_doc_comment(ret, func->docComment(), func->isBuiltin());
2470 // parameters
2471 ret.set(s_params, get_function_param_info(func));
2473 // user attributes
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,
2482 const Class* cls) {
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()
2494 ? func
2495 : cls->lookupMethod(func->name());
2497 if (!resolved_func) {
2498 resolved_func = func;
2501 ret.set(s_class,
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());
2520 return ret;
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()));
2532 // interfaces
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()));
2548 // traits
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()));
2558 // trait aliases
2560 ret.set(s_trait_aliases, VarNR(get_trait_alias_info(cls)).tv());
2563 // attributes
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));
2592 // methods
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());
2624 // properties
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);
2646 continue;
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);
2661 continue;
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());
2673 // constants
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()));
2691 { // source info
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());
2698 // user attributes
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()));
2709 return ret;
2714 ///////////////////////////////////////////////////////////////////////////////