2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/ext/reflection/ext_reflection.h"
20 #include "hphp/runtime/base/array-init.h"
21 #include "hphp/runtime/base/externals.h"
22 #include "hphp/runtime/base/file.h"
23 #include "hphp/runtime/base/mixed-array.h"
24 #include "hphp/runtime/base/runtime-option.h"
25 #include "hphp/runtime/base/string-hash-set.h"
26 #include "hphp/runtime/base/string-util.h"
27 #include "hphp/runtime/base/tv-refcount.h"
28 #include "hphp/runtime/base/type-structure.h"
29 #include "hphp/runtime/base/type-variant.h"
30 #include "hphp/runtime/base/unit-cache.h"
31 #include "hphp/runtime/vm/jit/translator-inline.h"
32 #include "hphp/runtime/vm/native-data.h"
33 #include "hphp/runtime/vm/native-prop-handler.h"
35 #include "hphp/runtime/ext/debugger/ext_debugger.h"
36 #include "hphp/runtime/ext/std/ext_std_closure.h"
37 #include "hphp/runtime/ext/collections/ext_collections-set.h"
38 #include "hphp/runtime/ext/std/ext_std_misc.h"
39 #include "hphp/runtime/ext/string/ext_string.h"
40 #include "hphp/runtime/ext/extension-registry.h"
42 #include "hphp/system/systemlib.h"
45 #include <boost/algorithm/string/predicate.hpp>
49 ///////////////////////////////////////////////////////////////////////////////
57 s_constants("constants"),
58 s_constructor("constructor"),
59 s_functions("functions"),
63 s_protected("protected"),
69 s_modifiers("modifiers"),
71 s_prototype("prototype"),
76 s_nullable("nullable"),
78 s_is_optional("is_optional"),
79 s_is_variadic("is_variadic"),
81 s_defaultValue("defaultValue"),
82 s_defaultText("defaultText"),
85 s_abstract("abstract"),
86 s_instantiable("instantiable"),
87 s_internal("internal"),
88 s_is_async("is_async"),
89 s_is_closure("is_closure"),
90 s_is_generator("is_generator"),
92 s_static_variables("static_variables"),
93 s_extension("extension"),
94 s_interfaces("interfaces"),
96 s_interface("interface"),
99 s_properties("properties"),
100 s_private_properties("private_properties"),
101 s_properties_index("properties_index"),
102 s_private_properties_index("private_properties_index"),
103 s_attributes("attributes"),
104 s_function("function"),
105 s_trait_aliases("trait_aliases"),
107 s___invoke("__invoke"),
108 s_return_type("return_type"),
109 s_accessible("accessible"),
110 s_reflectionexception("ReflectionException"),
111 s_reflectionextension("ReflectionExtension"),
112 s_type_hint("type_hint"),
113 s_type_hint_builtin("type_hint_builtin"),
114 s_type_hint_nullable("type_hint_nullable");
116 Class
* Reflection::s_ReflectionExceptionClass
= nullptr;
117 Class
* Reflection::s_ReflectionExtensionClass
= nullptr;
119 Class
* get_cls(const Variant
& class_or_object
) {
120 if (class_or_object
.is(KindOfObject
)) {
121 return class_or_object
.toCObjRef()->getVMClass();
122 } else if (class_or_object
.isClass()) {
123 return class_or_object
.toClassVal();
126 return Unit::loadClass(class_or_object
.toString().get());
129 const Func
* get_method_func(const Class
* cls
, const String
& meth_name
) {
130 const Func
* func
= cls
->lookupMethod(meth_name
.get());
132 if (cls
->attrs() & (AttrInterface
| AttrAbstract
| AttrTrait
)) {
133 const Class::InterfaceMap
& ifaces
= cls
->allInterfaces();
134 for (int i
= 0, size
= ifaces
.size(); i
< size
; i
++) {
135 func
= ifaces
[i
]->lookupMethod(meth_name
.get());
140 assertx(func
== nullptr || func
->isMethod());
144 Variant
default_arg_from_php_code(const Func::ParamInfo
& fpi
,
145 const Func
* func
, unsigned argIdx
) {
146 assertx(fpi
.hasDefaultValue());
147 if (fpi
.hasScalarDefaultValue()) {
148 // Most of the time the default value is scalar, so we can
149 // avoid evaling in the common case
150 return tvAsVariant((TypedValue
*)&fpi
.defaultValue
);
152 // Eval PHP code to get the default value. Note that eval here can throw a
153 // fatal, e.g. due to the use of undefined class constants or static:: .
154 // When this happens, instead of fataling the execution, set the default
155 // value to null and raise a warning.
157 return g_context
->getEvaledArg(
159 // We use cls() instead of implCls() because we want the namespace and
160 // class context for which the closure is scoped, not that of the
161 // Closure subclass (which, among other things, is always globally
163 func
->cls() ? func
->cls()->nameStr() : func
->nameStr(),
166 } catch (Exception
& e
) {
167 raise_warning("Failed to eval default value of %s()'s $%s argument for "
168 "reflection, assigning NULL instead",
169 func
->fullNameStr().data(),
170 func
->localNames()[argIdx
]->data());
171 return init_null_variant
;
175 Array
HHVM_FUNCTION(hphp_get_extension_info
, const String
& name
) {
178 Extension
*ext
= ExtensionRegistry::get(name
);
180 ret
.set(s_name
, name
);
181 ret
.set(s_version
, ext
? ext
->getVersion() : "");
182 ret
.set(s_info
, empty_string_variant_ref
);
183 ret
.set(s_ini
, Array::Create());
184 ret
.set(s_constants
, Array::Create());
185 ret
.set(s_functions
, Array::Create());
186 ret
.set(s_classes
, Array::Create());
191 int get_modifiers(Attr attrs
, bool cls
, bool prop
) {
192 int php_modifier
= 0;
194 // These bits have different meanings with properties
195 if (attrs
& AttrAbstract
) php_modifier
|= cls
? 0x20 : 0x02;
196 if (attrs
& AttrFinal
) php_modifier
|= cls
? 0x40 : 0x04;
198 if (!cls
) { // AttrPublic bits are not valid on class (have other meaning)
199 if (attrs
& AttrStatic
) php_modifier
|= 0x01;
200 if (attrs
& AttrPublic
) php_modifier
|= 0x100;
201 if (attrs
& AttrProtected
) php_modifier
|= 0x200;
202 if (attrs
& AttrPrivate
) php_modifier
|= 0x400;
208 static Attr
attrs_from_modifiers(int php_modifier
, bool cls
) {
209 Attr attrs
= (Attr
) 0;
210 if (php_modifier
& (cls
? 0x20 : 0x02)) {
211 attrs
= (Attr
)(attrs
| AttrAbstract
);
213 if (php_modifier
& (cls
? 0x40 : 0x04)) {
214 attrs
= (Attr
)(attrs
| AttrFinal
);
216 if (php_modifier
& 0x01) { attrs
= (Attr
)(attrs
| AttrStatic
); }
217 if (!cls
) { // AttrPublic bits are not valid on class (have other meaning)
218 if (php_modifier
& 0x100) { attrs
= (Attr
)(attrs
| AttrPublic
); }
219 if (php_modifier
& 0x200) { attrs
= (Attr
)(attrs
| AttrProtected
); }
220 if (php_modifier
& 0x400) { attrs
= (Attr
)(attrs
| AttrPrivate
); }
225 static void set_attrs(Array
& ret
, int modifiers
) {
226 if (modifiers
& 0x100) {
227 ret
.set(s_access
, VarNR(s_public
).tv());
228 ret
.set(s_accessible
, true_varNR
.tv());
229 } else if (modifiers
& 0x200) {
230 ret
.set(s_access
, VarNR(s_protected
).tv());
231 ret
.set(s_accessible
, false_varNR
.tv());
232 } else if (modifiers
& 0x400) {
233 ret
.set(s_access
, VarNR(s_private
).tv());
234 ret
.set(s_accessible
, false_varNR
.tv());
238 ret
.set(s_modifiers
, make_tv
<KindOfInt64
>(modifiers
));
239 if (modifiers
& 0x1) {
240 ret
.set(s_static
, true_varNR
.tv());
242 if (modifiers
& 0x44) {
243 ret
.set(s_final
, true_varNR
.tv());
245 if (modifiers
& 0x22) {
246 ret
.set(s_abstract
, true_varNR
.tv());
250 static void set_empty_doc_comment(Array
& ret
) {
251 ret
.set(s_doc
, false_varNR
.tv());
254 static void set_doc_comment(Array
& ret
,
255 const StringData
* comment
,
257 if (comment
== nullptr || comment
->empty()) {
258 set_empty_doc_comment(ret
);
259 } else if (isBuiltin
&& !HHVM_FUNCTION(hphp_debugger_attached
)) {
260 set_empty_doc_comment(ret
);
262 assertx(!comment
->isRefCounted());
263 ret
.set(s_doc
, make_tv
<KindOfPersistentString
>(comment
));
267 static void set_instance_prop_info(Array
& ret
,
268 const Class::Prop
* prop
,
269 const Variant
& default_val
) {
270 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(prop
->name
));
271 ret
.set(s_default
, true_varNR
.tv());
272 ret
.set(s_defaultValue
, default_val
);
273 set_attrs(ret
, get_modifiers(prop
->attrs
, false, true) & ~0x66);
274 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
275 set_doc_comment(ret
, prop
->preProp
->docComment(), prop
->cls
->isBuiltin());
277 auto const user_type
= prop
->preProp
->userType();
278 if (user_type
&& user_type
->size()) {
279 ret
.set(s_type
, make_tv
<KindOfPersistentString
>(user_type
));
281 ret
.set(s_type
, false_varNR
.tv());
285 static void set_dyn_prop_info(
288 const StringData
* className
) {
289 ret
.set(s_name
, name
);
290 set_attrs(ret
, get_modifiers(AttrPublic
, false, true) & ~0x66);
291 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(className
));
292 set_empty_doc_comment(ret
);
293 ret
.set(s_type
, false_varNR
.tv());
296 static void set_static_prop_info(Array
&ret
, const Class::SProp
* prop
) {
297 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(prop
->name
));
298 ret
.set(s_default
, true_varNR
.tv());
299 ret
.set(s_defaultValue
, prop
->val
);
300 set_attrs(ret
, get_modifiers(prop
->attrs
, false, true) & ~0x66);
301 ret
.set(s_class
, make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
302 set_doc_comment(ret
, prop
->preProp
->docComment(), prop
->cls
->isBuiltin());
303 auto const user_type
= prop
->preProp
->userType();
304 if (user_type
&& user_type
->size()) {
305 ret
.set(s_type
, make_tv
<KindOfPersistentString
>(user_type
));
307 ret
.set(s_type
, false_varNR
.tv());
311 static bool resolveConstant(const char *p
, int64_t len
, Variant
&cns
) {
313 while (len
&& (*p
== ' ')) {
318 while (len
&& (p
[len
-1] == ' ')) {
322 String
cname(p
, len
, CopyString
);
324 if (!f_defined(cname
)) {
329 cns
= f_constant(cname
);
333 bool resolveDefaultParameterConstant(const char *value
, int64_t valueLen
,
335 const char *p
= value
;
336 const char *e
= value
+ valueLen
;
341 while ((s
= strchr(p
, '|'))) {
343 if (!resolveConstant(p
, s
- p
, cns
)) {
346 lval
|= cns
.toInt64();
349 if (!resolveConstant(p
, e
- p
, cns
)) {
353 cns
= cns
.toInt64() | lval
;
358 static bool isConstructor(const Func
* func
) {
359 PreClass
* pcls
= func
->preClass();
360 if (!pcls
|| (pcls
->attrs() & AttrInterface
)) { return false; }
361 if (func
->implCls()) { return func
== func
->implCls()->getCtor(); }
362 if (0 == strcasecmp("__construct", func
->name()->data())) { return true; }
363 /* A same named function is not a constructor in a trait */
364 if (pcls
->attrs() & AttrTrait
) return false;
365 return pcls
->name()->isame(func
->name());
368 static const Class
* get_prototype_class_from_interfaces(const Class
*cls
,
370 // only looks at the interfaces if the method is public
371 if (!func
->isPublic()) return nullptr;
372 const Class::InterfaceMap
& interfaces
= cls
->allInterfaces();
373 for (unsigned int i
= 0, size
= interfaces
.size(); i
< size
; i
++) {
374 const Class
* iface
= interfaces
[i
];
375 if (iface
->preClass()->hasMethod(func
->name())) return iface
;
380 Variant
HHVM_FUNCTION(hphp_invoke
, const String
& name
, const Variant
& params
) {
381 return invoke(name
.data(), params
);
384 static const StaticString
s_invoke_not_instanceof_error(
385 "Given object is not an instance of the class this method was declared in"
388 static const StaticString
s_invoke_non_object(
389 "Non-object passed to Invoke()"
392 Variant
HHVM_FUNCTION(hphp_invoke_method
, const Variant
& obj
,
395 const Variant
& params
) {
397 return invoke_static_method(cls
, name
, params
);
400 if (!obj
.is(KindOfObject
)) {
401 Reflection::ThrowReflectionExceptionObject(s_invoke_non_object
);
404 auto const providedClass
= Unit::loadClass(cls
.get());
405 if (!providedClass
) {
406 raise_error("Call to undefined method %s::%s()", cls
.data(), name
.data());
408 auto const selectedFunc
= providedClass
->lookupMethod(name
.get());
410 raise_error("Call to undefined method %s::%s()", cls
.data(), name
.data());
413 auto const objData
= obj
.toCObjRef().get();
414 auto const implementingClass
= selectedFunc
->implCls();
415 if (!objData
->instanceof(implementingClass
)) {
416 Reflection::ThrowReflectionExceptionObject(s_invoke_not_instanceof_error
);
419 // Get the CallCtx this way instead of using vm_decode_function() because
420 // vm_decode_function() has no way to specify a class independent from the
421 // class::function being called.
422 // Note that this breaks the rules for name lookup (for protected and private)
423 // but that's okay because so does Zend's implementation.
425 ctx
.cls
= providedClass
;
427 ctx
.invName
= nullptr;
428 ctx
.func
= selectedFunc
;
431 return Variant::attach(
432 g_context
->invokeFunc(ctx
, params
)
436 Object
HHVM_FUNCTION(hphp_create_object
, const String
& name
,
437 const Variant
& params
) {
438 return Object::attach(g_context
->createObject(name
.get(), params
));
441 Object
HHVM_FUNCTION(hphp_create_object_without_constructor
,
442 const String
& name
) {
443 return Object::attach(
444 g_context
->createObject(name
.get(), init_null_variant
, false)
448 Variant
HHVM_FUNCTION(hphp_get_property
, const Object
& obj
, const String
& cls
,
449 const String
& prop
) {
450 /* It's possible to get a ReflectionProperty for a property which
451 * no longer exists. Silentyly fail to match PHP5 behavior
453 return obj
->o_get(prop
, false /* error */, cls
);
456 void HHVM_FUNCTION(hphp_set_property
, const Object
& obj
, const String
& cls
,
457 const String
& prop
, const Variant
& value
) {
458 if (!cls
.empty() && RuntimeOption::EvalAuthoritativeMode
) {
460 "We've already made many assumptions about private variables. "
461 "You can't change accessibility in Whole Program mode"
465 obj
->o_set(prop
, value
, cls
);
468 Variant
HHVM_FUNCTION(hphp_get_static_property
, const String
& cls
,
471 auto const sd
= cls
.get();
472 auto const class_
= Unit::lookupClass(sd
);
474 raise_error("Non-existent class %s", sd
->data());
478 auto const lookup
= class_
->getSPropIgnoreLateInit(
479 force
? class_
: arGetContextClass(vmfp()),
483 raise_error("Class %s does not have a property named %s",
484 sd
->data(), prop
.get()->data());
486 if (!lookup
.accessible
) {
487 raise_error("Invalid access to class %s's property %s",
488 sd
->data(), prop
.get()->data());
490 return tvAsVariant(lookup
.val
);
493 void HHVM_FUNCTION(hphp_set_static_property
, const String
& cls
,
495 const Variant
& value
,
497 if (RuntimeOption::EvalAuthoritativeMode
) {
498 raise_error("Setting static properties through reflection is not "
499 "allowed in RepoAuthoritative mode");
501 auto const sd
= cls
.get();
502 auto const class_
= Unit::lookupClass(sd
);
504 if (!class_
) raise_error("Non-existent class %s", sd
->data());
508 auto const lookup
= class_
->getSPropIgnoreLateInit(
509 force
? class_
: arGetContextClass(vmfp()),
513 raise_error("Class %s does not have a property named %s",
514 cls
.get()->data(), prop
.get()->data());
516 if (!lookup
.accessible
) {
517 raise_error("Invalid access to class %s's property %s",
518 sd
->data(), prop
.get()->data());
521 auto const& sprop
= class_
->staticProperties()[lookup
.slot
];
522 auto const& tc
= sprop
.typeConstraint
;
523 auto const temp
= value
.asInitCellTmp();
524 if (RuntimeOption::EvalCheckPropTypeHints
> 0 && tc
.isCheckable()) {
525 tc
.verifyStaticProperty(&temp
, class_
, sprop
.cls
, prop
.get());
527 tvAsVariant(lookup
.val
) = value
;
531 * cls_or_obj: the name of a class or an instance of the class;
532 * cns_name: the name of the type constant of the class;
534 * If the type constant exists and is not abstract, this function
535 * returns the shape representing the type associated with the type
538 Array
HHVM_FUNCTION(type_structure
,
539 const Variant
& cls_or_obj
, const Variant
& cns_name
) {
540 auto const cns_sd
= cns_name
.getStringDataOrNull();
542 auto name
= cls_or_obj
.toString();
544 auto const typeAlias
= Unit::loadTypeAlias(name
.get());
547 raise_error("Non-existent type alias %s", name
.get()->data());
550 auto const typeStructure
= typeAlias
->typeStructure
;
551 assertx(!typeStructure
.empty());
552 assertx(typeStructure
.isDictOrDArray());
555 bool persistent
= true;
556 resolved
= TypeStructure::resolve(name
, typeStructure
, persistent
);
557 } catch (Exception
& e
) {
558 raise_error("resolving type alias %s failed. "
559 "Have you declared all classes in the type alias",
562 assertx(!resolved
.empty());
563 assertx(resolved
.isDictOrDArray());
567 auto const cls
= get_cls(cls_or_obj
);
570 raise_error("Class undefined: %s", cls_or_obj
.toString().get()->data());
573 auto const cls_sd
= cls
->name();
574 auto typeCns
= cls
->clsCnsGet(cns_sd
, true);
575 if (typeCns
.m_type
== KindOfUninit
) {
576 if (cls
->hasTypeConstant(cns_sd
, true)) {
577 raise_error("Type constant %s::%s is abstract",
578 cls_sd
->data(), cns_sd
->data());
580 raise_error("Non-existent type constant %s::%s",
581 cls_sd
->data(), cns_sd
->data());
585 assertx(isArrayLikeType(typeCns
.m_type
));
586 assertx(typeCns
.m_data
.parr
->isDictOrDArray());
587 assertx(typeCns
.m_data
.parr
->isStatic());
588 return Array::attach(typeCns
.m_data
.parr
);
591 String
HHVM_FUNCTION(hphp_get_original_class_name
, const String
& name
) {
592 Class
* cls
= Unit::loadClass(name
.get());
593 if (!cls
) return empty_string();
594 return cls
->nameStr();
598 void Reflection::ThrowReflectionExceptionObject(const Variant
& message
) {
599 Object inst
{s_ReflectionExceptionClass
};
601 g_context
->invokeFunc(s_ReflectionExceptionClass
->getCtor(),
602 make_vec_array(message
),
609 /////////////////////////////////////////////////////////////////////////////
610 // class ReflectionFuncHandle
612 const StaticString
s_ReflectionFuncHandle("ReflectionFuncHandle");
614 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getFileName
) {
615 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
616 if (func
->isBuiltin()) {
619 auto file
= func
->unit()->filepath()->data();
620 if (!file
) { file
= ""; }
621 if (file
[0] != '/') {
622 return String(RuntimeOption::SourceRoot
+ file
);
628 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getStartLine
) {
629 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
630 if (func
->isBuiltin()) {
633 return func
->line1();
636 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getEndLine
) {
637 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
638 if (func
->isBuiltin()) {
641 return func
->line2();
644 static Variant
HHVM_METHOD(ReflectionFunctionAbstract
, getDocComment
) {
645 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
646 auto const comment
= func
->docComment();
647 if (comment
== nullptr || comment
->empty()) {
649 } else if (func
->isBuiltin() && !HHVM_FUNCTION(hphp_debugger_attached
)) {
652 auto ret
= const_cast<StringData
*>(comment
);
658 static Array
get_function_static_variables(const Func
* func
) {
659 auto const& staticVars
= func
->staticVars();
661 auto size
= staticVars
.size();
664 for (size_t i
= 0; i
< staticVars
.size(); ++i
) {
665 const Func::SVInfo
&sv
= staticVars
[i
];
666 auto const staticLocalData
= rds::bindStaticLocal(func
, sv
.name
);
667 // FIXME: this should not require variant hops
670 staticLocalData
.isInit()
671 ? tvAsCVarRef(staticLocalData
.get()->ref
.cell())
678 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getStaticVariables
) {
679 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
680 return get_function_static_variables(func
);
683 static String
HHVM_METHOD(ReflectionFunctionAbstract
, getName
) {
684 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
685 auto ret
= const_cast<StringData
*>(func
->name());
689 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isHack
) {
690 if (RuntimeOption::EnableHipHopSyntax
) {
693 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
694 return func
->unit()->isHHFile();
697 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isInternal
) {
698 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
699 return func
->isBuiltin();
702 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isGenerator
) {
703 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
704 return func
->isGenerator();
707 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isAsync
) {
708 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
709 return func
->isAsync();
712 static bool HHVM_METHOD(ReflectionFunctionAbstract
, isVariadic
) {
713 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
714 return func
->hasVariadicCaptureParam();
717 static int64_t HHVM_METHOD(ReflectionFunctionAbstract
, getNumberOfParameters
) {
718 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
719 return func
->numParams();
722 // If we are in <?php and in PHP 7 mode w.r.t. scalar types
723 ALWAYS_INLINE
static bool isPhpTypeHintEnabled(const Func
* func
) {
724 return (!(func
->unit()->isHHFile() || RuntimeOption::EnableHipHopSyntax
) &&
725 RuntimeOption::PHP7_ScalarTypes
730 static Array
get_function_param_info(const Func
* func
) {
731 const Func::ParamInfoVec
& params
= func
->params();
732 VArrayInit
ai(func
->numParams());
734 for (int i
= 0; i
< func
->numParams(); ++i
) {
735 Array param
= Array::CreateDArray();
736 const Func::ParamInfo
& fpi
= params
[i
];
738 param
.set(s_index
, make_tv
<KindOfInt64
>(i
));
739 param
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->localNames()[i
]));
741 auto const nonExtendedConstraint
=
742 fpi
.typeConstraint
.hasConstraint() &&
743 !fpi
.typeConstraint
.isExtended();
744 auto const type
= nonExtendedConstraint
745 ? fpi
.typeConstraint
.typeName()
746 : staticEmptyString();
748 param
.set(s_type
, make_tv
<KindOfPersistentString
>(type
));
749 const StringData
* typeHint
= fpi
.userType
751 : staticEmptyString();
752 param
.set(s_type_hint
, make_tv
<KindOfPersistentString
>(typeHint
));
754 std::string
phpTypeHint(isPhpTypeHintEnabled(func
) ? typeHint
->toCppString() : "");
756 if (!phpTypeHint
.empty() && phpTypeHint
[0] == '?') {
757 phpTypeHint
= phpTypeHint
.substr(1);
758 param
.set(s_type_hint
, phpTypeHint
);
761 // callable typehint considered builtin; stdclass typehint is not
763 fpi
.typeConstraint
.isCallable() ||
764 (fpi
.typeConstraint
.underlyingDataType() &&
765 fpi
.typeConstraint
.underlyingDataType() != KindOfObject
768 param
.set(s_type_hint_builtin
, true_varNR
.tv());
769 // If we are in <?php and in PHP 7 mode w.r.t. scalar types, then we want
770 // the types to come back as PHP 7 style scalar types, not HH\ style
772 if (!phpTypeHint
.empty() && boost::starts_with(phpTypeHint
, "HH\\")) {
773 phpTypeHint
= phpTypeHint
.substr(3);
774 param
.set(s_type_hint
, phpTypeHint
);
777 param
.set(s_type_hint_builtin
, false_varNR
.tv());
779 param
.set(s_function
, make_tv
<KindOfPersistentString
>(func
->name()));
780 if (func
->preClass()) {
783 make_tv
<KindOfPersistentString
>(
784 func
->implCls() ? func
->implCls()->name()
785 : func
->preClass()->name()
789 if (!nonExtendedConstraint
|| fpi
.typeConstraint
.isNullable()) {
790 param
.set(s_nullable
, true_varNR
.tv());
791 param
.set(s_type_hint_nullable
, true_varNR
.tv());
793 param
.set(s_type_hint_nullable
, false_varNR
.tv());
797 Variant v
= default_arg_from_php_code(fpi
, func
, i
);
798 param
.set(s_default
, v
);
799 param
.set(s_defaultText
, make_tv
<KindOfPersistentString
>(fpi
.phpCode
));
802 if (func
->byRef(i
)) {
803 param
.set(s_ref
, true_varNR
.tv());
805 if (func
->isInOutWrapper() || fpi
.inout
) {
806 param
.set(s_inout
, true_varNR
.tv());
808 if (fpi
.isVariadic()) {
809 param
.set(s_is_variadic
, true_varNR
.tv());
812 Array userAttrs
= Array::Create();
813 for (auto it
= fpi
.userAttributes
.begin();
814 it
!= fpi
.userAttributes
.end(); ++it
) {
815 userAttrs
.set(StrNR(it
->first
), it
->second
);
817 param
.set(s_attributes
, VarNR(userAttrs
).tv());
819 ai
.append(VarNR(param
).tv());
822 auto arr
= ai
.toArray();
824 bool isOptional
= true;
825 for (int i
= func
->numParams() - 1; i
>= 0; i
--) {
826 auto& param
= asArrRef(arr
.lvalAt(i
));
828 isOptional
= isOptional
&& (param
.exists(s_default
) ||
829 param
.exists(s_is_variadic
));
830 param
.set(s_is_optional
, isOptional
);
835 // helper for getParameters
836 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getParamInfo
) {
837 // FIXME: each parameter info should be HNI with a handle to the
839 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
840 return get_function_param_info(func
);
843 // helper for getReturnTypeText
844 static String
HHVM_METHOD(ReflectionFunctionAbstract
, getReturnTypeHint
) {
845 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
846 auto retTypeSD
= func
->returnUserType();
847 if (retTypeSD
&& retTypeSD
->size()) {
848 auto ret
= const_cast<StringData
*>(retTypeSD
);
854 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getRetTypeInfo
) {
855 Array retTypeInfo
= Array::Create();
856 auto name
= HHVM_MN(ReflectionFunctionAbstract
, getReturnTypeHint
)(this_
);
857 if (name
&& !name
.empty()) {
858 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
859 auto retType
= func
->returnTypeConstraint();
860 if (retType
.isNullable()) {
861 retTypeInfo
.set(s_type_hint_nullable
, true_varNR
.tv());
862 if (isPhpTypeHintEnabled(func
)) {
863 name
= name
.substr(1); //removes '?' - e.g. ?int -> int
866 retTypeInfo
.set(s_type_hint_nullable
, false_varNR
.tv());
870 retType
.isCallable() || // callable type hint is considered builtin
871 (retType
.underlyingDataType() &&
872 retType
.underlyingDataType() != KindOfObject
875 retTypeInfo
.set(s_type_hint_builtin
, true_varNR
.tv());
876 // If we are in <?php and in PHP 7 mode w.r.t. scalar types, then we want
877 // the types to come back as PHP 7 style scalar types, not HH\ style
879 if (isPhpTypeHintEnabled(func
) && boost::starts_with(name
.toCppString(), "HH\\")) {
880 name
= name
.substr(3);
883 retTypeInfo
.set(s_type_hint_builtin
, false_varNR
.tv());
886 name
= staticEmptyString();
887 retTypeInfo
.set(s_type_hint_nullable
, false_varNR
.tv());
888 retTypeInfo
.set(s_type_hint_builtin
, false_varNR
.tv());
890 retTypeInfo
.set(s_type_hint
, name
);
895 static Array
get_function_user_attributes(const Func
* func
) {
896 auto userAttrs
= func
->userAttributes();
898 DArrayInit
ai(userAttrs
.size());
899 for (auto it
= userAttrs
.begin(); it
!= userAttrs
.end(); ++it
) {
900 ai
.set(VarNR::MakeKey(StrNR(it
->first
).asString()).tv(), it
->second
);
905 static Array
HHVM_METHOD(ReflectionFunctionAbstract
, getAttributesNamespaced
) {
906 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
907 return get_function_user_attributes(func
);
910 // ------------------------- class ReflectionMethod
912 // helper for __construct
913 static bool HHVM_METHOD(ReflectionMethod
, __init
,
914 const Variant
& cls_or_object
, const String
& meth_name
) {
915 auto const cls
= get_cls(cls_or_object
);
916 if (!cls
|| meth_name
.isNull()) {
917 // caller raises exception
920 auto const func
= get_method_func(cls
, meth_name
);
922 // caller raises exception
925 assertx(func
->isMethod());
926 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
930 static bool HHVM_METHOD(ReflectionMethod
, isFinal
) {
931 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
932 return func
->attrs() & AttrFinal
;
935 static bool HHVM_METHOD(ReflectionMethod
, isAbstract
) {
936 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
937 return func
->attrs() & AttrAbstract
;
940 static bool HHVM_METHOD(ReflectionMethod
, isPublic
) {
941 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
942 return func
->attrs() & AttrPublic
;
945 static bool HHVM_METHOD(ReflectionMethod
, isProtected
) {
946 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
947 return func
->attrs() & AttrProtected
;
950 static bool HHVM_METHOD(ReflectionMethod
, isPrivate
) {
951 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
952 return func
->attrs() & AttrPrivate
;
955 static bool HHVM_METHOD(ReflectionMethod
, isStatic
) {
956 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
957 return func
->attrs() & AttrStatic
;
960 static bool HHVM_METHOD(ReflectionMethod
, isConstructor
) {
961 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
962 return isConstructor(func
);
965 static int HHVM_METHOD(ReflectionMethod
, getModifiers
) {
966 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
967 return get_modifiers(func
->attrs(), false, false);
970 // private helper for getPrototype
971 static String
HHVM_METHOD(ReflectionMethod
, getPrototypeClassname
) {
972 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
973 const Class
*prototypeCls
= nullptr;
974 if (func
->baseCls() != nullptr && func
->baseCls() != func
->implCls()) {
975 prototypeCls
= func
->baseCls();
976 const Class
*result
= get_prototype_class_from_interfaces(
978 if (result
) { prototypeCls
= result
; }
979 } else if (func
->isMethod()) {
980 // lookup the prototype in the interfaces
981 prototypeCls
= get_prototype_class_from_interfaces(func
->implCls(), func
);
984 auto ret
= const_cast<StringData
*>(prototypeCls
->name());
990 // private helper for getDeclaringClass
991 static String
HHVM_METHOD(ReflectionMethod
, getDeclaringClassname
) {
992 auto const func
= ReflectionFuncHandle::GetFuncFor(this_
);
993 auto ret
= const_cast<StringData
*>(func
->implCls()->name());
997 // ------------------------- class ReflectionFile
999 const StaticString
s_ReflectionFileHandle("ReflectionFileHandle");
1001 // helper for __construct
1002 static String
HHVM_METHOD(ReflectionFile
, __init
, const String
& name
) {
1003 if (name
.isNull()) {
1004 Reflection::ThrowReflectionExceptionObject(
1005 "Tried to construct ReflectionFile but the name was null"
1009 const Unit
* unit
= lookupUnit(
1010 File::TranslatePath(name
).get(),
1013 Native::s_noNativeFuncs
1017 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1018 "File '{}' does not exist",
1023 ReflectionFileHandle::Get(this_
)->setUnit(unit
);
1025 return String::attach(const_cast<StringData
*>(unit
->filepath()));
1028 static Array
HHVM_METHOD(ReflectionFile
, getAttributesNamespaced
) {
1029 auto const unit
= ReflectionFileHandle::GetUnitFor(this_
);
1032 auto fileAttrs
= unit
->fileAttributes();
1033 DArrayInit
ai(fileAttrs
.size());
1035 for (auto it
= fileAttrs
.begin(); it
!= fileAttrs
.end(); ++it
) {
1036 ai
.set(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
1038 return ai
.toArray();
1041 // ------------------------- class ReflectionFunction
1043 // helper for __construct
1044 static bool HHVM_METHOD(ReflectionFunction
, __initName
, const String
& name
) {
1045 if (name
.isNull()) { return false; }
1046 const Func
* func
= Unit::loadFunc(name
.get());
1047 if (!func
) { return false; }
1048 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
1052 // helper for __construct
1053 static bool HHVM_METHOD(ReflectionFunction
, __initClosure
,
1054 const Object
& closure
) {
1055 auto const cls
= get_cls(closure
);
1057 if (!cls
) { return false; }
1058 const Func
* func
= cls
->lookupMethod(s___invoke
.get());
1060 // caller raises exception
1063 assertx(func
->isClosureBody());
1064 assertx(func
->implCls()->isScopedClosure());
1065 ReflectionFuncHandle::Get(this_
)->setFunc(func
);
1069 const StaticString
s_ExpectedClosureInstance("Expected closure instance");
1071 // helper for getClosureScopeClass
1072 static Variant
HHVM_METHOD(ReflectionFunction
, getClosureScopeClassname
,
1073 const Object
& closure
) {
1074 if (!closure
->instanceof(c_Closure::classof())) {
1075 SystemLib::throwExceptionObject(s_ExpectedClosureInstance
);
1077 if (auto scope
= c_Closure::fromObject(closure
.get())->getScope()) {
1078 return String(const_cast<StringData
*>(scope
->name()));
1080 return init_null_variant
;
1083 static Variant
HHVM_METHOD(ReflectionFunction
, getClosureThisObject
,
1084 const Object
& closure
) {
1085 if (!closure
->instanceof(c_Closure::classof())) {
1086 SystemLib::throwExceptionObject(s_ExpectedClosureInstance
);
1088 auto const clos
= c_Closure::fromObject(closure
.get());
1089 if (clos
->hasThis()) {
1090 return Object
{clos
->getThis()};
1092 return init_null_variant
;
1095 // helper for getStaticVariables
1096 static Array
HHVM_METHOD(ReflectionFunction
, getClosureUseVariables
,
1097 const Object
& closure
) {
1098 auto const cls
= get_cls(closure
);
1100 MixedArrayInit
ai(cls
->numDeclProperties());
1101 auto propVal
= closure
->propVec();
1102 for (auto const& prop
: cls
->declProperties()) {
1103 // Closure static locals are represented as special instance properties
1104 // with a mangled name.
1105 if (prop
.name
->data()[0] == '8') {
1106 static const char prefix
[] = "86static_";
1107 assertx(0 == strncmp(prop
.name
->data(), prefix
, sizeof prefix
- 1));
1108 String
strippedName(prop
.name
->data() + sizeof prefix
- 1,
1109 prop
.name
->size() - sizeof prefix
+ 1,
1111 ai
.setUnknownKey(VarNR(strippedName
), tvAsCVarRef(propVal
));
1113 ai
.setWithRef(StrNR(prop
.name
), *propVal
);
1117 return ai
.toArray();
1120 /////////////////////////////////////////////////////////////////////////////
1121 // class ReflectionClass
1123 const StaticString
s_ReflectionClassHandle("ReflectionClassHandle");
1125 // helper for __construct
1126 static String
HHVM_METHOD(ReflectionClass
, __init
, const String
& name
) {
1127 return ReflectionClassHandle::Get(this_
)->init(name
);
1130 static String
HHVM_METHOD(ReflectionClass
, getName
) {
1131 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1132 return cls
->nameStr();
1135 static String
HHVM_METHOD(ReflectionClass
, getParentName
) {
1136 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1137 return cls
->parentStr();
1140 static bool HHVM_METHOD(ReflectionClass
, isHack
) {
1141 if (RuntimeOption::EnableHipHopSyntax
) {
1144 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1145 return cls
->preClass()->unit()->isHHFile();
1148 static bool HHVM_METHOD(ReflectionClass
, isInternal
) {
1149 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1150 return cls
->attrs() & AttrBuiltin
;
1153 static bool HHVM_METHOD(ReflectionClass
, isInstantiable
) {
1154 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1155 return !(cls
->attrs() & (AttrAbstract
| AttrInterface
| AttrTrait
| AttrEnum
))
1156 && (cls
->getCtor()->attrs() & AttrPublic
);
1159 static bool HHVM_METHOD(ReflectionClass
, isFinal
) {
1160 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1161 return cls
->attrs() & AttrFinal
;
1164 static bool HHVM_METHOD(ReflectionClass
, isAbstract
) {
1165 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1166 return cls
->attrs() & AttrAbstract
;
1169 static bool HHVM_METHOD(ReflectionClass
, isInterface
) {
1170 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1171 return cls
->attrs() & AttrInterface
;
1174 static bool HHVM_METHOD(ReflectionClass
, isTrait
) {
1175 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1176 return cls
->attrs() & AttrTrait
;
1179 static bool HHVM_METHOD(ReflectionClass
, isEnum
) {
1180 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1181 return cls
->attrs() & AttrEnum
;
1184 static int HHVM_METHOD(ReflectionClass
, getModifiers
) {
1185 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1186 return get_modifiers(cls
->attrs(), true, false);
1189 static Variant
HHVM_METHOD(ReflectionClass
, getFileName
) {
1190 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1191 if (cls
->attrs() & AttrBuiltin
) {
1194 auto file
= cls
->preClass()->unit()->filepath()->data();
1195 if (!file
) { file
= ""; }
1196 if (file
[0] != '/') {
1197 return String(RuntimeOption::SourceRoot
+ file
);
1199 return String(file
);
1203 static Variant
HHVM_METHOD(ReflectionClass
, getStartLine
) {
1204 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1205 if (cls
->isBuiltin()) {
1208 return cls
->preClass()->line1();
1211 static Variant
HHVM_METHOD(ReflectionClass
, getEndLine
) {
1212 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1213 if (cls
->isBuiltin()) {
1216 return cls
->preClass()->line2();
1219 static Variant
HHVM_METHOD(ReflectionClass
, getDocComment
) {
1220 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1221 auto const pcls
= cls
->preClass();
1222 auto const comment
= pcls
->docComment();
1223 if (comment
== nullptr || comment
->empty()) {
1225 } else if (pcls
->isBuiltin() && !HHVM_FUNCTION(hphp_debugger_attached
)) {
1228 auto ret
= const_cast<StringData
*>(comment
);
1233 static Array
HHVM_METHOD(ReflectionClass
, getRequirementNames
) {
1234 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1235 if (!(cls
->attrs() & (AttrTrait
| AttrInterface
))) {
1236 // requirements are applied to abstract/concrete classes when they use
1237 // a trait / implement an interface
1238 return empty_varray();
1241 auto const& requirements
= cls
->allRequirements();
1242 auto numReqs
= requirements
.size();
1244 return empty_varray();
1247 VArrayInit
pai(numReqs
);
1248 for (int i
= 0; i
< numReqs
; ++i
) {
1249 auto const& req
= requirements
[i
];
1250 pai
.append(Variant
{const_cast<StringData
*>(req
->name())});
1252 return pai
.toArray();
1255 static Array
HHVM_METHOD(ReflectionClass
, getInterfaceNames
) {
1256 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1258 auto st
= req::make
<c_Set
>();
1259 auto const& allIfaces
= cls
->allInterfaces();
1260 st
->reserve(allIfaces
.size());
1262 for (auto const& interface
: cls
->declInterfaces()) {
1263 st
->add(const_cast<StringData
*>(interface
->name()));
1265 if (allIfaces
.size() > cls
->declInterfaces().size()) {
1266 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1267 auto const& interface
= allIfaces
[i
];
1268 st
->add(const_cast<StringData
*>(interface
->name()));
1271 return st
->toVArray();
1274 static Array
HHVM_METHOD(ReflectionClass
, getTraitNames
) {
1275 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1276 auto const& traits
= cls
->preClass()->usedTraits();
1277 VArrayInit
ai(traits
.size());
1278 for (const StringData
* traitName
: traits
) {
1279 ai
.append(Variant
{const_cast<StringData
*>(traitName
)});
1281 return ai
.toArray();
1284 static Array
get_trait_alias_info(const Class
* cls
) {
1285 auto const& aliases
= cls
->traitAliases();
1287 if (aliases
.size()) {
1288 DArrayInit
ai(aliases
.size());
1290 for (auto const& namePair
: aliases
) {
1291 ai
.set(StrNR(namePair
.first
), VarNR(namePair
.second
).tv());
1293 return ai
.toArray();
1295 // Even if we have alias rules, if we're in repo mode, they will be applied
1296 // during the trait flattening step, and we won't populate traitAliases()
1298 auto const& rules
= cls
->preClass()->traitAliasRules();
1300 DArrayInit
ai(rules
.size());
1302 for (auto const& rule
: rules
) {
1303 auto namePair
= rule
.asNamePair();
1304 ai
.set(StrNR(namePair
.first
), VarNR(namePair
.second
).tv());
1306 return ai
.toArray();
1310 static Array
HHVM_METHOD(ReflectionClass
, getTraitAliases
) {
1311 return get_trait_alias_info(ReflectionClassHandle::GetClassFor(this_
));
1314 static bool HHVM_METHOD(ReflectionClass
, hasMethod
, const String
& name
) {
1315 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1316 return (get_method_func(cls
, name
) != nullptr);
1320 const Class
* get_class_from_name(const String
& name
) {
1321 auto const cls
= Unit::loadClass(name
.get());
1323 auto message
= folly::sformat(
1324 "class {} could not be loaded",
1327 Reflection::ThrowReflectionExceptionObject(message
);
1333 // helper for getMethods: returns a Set
1334 static Object
HHVM_STATIC_METHOD(
1337 const String
& clsname
,
1339 auto const cls
= get_class_from_name(clsname
);
1340 Attr mask
= attrs_from_modifiers(filter
, false);
1342 // At each step, we fetch from the PreClass is important because the
1343 // order in which getMethods returns matters
1344 req::StringIFastSet visitedMethods
;
1345 auto st
= req::make
<c_Set
>();
1346 st
->reserve(cls
->numMethods());
1348 auto add
= [&] (const Func
* m
) {
1349 if (m
->isGenerated()) return;
1350 if (!visitedMethods
.insert(m
->nameStr()).second
) return;
1351 if (m
->attrs() & mask
) {
1352 st
->add(HHVM_FN(strtolower
)(m
->nameStr()).get());
1356 std::function
<void(const Class
*)> collect
;
1357 std::function
<void(const Class
*)> collectInterface
;
1359 collect
= [&] (const Class
* clas
) {
1362 auto const methods
= clas
->preClass()->methods();
1363 auto const numMethods
= clas
->preClass()->numMethods();
1365 auto numDeclMethods
= clas
->preClass()->numDeclMethods();
1366 if (numDeclMethods
== -1) numDeclMethods
= numMethods
;
1368 // Add declared methods.
1369 for (Slot i
= 0; i
< numDeclMethods
; ++i
) {
1373 // Recurse; we need to order the parent's methods before our trait methods.
1374 collect(clas
->parent());
1376 for (Slot i
= numDeclMethods
; i
< numMethods
; ++i
) {
1377 // For repo mode, where trait methods are flattened at compile-time.
1380 for (Slot i
= clas
->traitsBeginIdx(); i
< clas
->traitsEndIdx(); ++i
) {
1381 // For non-repo mode, where they are added at Class-creation time.
1382 add(clas
->getMethod(i
));
1386 collectInterface
= [&] (const Class
* iface
) {
1389 size_t const numMethods
= iface
->preClass()->numMethods();
1390 Func
* const* methods
= iface
->preClass()->methods();
1391 for (Slot i
= 0; i
< numMethods
; ++i
) {
1395 for (auto const& parentIface
: iface
->declInterfaces()) {
1396 collectInterface(parentIface
.get());
1398 auto const& allIfaces
= iface
->allInterfaces();
1399 if (allIfaces
.size() > iface
->declInterfaces().size()) {
1400 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1401 collectInterface(allIfaces
[i
].get());
1406 collect(const_cast<Class
*>(cls
));
1408 // concrete classes should already have all of their methods present
1409 if (((AttrPublic
| AttrAbstract
| AttrStatic
) & mask
) &&
1410 cls
->attrs() & (AttrInterface
| AttrAbstract
| AttrTrait
)) {
1411 for (auto const& interface
: cls
->declInterfaces()) {
1412 collectInterface(interface
.get());
1414 auto const& allIfaces
= cls
->allInterfaces();
1415 if (allIfaces
.size() > cls
->declInterfaces().size()) {
1416 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
1417 auto const& interface
= allIfaces
[i
];
1418 collectInterface(interface
.get());
1422 return Object(std::move(st
));
1425 static bool HHVM_METHOD(ReflectionClass
, hasConstant
, const String
& name
) {
1426 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1427 return cls
->hasConstant(name
.get());
1430 static Variant
HHVM_METHOD(ReflectionClass
, getConstant
, const String
& name
) {
1431 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1432 auto value
= cls
->clsCnsGet(name
.get());
1433 return (value
.m_type
== KindOfUninit
) ? false_varNR
: cellAsCVarRef(value
);
1437 void addClassConstantNames(const Class
* cls
,
1438 const req::ptr
<c_Set
>& st
,
1440 assertx(cls
&& st
&& (st
->size() < limit
));
1442 auto numConsts
= cls
->numConstants();
1444 const Class::Const
* consts
= cls
->constants();
1445 for (size_t i
= 0; i
< numConsts
; i
++) {
1446 if (consts
[i
].cls
== cls
&& !consts
[i
].isAbstract() &&
1447 !consts
[i
].isType()) {
1448 st
->add(const_cast<StringData
*>(consts
[i
].name
.get()));
1451 if ((st
->size() < limit
) && cls
->parent()) {
1452 addClassConstantNames(cls
->parent(), st
, limit
);
1455 auto const& allIfaces
= cls
->allInterfaces();
1456 auto const numIfaces
= allIfaces
.size();
1457 for (int i
= 0; i
< numIfaces
&& (st
->size() < limit
); ++i
) {
1458 addClassConstantNames(allIfaces
[i
].get(), st
, limit
);
1462 // helper for getConstants
1463 static Array
HHVM_STATIC_METHOD(
1465 getOrderedConstants
,
1466 const String
& clsname
) {
1467 auto const cls
= get_class_from_name(clsname
);
1469 size_t numConsts
= cls
->numConstants();
1471 return Array::CreateDArray();
1474 auto st
= req::make
<c_Set
>();
1475 st
->reserve(numConsts
);
1477 addClassConstantNames(cls
, st
, numConsts
);
1478 assertx(st
->size() <= numConsts
);
1480 DArrayInit
ai(numConsts
);
1481 for (ArrayIter
iter(st
.get()); iter
; ++iter
) {
1482 auto constName
= iter
.first().getStringData();
1483 Cell value
= cls
->clsCnsGet(constName
);
1484 assertx(value
.m_type
!= KindOfUninit
);
1485 ai
.add(constName
, cellAsCVarRef(value
));
1487 return ai
.toArray();
1490 // helper for getAbstractConstantNames
1491 static Array
HHVM_STATIC_METHOD(
1493 getOrderedAbstractConstants
,
1494 const String
& clsname
) {
1495 auto const cls
= get_class_from_name(clsname
);
1497 size_t numConsts
= cls
->numConstants();
1499 return Array::CreateDArray();
1502 auto st
= req::make
<c_Set
>();
1503 st
->reserve(numConsts
);
1505 const Class::Const
* consts
= cls
->constants();
1506 for (size_t i
= 0; i
< numConsts
; i
++) {
1507 if (consts
[i
].isAbstract() && !consts
[i
].isType()) {
1508 st
->add(const_cast<StringData
*>(consts
[i
].name
.get()));
1512 assertx(st
->size() <= numConsts
);
1514 return st
->toDArray();
1519 // helper for getTypeConstants/hasTypeConstant
1520 static Array
HHVM_STATIC_METHOD(
1522 getOrderedTypeConstants
,
1523 const String
& clsname
) {
1524 auto const cls
= get_class_from_name(clsname
);
1526 size_t numConsts
= cls
->numConstants();
1528 return Array::Create();
1531 auto st
= req::make
<c_Set
>();
1532 st
->reserve(numConsts
);
1534 const Class::Const
* consts
= cls
->constants();
1535 for (size_t i
= 0; i
< numConsts
; i
++) {
1536 if (consts
[i
].isType()) {
1537 st
->add(const_cast<StringData
*>(consts
[i
].name
.get()));
1541 assertx(st
->size() <= numConsts
);
1542 return st
->toDArray();
1545 static Array
HHVM_METHOD(ReflectionClass
, getAttributesNamespaced
) {
1546 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1547 // UserAttributes are stored exclusively on the PreClass.
1548 auto const pcls
= cls
->preClass();
1550 auto userAttrs
= pcls
->userAttributes();
1551 DArrayInit
ai(userAttrs
.size());
1553 for (auto it
= userAttrs
.begin(); it
!= userAttrs
.end(); ++it
) {
1554 ai
.set(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
1556 return ai
.toArray();
1559 static Array
HHVM_METHOD(ReflectionClass
, getAttributesRecursiveNamespaced
) {
1560 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1562 Array ret
= Array::CreateDArray(); // no reasonable idea about sizing
1564 // UserAttributes are stored in the PreClass, so we must walk the parent
1565 // chain to get all of them; attribute specifications from child classes
1566 // win over parents.
1568 // const pointer to Class => pointer to a (const) Class
1569 Class
* currentCls
= const_cast<Class
*>(cls
);
1571 auto const pcls
= currentCls
->preClass();
1572 for (auto it
= pcls
->userAttributes().begin();
1573 it
!= pcls
->userAttributes().end(); ++it
) {
1574 if (!ret
.exists(StrNR(it
->first
))) {
1575 ret
.set(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
1578 } while ((currentCls
= currentCls
->parent()));
1583 static Array
HHVM_STATIC_METHOD(
1585 getClassPropertyInfo
,
1586 const String
& clsname
) {
1588 * FIXME: This implementation is pretty horrible and should be rewritten
1589 * when ReflectionProperty is ported.
1591 auto const cls
= get_class_from_name(clsname
);
1592 auto const properties
= cls
->declProperties();
1594 auto const& propInitVec
= cls
->getPropData()
1595 ? *cls
->getPropData()
1596 : cls
->declPropInit();
1598 auto ret
= Array::Create();
1599 for (auto const& declProp
: properties
) {
1600 auto slot
= declProp
.serializationIdx
;
1601 auto const& prop
= properties
[slot
];
1602 auto const& default_val
= tvAsCVarRef(&propInitVec
[slot
]);
1603 if (((prop
.attrs
& AttrPrivate
) == AttrPrivate
) && (prop
.cls
!= cls
)) {
1607 auto info
= Array::Create();
1608 set_instance_prop_info(info
, &prop
, default_val
);
1609 ret
.set(StrNR(prop
.name
), VarNR(info
).tv());
1612 // static properties
1613 auto const sProperties
= cls
->staticProperties();
1614 for (auto const& sProp
: sProperties
) {
1615 auto slot
= sProp
.serializationIdx
;
1616 auto const& prop
= sProperties
[slot
];
1617 if (((prop
.attrs
& AttrPrivate
) == AttrPrivate
) && (prop
.cls
!= cls
)) {
1621 auto info
= Array::Create();
1622 set_static_prop_info(info
, &prop
);
1623 ret
.set(StrNR(prop
.name
), VarNR(info
).tv());
1628 static Array
HHVM_METHOD(ReflectionClass
, getDynamicPropertyInfos
,
1629 const Object
& obj
) {
1630 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1631 auto obj_data
= obj
.get();
1632 assertx(obj_data
->getVMClass() == cls
);
1633 if (!obj_data
->hasDynProps()) {
1634 return empty_array();
1637 auto const dynPropArray
= obj_data
->dynPropArray();
1638 ArrayInit
ret(dynPropArray
->size(), ArrayInit::Mixed
{});
1639 IterateKV(dynPropArray
.get(), [&](Cell k
, TypedValue
) {
1640 if (RuntimeOption::EvalNoticeOnReadDynamicProp
) {
1641 auto const key
= tvCastToString(k
);
1642 obj_data
->raiseReadDynamicProp(key
.get());
1644 Array info
= Array::Create();
1645 set_dyn_prop_info(info
, k
, cls
->name());
1646 ret
.setValidKey(k
, VarNR(info
).tv());
1648 return ret
.toArray();
1651 static String
HHVM_METHOD(ReflectionClass
, getConstructorName
) {
1652 auto const cls
= ReflectionClassHandle::GetClassFor(this_
);
1653 auto ctor
= cls
->getDeclaredCtor();
1654 if (!ctor
) { return String(); }
1655 auto ret
= const_cast<StringData
*>(ctor
->name());
1659 void ReflectionClassHandle::wakeup(const Variant
& content
, ObjectData
* obj
) {
1660 if (!content
.isString()) {
1661 throw Exception("Native data of ReflectionClass should be a class name");
1664 String clsName
= content
.toString();
1665 String result
= init(clsName
);
1666 if (result
.empty()) {
1667 auto msg
= folly::format("Class {} does not exist", clsName
).str();
1668 Reflection::ThrowReflectionExceptionObject(String(msg
));
1671 // It is possible that $name does not get serialized. If a class derives
1672 // from ReflectionClass and the return value of its __sleep() function does
1673 // not contain 'name', $name gets ignored. So, we restore $name here.
1674 obj
->setProp(nullptr, s_name
.get(), result
.toCell());
1677 static Variant
reflection_extension_name_get(const Object
& this_
) {
1678 assertx(Reflection::s_ReflectionExtensionClass
);
1679 auto const name
= this_
->getProp(
1680 Reflection::s_ReflectionExtensionClass
,
1683 return tvCastToString(name
.tv());
1686 static Native::PropAccessor reflection_extension_Accessors
[] = {
1687 {"name", reflection_extension_name_get
,
1688 nullptr, nullptr, nullptr}, // name is read only
1689 {nullptr, nullptr, nullptr, nullptr, nullptr}
1692 static Native::PropAccessorMap reflection_extension_accessorsMap
1693 ((Native::PropAccessor
*)reflection_extension_Accessors
);
1695 struct reflection_extension_PropHandler
:
1696 Native::MapPropHandler
<reflection_extension_PropHandler
> {
1698 static constexpr Native::PropAccessorMap
& map
=
1699 reflection_extension_accessorsMap
;
1702 /////////////////////////////////////////////////////////////////////////////
1703 // class ReflectionTypeConstant
1705 const StaticString
s_ReflectionConstHandle("ReflectionConstHandle");
1707 // helper for __construct
1708 static bool HHVM_METHOD(ReflectionTypeConstant
, __init
,
1709 const Variant
& cls_or_obj
, const String
& const_name
) {
1710 auto const cls
= get_cls(cls_or_obj
);
1711 if (!cls
|| const_name
.isNull()) {
1712 // caller raises exception
1716 size_t numConsts
= cls
->numConstants();
1717 const Class::Const
* consts
= cls
->constants();
1719 for (size_t i
= 0; i
< numConsts
; i
++) {
1720 if (const_name
.same(consts
[i
].name
) && consts
[i
].isType()) {
1721 auto handle
= ReflectionConstHandle::Get(this_
);
1722 handle
->setConst(&consts
[i
]);
1723 handle
->setClass(cls
);
1728 // caller raises exception
1732 static String
HHVM_METHOD(ReflectionTypeConstant
, getName
) {
1733 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1734 auto ret
= const_cast<StringData
*>(cns
->name
.get());
1738 static bool HHVM_METHOD(ReflectionTypeConstant
, isAbstract
) {
1739 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1740 return cns
->isAbstract();
1743 // helper for getAssignedTypeText
1744 static String
HHVM_METHOD(ReflectionTypeConstant
, getAssignedTypeHint
) {
1745 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1747 if (isStringType(cns
->val
.m_type
)) {
1748 return String(cns
->val
.m_data
.pstr
);
1751 if (isArrayLikeType(cns
->val
.m_type
)) {
1752 auto const cls
= cns
->cls
;
1753 // go to the preclass to find the unresolved TypeStructure to get
1754 // the original assigned type text
1755 auto const preCls
= cls
->preClass();
1756 auto typeCns
= preCls
->lookupConstant(cns
->name
);
1757 assertx(typeCns
->isType());
1758 assertx(!typeCns
->isAbstract());
1759 assertx(isArrayLikeType(typeCns
->val().m_type
));
1760 return TypeStructure::toString(Array::attach(typeCns
->val().m_data
.parr
));
1766 // private helper for getDeclaringClass
1767 static String
HHVM_METHOD(ReflectionTypeConstant
, getDeclaringClassname
) {
1768 auto const cns
= ReflectionConstHandle::GetConstFor(this_
);
1769 auto cls
= cns
->cls
;
1770 auto ret
= const_cast<StringData
*>(cls
->name());
1774 // private helper for getClass
1775 static String
HHVM_METHOD(ReflectionTypeConstant
, getClassname
) {
1776 auto const cls
= ReflectionConstHandle::GetClassFor(this_
);
1777 auto ret
= const_cast<StringData
*>(cls
->name());
1781 /////////////////////////////////////////////////////////////////////////////
1782 // class ReflectionProperty
1784 const StaticString
s_ReflectionPropHandle("ReflectionPropHandle");
1786 static void HHVM_METHOD(ReflectionProperty
, __construct
,
1787 const Variant
& cls_or_obj
, const String
& prop_name
) {
1788 auto const cls
= get_cls(cls_or_obj
);
1790 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1791 "Class {} does not exist",
1792 cls_or_obj
.toString().toCppString()
1795 if (prop_name
.isNull()) {
1796 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1797 "Property {}:: does not exist",
1798 cls
->name()->toCppString()
1802 auto data
= Native::data
<ReflectionPropHandle
>(this_
);
1804 // is there a declared instance property?
1805 auto lookup
= cls
->getDeclPropIndex(cls
, prop_name
.get());
1806 auto propIdx
= lookup
.slot
;
1807 if (propIdx
!= kInvalidSlot
) {
1808 auto const prop
= &cls
->declProperties()[propIdx
];
1809 data
->setInstanceProp(prop
);
1810 this_
->setProp(nullptr, s_class
.get(),
1811 make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
1812 this_
->setProp(nullptr, s_name
.get(),
1813 make_tv
<KindOfPersistentString
>(prop
->name
));
1817 // is there a declared static property?
1818 lookup
= cls
->findSProp(cls
, prop_name
.get());
1819 propIdx
= lookup
.slot
;
1820 if (propIdx
!= kInvalidSlot
) {
1821 auto const prop
= &cls
->staticProperties()[propIdx
];
1822 data
->setStaticProp(prop
);
1823 this_
->setProp(nullptr, s_class
.get(),
1824 make_tv
<KindOfPersistentString
>(prop
->cls
->name()));
1825 this_
->setProp(nullptr, s_name
.get(),
1826 make_tv
<KindOfPersistentString
>(prop
->name
));
1830 // is there a dynamic property?
1831 if (cls_or_obj
.is(KindOfObject
)) {
1832 auto obj
= cls_or_obj
.toCObjRef().get();
1833 assertx(cls
== obj
->getVMClass());
1834 if (obj
->getAttribute(ObjectData::HasDynPropArr
) &&
1835 obj
->dynPropArray().exists(
1836 obj
->dynPropArray().convertKey
<IntishCast::CastSilently
>(prop_name
))
1838 if (RuntimeOption::EvalNoticeOnReadDynamicProp
) {
1839 obj
->raiseReadDynamicProp(prop_name
.get());
1841 data
->setDynamicProp();
1842 this_
->setProp(nullptr, s_class
.get(),
1843 make_tv
<KindOfPersistentString
>(cls
->name()));
1844 this_
->setProp(nullptr, s_name
.get(), prop_name
.toCell());
1849 Reflection::ThrowReflectionExceptionObject(folly::sformat(
1850 "Property {}::{} does not exist",
1851 cls
->name()->toCppString(),
1852 prop_name
.toCppString()
1858 [[noreturn
]] void reflection_property_internal_error() {
1859 raise_fatal_error("Internal error: Failed to retrieve the reflection object");
1864 static bool HHVM_METHOD(ReflectionProperty
, isPublic
) {
1865 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1866 switch (data
->getType()) {
1867 case ReflectionPropHandle::Type::Instance
:
1868 return data
->getProp()->attrs
& AttrPublic
;
1869 case ReflectionPropHandle::Type::Static
:
1870 return data
->getSProp()->attrs
& AttrPublic
;
1871 case ReflectionPropHandle::Type::Dynamic
:
1874 reflection_property_internal_error();
1878 static bool HHVM_METHOD(ReflectionProperty
, isProtected
) {
1879 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1880 switch (data
->getType()) {
1881 case ReflectionPropHandle::Type::Instance
:
1882 return data
->getProp()->attrs
& AttrProtected
;
1883 case ReflectionPropHandle::Type::Static
:
1884 return data
->getSProp()->attrs
& AttrProtected
;
1885 case ReflectionPropHandle::Type::Dynamic
:
1888 reflection_property_internal_error();
1892 static bool HHVM_METHOD(ReflectionProperty
, isPrivate
) {
1893 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1894 switch (data
->getType()) {
1895 case ReflectionPropHandle::Type::Instance
:
1896 return data
->getProp()->attrs
& AttrPrivate
;
1897 case ReflectionPropHandle::Type::Static
:
1898 return data
->getSProp()->attrs
& AttrPrivate
;
1899 case ReflectionPropHandle::Type::Dynamic
:
1902 reflection_property_internal_error();
1906 static bool HHVM_METHOD(ReflectionProperty
, isStatic
) {
1907 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1908 switch (data
->getType()) {
1909 case ReflectionPropHandle::Type::Static
:
1911 case ReflectionPropHandle::Type::Instance
:
1912 case ReflectionPropHandle::Type::Dynamic
:
1915 reflection_property_internal_error();
1919 static bool HHVM_METHOD(ReflectionProperty
, isDefault
) {
1920 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1921 switch (data
->getType()) {
1922 case ReflectionPropHandle::Type::Instance
:
1923 case ReflectionPropHandle::Type::Static
:
1925 case ReflectionPropHandle::Type::Dynamic
:
1928 reflection_property_internal_error();
1932 static int HHVM_METHOD(ReflectionProperty
, getModifiers
) {
1933 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1934 switch (data
->getType()) {
1935 case ReflectionPropHandle::Type::Instance
:
1936 return get_modifiers(data
->getProp()->attrs
, false, true);
1937 case ReflectionPropHandle::Type::Static
:
1938 return get_modifiers(data
->getSProp()->attrs
, false, true);
1939 case ReflectionPropHandle::Type::Dynamic
:
1940 return get_modifiers(AttrPublic
, false, true);
1942 reflection_property_internal_error();
1946 static TypedValue
HHVM_METHOD(ReflectionProperty
, getDocComment
) {
1947 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1948 const StringData
*comment
= nullptr;
1949 switch (data
->getType()) {
1950 case ReflectionPropHandle::Type::Instance
:
1951 comment
= data
->getProp()->preProp
->docComment();
1953 case ReflectionPropHandle::Type::Static
:
1954 comment
= data
->getSProp()->preProp
->docComment();
1956 case ReflectionPropHandle::Type::Dynamic
:
1959 reflection_property_internal_error();
1961 if (comment
== nullptr || comment
->empty()) {
1962 return tvReturn(false);
1964 Variant vComment
{comment
, Variant::PersistentStrInit
{}};
1965 return tvReturn(std::move(vComment
));
1969 static String
HHVM_METHOD(ReflectionProperty
, getTypeText
) {
1970 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1971 const StringData
*type
= nullptr;
1972 switch (data
->getType()) {
1973 case ReflectionPropHandle::Type::Instance
:
1974 type
= data
->getProp()->preProp
->userType();
1976 case ReflectionPropHandle::Type::Static
:
1977 type
= data
->getSProp()->preProp
->userType();
1979 case ReflectionPropHandle::Type::Dynamic
:
1982 reflection_property_internal_error();
1984 if (type
== nullptr || type
->empty()) {
1985 return empty_string();
1991 static TypedValue
HHVM_METHOD(ReflectionProperty
, getDefaultValue
) {
1992 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
1993 switch (data
->getType()) {
1994 case ReflectionPropHandle::Type::Instance
: {
1995 auto const prop
= data
->getProp();
1996 // We can't get propIdx from prop->idx (that's not what that is) or by
1997 // doing prop - prop->cls->declProperties().begin() (the prop can be in
1998 // the prop vector of a child class but it will always point to the class
1999 // it was declared in); so if we don't want to store propIdx we have to
2000 // look it up by name.
2001 auto lookup
= prop
->cls
->getDeclPropIndex(prop
->cls
, prop
->name
);
2002 auto propIdx
= lookup
.slot
;
2003 assertx(propIdx
!= kInvalidSlot
);
2004 prop
->cls
->initialize();
2005 auto const& propInitVec
= prop
->cls
->getPropData()
2006 ? *prop
->cls
->getPropData()
2007 : prop
->cls
->declPropInit();
2008 return tvReturn(tvAsCVarRef(&propInitVec
[propIdx
]));
2010 case ReflectionPropHandle::Type::Static
: {
2011 auto const prop
= data
->getSProp();
2012 prop
->cls
->initialize();
2013 return tvReturn(tvAsCVarRef(&prop
->val
));
2015 case ReflectionPropHandle::Type::Dynamic
:
2016 return make_tv
<KindOfNull
>();
2018 reflection_property_internal_error();
2022 static Array
HHVM_METHOD(ReflectionProperty
, getAttributesNamespaced
) {
2023 auto const data
= Native::data
<ReflectionPropHandle
>(this_
);
2024 auto attrs
= Array::CreateDict();
2025 switch (data
->getType()) {
2026 case ReflectionPropHandle::Type::Instance
: {
2027 auto const prop
= data
->getProp()->preProp
;
2028 for (auto attr
: prop
->userAttributes()) {
2029 attrs
.set(StrNR(attr
.first
), attr
.second
);
2033 case ReflectionPropHandle::Type::Static
: {
2034 auto const prop
= data
->getSProp()->preProp
;
2035 for (auto attr
: prop
->userAttributes()) {
2036 attrs
.set(StrNR(attr
.first
), attr
.second
);
2040 case ReflectionPropHandle::Type::Dynamic
:
2043 reflection_property_internal_error();
2047 /////////////////////////////////////////////////////////////////////////////
2048 // class ReflectionTypeAlias
2050 const StaticString
s_ReflectionTypeAliasHandle("ReflectionTypeAliasHandle");
2052 // helper for __construct:
2053 // caller throws exception when return value is false
2054 static String
HHVM_METHOD(ReflectionTypeAlias
, __init
, const String
& name
) {
2055 auto const typeAliasReq
= Unit::loadTypeAlias(name
.get());
2057 if (!typeAliasReq
) {
2058 return empty_string();
2061 ReflectionTypeAliasHandle::Get(this_
)->setTypeAliasReq(typeAliasReq
);
2062 return String::attach(const_cast<StringData
*>(typeAliasReq
->name
.get()));
2065 static Array
HHVM_METHOD(ReflectionTypeAlias
, getTypeStructure
) {
2066 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasReqFor(this_
);
2068 auto const typeStructure
= req
->typeStructure
;
2069 assertx(!typeStructure
.empty());
2070 assertx(typeStructure
.isDictOrDArray());
2071 return typeStructure
;
2074 static String
HHVM_METHOD(ReflectionTypeAlias
, getAssignedTypeText
) {
2075 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasReqFor(this_
);
2077 auto const typeStructure
= req
->typeStructure
;
2078 assertx(!typeStructure
.empty());
2079 assertx(typeStructure
.isDictOrDArray());
2080 return TypeStructure::toString(typeStructure
);
2083 static Array
HHVM_METHOD(ReflectionTypeAlias
, getAttributesNamespaced
) {
2084 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasReqFor(this_
);
2086 auto const userAttrs
= req
->userAttrs
;
2088 DArrayInit
ai(userAttrs
.size());
2089 for (auto& attr
: userAttrs
) {
2090 ai
.set(StrNR(attr
.first
), tvAsCVarRef(&attr
.second
));
2092 return ai
.toArray();
2095 static String
HHVM_METHOD(ReflectionTypeAlias
, getFileName
) {
2096 auto const req
= ReflectionTypeAliasHandle::GetTypeAliasReqFor(this_
);
2098 auto file
= req
->unit
->filepath()->data();
2099 if (!file
) { file
= ""; }
2100 if (file
[0] != '/') {
2101 return String(RuntimeOption::SourceRoot
+ file
);
2103 return String(file
);
2107 ///////////////////////////////////////////////////////////////////////////////
2108 struct ReflectionExtension final
: Extension
{
2109 ReflectionExtension() : Extension("reflection", "$Id$") { }
2110 void moduleInit() override
{
2111 HHVM_FE(hphp_create_object
);
2112 HHVM_FE(hphp_create_object_without_constructor
);
2113 HHVM_FE(hphp_get_extension_info
);
2114 HHVM_FE(hphp_get_original_class_name
);
2115 HHVM_FE(hphp_get_property
);
2116 HHVM_FE(hphp_get_static_property
);
2117 HHVM_FE(hphp_invoke
);
2118 HHVM_FE(hphp_invoke_method
);
2119 HHVM_FE(hphp_set_property
);
2120 HHVM_FE(hphp_set_static_property
);
2121 HHVM_FALIAS(HH
\\type_structure
, type_structure
);
2123 HHVM_ME(ReflectionFunctionAbstract
, getName
);
2124 HHVM_ME(ReflectionFunctionAbstract
, isHack
);
2125 HHVM_ME(ReflectionFunctionAbstract
, isInternal
);
2126 HHVM_ME(ReflectionFunctionAbstract
, isGenerator
);
2127 HHVM_ME(ReflectionFunctionAbstract
, isAsync
);
2128 HHVM_ME(ReflectionFunctionAbstract
, isVariadic
);
2129 HHVM_ME(ReflectionFunctionAbstract
, getFileName
);
2130 HHVM_ME(ReflectionFunctionAbstract
, getStartLine
);
2131 HHVM_ME(ReflectionFunctionAbstract
, getEndLine
);
2132 HHVM_ME(ReflectionFunctionAbstract
, getDocComment
);
2133 HHVM_ME(ReflectionFunctionAbstract
, getStaticVariables
);
2134 HHVM_ME(ReflectionFunctionAbstract
, getReturnTypeHint
);
2135 HHVM_ME(ReflectionFunctionAbstract
, getNumberOfParameters
);
2136 HHVM_ME(ReflectionFunctionAbstract
, getParamInfo
);
2137 HHVM_ME(ReflectionFunctionAbstract
, getAttributesNamespaced
);
2138 HHVM_ME(ReflectionFunctionAbstract
, getRetTypeInfo
);
2140 HHVM_ME(ReflectionMethod
, __init
);
2141 HHVM_ME(ReflectionMethod
, isFinal
);
2142 HHVM_ME(ReflectionMethod
, isAbstract
);
2143 HHVM_ME(ReflectionMethod
, isPublic
);
2144 HHVM_ME(ReflectionMethod
, isProtected
);
2145 HHVM_ME(ReflectionMethod
, isPrivate
);
2146 HHVM_ME(ReflectionMethod
, isStatic
);
2147 HHVM_ME(ReflectionMethod
, isConstructor
);
2148 HHVM_ME(ReflectionMethod
, getModifiers
);
2149 HHVM_ME(ReflectionMethod
, getPrototypeClassname
);
2150 HHVM_ME(ReflectionMethod
, getDeclaringClassname
);
2152 HHVM_ME(ReflectionFile
, __init
);
2153 HHVM_ME(ReflectionFile
, getAttributesNamespaced
);
2155 HHVM_ME(ReflectionFunction
, __initName
);
2156 HHVM_ME(ReflectionFunction
, __initClosure
);
2157 HHVM_ME(ReflectionFunction
, getClosureUseVariables
);
2158 HHVM_ME(ReflectionFunction
, getClosureScopeClassname
);
2159 HHVM_ME(ReflectionFunction
, getClosureThisObject
);
2161 HHVM_ME(ReflectionTypeConstant
, __init
);
2162 HHVM_ME(ReflectionTypeConstant
, getName
);
2163 HHVM_ME(ReflectionTypeConstant
, isAbstract
);
2164 HHVM_ME(ReflectionTypeConstant
, getAssignedTypeHint
);
2165 HHVM_ME(ReflectionTypeConstant
, getDeclaringClassname
);
2166 HHVM_ME(ReflectionTypeConstant
, getClassname
);
2168 HHVM_ME(ReflectionProperty
, __construct
);
2169 HHVM_ME(ReflectionProperty
, isPublic
);
2170 HHVM_ME(ReflectionProperty
, isProtected
);
2171 HHVM_ME(ReflectionProperty
, isPrivate
);
2172 HHVM_ME(ReflectionProperty
, isStatic
);
2173 HHVM_ME(ReflectionProperty
, isDefault
);
2174 HHVM_ME(ReflectionProperty
, getModifiers
);
2175 HHVM_ME(ReflectionProperty
, getDocComment
);
2176 HHVM_ME(ReflectionProperty
, getTypeText
);
2177 HHVM_ME(ReflectionProperty
, getDefaultValue
);
2178 HHVM_ME(ReflectionProperty
, getAttributesNamespaced
);
2180 HHVM_ME(ReflectionTypeAlias
, __init
);
2181 HHVM_ME(ReflectionTypeAlias
, getTypeStructure
);
2182 HHVM_ME(ReflectionTypeAlias
, getAttributesNamespaced
);
2183 HHVM_ME(ReflectionTypeAlias
, getAssignedTypeText
);
2184 HHVM_ME(ReflectionTypeAlias
, getFileName
);
2186 HHVM_ME(ReflectionClass
, __init
);
2187 HHVM_ME(ReflectionClass
, getName
);
2188 HHVM_ME(ReflectionClass
, getParentName
);
2189 HHVM_ME(ReflectionClass
, isHack
);
2190 HHVM_ME(ReflectionClass
, isInternal
);
2191 HHVM_ME(ReflectionClass
, isInstantiable
);
2192 HHVM_ME(ReflectionClass
, isInterface
);
2193 HHVM_ME(ReflectionClass
, isTrait
);
2194 HHVM_ME(ReflectionClass
, isEnum
);
2195 HHVM_ME(ReflectionClass
, isAbstract
);
2196 HHVM_ME(ReflectionClass
, isFinal
);
2197 HHVM_ME(ReflectionClass
, getModifiers
);
2198 HHVM_ME(ReflectionClass
, getFileName
);
2199 HHVM_ME(ReflectionClass
, getStartLine
);
2200 HHVM_ME(ReflectionClass
, getEndLine
);
2201 HHVM_ME(ReflectionClass
, getDocComment
);
2202 HHVM_ME(ReflectionClass
, getInterfaceNames
);
2203 HHVM_ME(ReflectionClass
, getRequirementNames
);
2204 HHVM_ME(ReflectionClass
, getTraitNames
);
2205 HHVM_ME(ReflectionClass
, getTraitAliases
);
2207 HHVM_ME(ReflectionClass
, hasMethod
);
2208 HHVM_STATIC_ME(ReflectionClass
, getMethodOrder
);
2210 HHVM_ME(ReflectionClass
, hasConstant
);
2211 HHVM_ME(ReflectionClass
, getConstant
);
2212 HHVM_STATIC_ME(ReflectionClass
, getOrderedConstants
);
2213 HHVM_STATIC_ME(ReflectionClass
, getOrderedAbstractConstants
);
2214 HHVM_STATIC_ME(ReflectionClass
, getOrderedTypeConstants
);
2216 HHVM_ME(ReflectionClass
, getAttributesNamespaced
);
2217 HHVM_ME(ReflectionClass
, getAttributesRecursiveNamespaced
);
2219 HHVM_STATIC_ME(ReflectionClass
, getClassPropertyInfo
);
2220 HHVM_ME(ReflectionClass
, getDynamicPropertyInfos
);
2221 HHVM_ME(ReflectionClass
, getConstructorName
);
2223 Native::registerNativeDataInfo
<ReflectionFuncHandle
>(
2224 s_ReflectionFuncHandle
.get());
2225 Native::registerNativeDataInfo
<ReflectionClassHandle
>(
2226 s_ReflectionClassHandle
.get());
2227 Native::registerNativeDataInfo
<ReflectionConstHandle
>(
2228 s_ReflectionConstHandle
.get());
2229 Native::registerNativeDataInfo
<ReflectionPropHandle
>(
2230 s_ReflectionPropHandle
.get());
2231 Native::registerNativeDataInfo
<ReflectionFileHandle
>(
2232 s_ReflectionFileHandle
.get());
2233 Native::registerNativeDataInfo
<ReflectionTypeAliasHandle
>(
2234 s_ReflectionTypeAliasHandle
.get(), Native::NO_SWEEP
);
2236 Native::registerNativePropHandler
2237 <reflection_extension_PropHandler
>(s_reflectionextension
);
2240 loadSystemlib("reflection-classes");
2241 loadSystemlib("reflection-internals-functions");
2242 loadSystemlib("reflection_hni");
2244 Reflection::s_ReflectionExceptionClass
=
2245 Unit::lookupClass(s_reflectionexception
.get());
2246 assertx(Reflection::s_ReflectionExceptionClass
);
2247 Reflection::s_ReflectionExtensionClass
=
2248 Unit::lookupClass(s_reflectionextension
.get());
2249 assertx(Reflection::s_ReflectionExtensionClass
);
2251 } s_reflection_extension
;
2253 ///////////////////////////////////////////////////////////////////////////////
2255 namespace DebuggerReflection
{
2257 static bool set_debugger_source_info(Array
&ret
, const char *file
, int line1
,
2259 if (!file
) file
= "";
2260 if (file
[0] != '/') {
2261 ret
.set(s_file
, String(RuntimeOption::SourceRoot
+ file
));
2263 ret
.set(s_file
, file
);
2265 ret
.set(s_line1
, make_tv
<KindOfInt64
>(line1
));
2266 ret
.set(s_line2
, make_tv
<KindOfInt64
>(line2
));
2267 return file
&& *file
;
2270 static void set_debugger_return_type_constraint(Array
&ret
, const StringData
* retType
) {
2271 if (retType
&& retType
->size()) {
2272 assertx(!retType
->isRefCounted());
2273 ret
.set(s_return_type
, make_tv
<KindOfPersistentString
>(retType
));
2275 ret
.set(s_return_type
, false_varNR
.tv());
2279 static void set_debugger_reflection_method_prototype_info(Array
& ret
,
2281 const Class
*prototypeCls
= nullptr;
2282 if (func
->baseCls() != nullptr && func
->baseCls() != func
->implCls()) {
2283 prototypeCls
= func
->baseCls();
2284 const Class
*result
= get_prototype_class_from_interfaces(
2285 prototypeCls
, func
);
2286 if (result
) prototypeCls
= result
;
2287 } else if (func
->isMethod()) {
2288 // lookup the prototype in the interfaces
2289 prototypeCls
= get_prototype_class_from_interfaces(func
->implCls(), func
);
2292 Array prototype
= Array::Create();
2293 prototype
.set(s_class
,
2294 make_tv
<KindOfPersistentString
>(prototypeCls
->name()));
2295 prototype
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2296 ret
.set(s_prototype
, prototype
);
2300 static void set_debugger_reflection_function_info(Array
& ret
,
2303 if (func
->isBuiltin()) {
2304 ret
.set(s_internal
, true_varNR
.tv());
2306 set_debugger_return_type_constraint(ret
, func
->returnUserType());
2309 set_doc_comment(ret
, func
->docComment(), func
->isBuiltin());
2312 ret
.set(s_params
, get_function_param_info(func
));
2315 ret
.set(s_static_variables
, get_function_static_variables(func
));
2318 ret
.set(s_attributes
, get_function_user_attributes(func
));
2320 ret
.set(s_is_async
, func
->isAsync());
2321 ret
.set(s_is_closure
, func
->isClosureBody());
2322 ret
.set(s_is_generator
, func
->isGenerator());
2325 static void set_debugger_reflection_method_info(Array
& ret
, const Func
* func
,
2327 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2328 set_attrs(ret
, get_modifiers(func
->attrs(), false, false));
2330 if (isConstructor(func
)) {
2331 ret
.set(s_constructor
, true_varNR
.tv());
2334 // If Func* is from a PreClass, it doesn't know about base classes etc.
2335 // Swap it out for the full version if possible.
2336 auto resolved_func
= func
->implCls()
2338 : cls
->lookupMethod(func
->name());
2340 if (!resolved_func
) {
2341 resolved_func
= func
;
2345 make_tv
<KindOfPersistentString
>(resolved_func
->implCls()->name()));
2346 set_debugger_reflection_function_info(ret
, resolved_func
);
2347 set_debugger_source_info(ret
, func
->unit()->filepath()->data(),
2348 func
->line1(), func
->line2());
2349 set_debugger_reflection_method_prototype_info(ret
, resolved_func
);
2352 Array
get_function_info(const String
& name
) {
2354 if (name
.get() == nullptr) return ret
;
2355 const Func
* func
= Unit::loadFunc(name
.get());
2356 if (!func
) return ret
;
2357 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(func
->name()));
2359 // setting parameters and static variables
2360 set_debugger_reflection_function_info(ret
, func
);
2361 set_debugger_source_info(ret
, func
->unit()->filepath()->data(),
2362 func
->line1(), func
->line2());
2366 Array
get_class_info(const String
& name
) {
2367 auto cls
= get_cls(name
);
2368 if (!cls
) return Array();
2371 ret
.set(s_name
, make_tv
<KindOfPersistentString
>(cls
->name()));
2372 ret
.set(s_extension
, empty_string_variant_ref
);
2373 ret
.set(s_parent
, make_tv
<KindOfPersistentString
>(cls
->preClass()->parent()));
2377 Array arr
= Array::Create();
2378 for (auto const& interface
: cls
->declInterfaces()) {
2379 arr
.set(interface
->nameStr(), make_tv
<KindOfInt64
>(1));
2381 auto const& allIfaces
= cls
->allInterfaces();
2382 if (allIfaces
.size() > cls
->declInterfaces().size()) {
2383 for (int i
= 0; i
< allIfaces
.size(); ++i
) {
2384 auto const& interface
= allIfaces
[i
];
2385 arr
.set(interface
->nameStr(), make_tv
<KindOfInt64
>(1));
2388 ret
.set(s_interfaces
, VarNR(arr
).tv());
2393 Array arr
= Array::Create();
2394 for (auto const& traitName
: cls
->preClass()->usedTraits()) {
2395 arr
.set(StrNR(traitName
), make_tv
<KindOfInt64
>(1));
2397 ret
.set(s_traits
, VarNR(arr
).tv());
2402 ret
.set(s_trait_aliases
, VarNR(get_trait_alias_info(cls
)).tv());
2407 if (cls
->attrs() & AttrBuiltin
) {
2408 ret
.set(s_internal
, true_varNR
.tv());
2410 if (cls
->attrs() & AttrFinal
) {
2411 ret
.set(s_final
, true_varNR
.tv());
2413 if (cls
->attrs() & AttrAbstract
) {
2414 ret
.set(s_abstract
, true_varNR
.tv());
2416 if (cls
->attrs() & AttrInterface
) {
2417 ret
.set(s_interface
, true_varNR
.tv());
2419 if (cls
->attrs() & AttrTrait
) {
2420 ret
.set(s_trait
, true_varNR
.tv());
2422 ret
.set(s_modifiers
, make_tv
<KindOfInt64
>(
2423 get_modifiers(cls
->attrs(), true, false))
2426 if (cls
->getCtor()->attrs() & AttrPublic
&&
2427 !(cls
->attrs() & AttrAbstract
) &&
2428 !(cls
->attrs() & AttrInterface
) &&
2429 !(cls
->attrs() & AttrTrait
)) {
2430 ret
.set(s_instantiable
, true_varNR
.tv());
2436 Array arr
= Array::Create();
2438 // Fetch from PreClass as:
2439 // - the order is important
2440 // - we want type profiling info
2441 // and neither of these are in the Class...
2442 Func
* const* methods
= cls
->preClass()->methods();
2443 size_t const numMethods
= cls
->preClass()->numMethods();
2444 for (Slot i
= 0; i
< numMethods
; ++i
) {
2445 const Func
* m
= methods
[i
];
2446 if (m
->isGenerated()) continue;
2448 auto lowerName
= HHVM_FN(strtolower
)(m
->nameStr());
2449 Array info
= Array::Create();
2450 set_debugger_reflection_method_info(info
, m
, cls
);
2451 arr
.set(lowerName
, VarNR(info
).tv());
2454 for (Slot i
= cls
->traitsBeginIdx(); i
< cls
->traitsEndIdx(); ++i
) {
2455 const Func
* m
= cls
->getMethod(i
);
2456 if (m
->isGenerated()) continue;
2458 auto lowerName
= HHVM_FN(strtolower
)(m
->nameStr());
2459 Array info
= Array::Create();
2460 set_debugger_reflection_method_info(info
, m
, cls
);
2461 arr
.set(lowerName
, VarNR(info
).tv());
2463 ret
.set(s_methods
, VarNR(arr
).tv());
2468 auto arr
= Array::Create();
2469 auto arrPriv
= Array::Create();
2470 auto arrIdx
= Array::Create();
2471 auto arrPrivIdx
= Array::Create();
2473 auto const properties
= cls
->declProperties();
2474 auto const& propInitVec
= cls
->declPropInit();
2475 auto const nProps
= cls
->numDeclProperties();
2477 for (Slot i
= 0; i
< nProps
; ++i
) {
2478 auto const& prop
= properties
[i
];
2479 auto const& default_val
= tvAsCVarRef(&propInitVec
[i
]);
2480 auto info
= Array::Create();
2481 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
2482 if (prop
.cls
== cls
) {
2483 set_instance_prop_info(info
, &prop
, default_val
);
2484 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
2485 arrPrivIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2489 set_instance_prop_info(info
, &prop
, default_val
);
2490 arr
.set(StrNR(prop
.name
), VarNR(info
).tv());
2491 arrIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2494 for (auto const& prop
: cls
->staticProperties()) {
2495 auto info
= Array::Create();
2496 if ((prop
.attrs
& AttrPrivate
) == AttrPrivate
) {
2497 if (prop
.cls
== cls
) {
2498 set_static_prop_info(info
, &prop
);
2499 arrPriv
.set(StrNR(prop
.name
), VarNR(info
).tv());
2500 arrPrivIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2504 set_static_prop_info(info
, &prop
);
2505 arr
.set(StrNR(prop
.name
), VarNR(info
).tv());
2506 arrIdx
.set(StrNR(prop
.name
), prop
.serializationIdx
);
2508 ret
.set(s_properties
, VarNR(arr
).tv());
2509 ret
.set(s_private_properties
, VarNR(arrPriv
).tv());
2510 ret
.set(s_properties_index
, VarNR(arrIdx
).tv());
2511 ret
.set(s_private_properties_index
, VarNR(arrPrivIdx
).tv());
2516 Array arr
= Array::Create();
2518 size_t numConsts
= cls
->numConstants();
2519 const Class::Const
* consts
= cls
->constants();
2521 for (size_t i
= 0; i
< numConsts
; i
++) {
2522 // Note: hphpc doesn't include inherited constants in
2523 // get_class_constants(), so mimic that behavior
2524 if (consts
[i
].cls
== cls
) {
2525 Cell value
= cls
->clsCnsGet(consts
[i
].name
);
2526 assertx(value
.m_type
!= KindOfUninit
);
2527 arr
.set(StrNR(consts
[i
].name
), cellAsCVarRef(value
));
2531 ret
.set(s_constants
, VarNR(arr
).tv());
2535 const PreClass
* pcls
= cls
->preClass();
2536 set_debugger_source_info(ret
, pcls
->unit()->filepath()->data(),
2537 pcls
->line1(), pcls
->line2());
2538 set_doc_comment(ret
, pcls
->docComment(), pcls
->isBuiltin());
2543 Array arr
= Array::Create();
2544 const PreClass
* pcls
= cls
->preClass();
2545 for (auto it
= pcls
->userAttributes().begin();
2546 it
!= pcls
->userAttributes().end(); ++it
) {
2547 arr
.set(StrNR(it
->first
), tvAsCVarRef(&it
->second
));
2549 ret
.set(s_attributes
, VarNR(arr
).tv());
2557 ///////////////////////////////////////////////////////////////////////////////