PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/runtime/ext/std/ext_std_classobj.cpp

https://gitlab.com/iranjith4/hhvm
C++ | 385 lines | 296 code | 57 blank | 32 comment | 66 complexity | 8e436a6a158cdf20c75c289d9bf98e7e MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2016 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. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/std/ext_std_classobj.h"
  18. #include "hphp/runtime/base/array-init.h"
  19. #include "hphp/runtime/ext/array/ext_array.h"
  20. #include "hphp/runtime/ext/string/ext_string.h"
  21. #include "hphp/runtime/vm/jit/translator-inline.h"
  22. #include "hphp/runtime/vm/jit/translator.h"
  23. #include "hphp/runtime/vm/unit.h"
  24. namespace HPHP {
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // helpers
  27. static inline StrNR ctxClassName() {
  28. Class* ctx = g_context->getContextClass();
  29. return ctx ? ctx->nameStr() : StrNR(staticEmptyString());
  30. }
  31. static const Class* get_cls(const Variant& class_or_object) {
  32. Class* cls = nullptr;
  33. if (class_or_object.is(KindOfObject)) {
  34. ObjectData* obj = class_or_object.toCObjRef().get();
  35. cls = obj->getVMClass();
  36. } else if (class_or_object.isArray()) {
  37. // do nothing but avoid the toString conversion notice
  38. } else {
  39. cls = Unit::loadClass(class_or_object.toString().get());
  40. }
  41. return cls;
  42. }
  43. ///////////////////////////////////////////////////////////////////////////////
  44. Array HHVM_FUNCTION(get_declared_classes) {
  45. return Unit::getClassesInfo();
  46. }
  47. Array HHVM_FUNCTION(get_declared_interfaces) {
  48. return Unit::getInterfacesInfo();
  49. }
  50. Array HHVM_FUNCTION(get_declared_traits) {
  51. return Unit::getTraitsInfo();
  52. }
  53. bool HHVM_FUNCTION(class_alias, const String& original, const String& alias,
  54. bool autoload /* = true */) {
  55. auto const origClass =
  56. autoload ? Unit::loadClass(original.get())
  57. : Unit::lookupClass(original.get());
  58. if (!origClass) {
  59. raise_warning("Class %s not found", original.data());
  60. return false;
  61. }
  62. if (origClass->isBuiltin()) {
  63. raise_warning(
  64. "First argument of class_alias() must be a name of user defined class");
  65. return false;
  66. }
  67. return Unit::aliasClass(origClass, alias.get());
  68. }
  69. bool HHVM_FUNCTION(class_exists, const String& class_name,
  70. bool autoload /* = true */) {
  71. return Unit::classExists(class_name.get(), autoload, ClassKind::Class);
  72. }
  73. bool HHVM_FUNCTION(interface_exists, const String& interface_name,
  74. bool autoload /* = true */) {
  75. return
  76. Unit::classExists(interface_name.get(), autoload, ClassKind::Interface);
  77. }
  78. bool HHVM_FUNCTION(trait_exists, const String& trait_name,
  79. bool autoload /* = true */) {
  80. return Unit::classExists(trait_name.get(), autoload, ClassKind::Trait);
  81. }
  82. bool HHVM_FUNCTION(enum_exists, const String& enum_name,
  83. bool autoload /* = true */) {
  84. Class* cls = Unit::getClass(enum_name.get(), autoload);
  85. return cls && isEnum(cls);
  86. }
  87. Variant HHVM_FUNCTION(get_class_methods, const Variant& class_or_object) {
  88. auto const cls = get_cls(class_or_object);
  89. if (!cls) return init_null();
  90. VMRegAnchor _;
  91. auto retVal = Array::attach(PackedArray::MakeReserve(cls->numMethods()));
  92. Class::getMethodNames(
  93. cls,
  94. arGetContextClassFromBuiltin(vmfp()),
  95. retVal
  96. );
  97. return Variant::attach(HHVM_FN(array_values)(retVal)).toArray();
  98. }
  99. Array HHVM_FUNCTION(get_class_constants, const String& className) {
  100. auto const cls = Unit::loadClass(className.get());
  101. if (cls == NULL) {
  102. return Array::attach(PackedArray::MakeReserve(0));
  103. }
  104. auto const numConstants = cls->numConstants();
  105. ArrayInit arrayInit(numConstants, ArrayInit::Map{});
  106. auto const consts = cls->constants();
  107. for (size_t i = 0; i < numConstants; i++) {
  108. // Note: hphpc doesn't include inherited constants in
  109. // get_class_constants(), so mimic that behavior
  110. if (consts[i].cls == cls && !consts[i].isAbstract() &&
  111. !consts[i].isType()) {
  112. auto const name = const_cast<StringData*>(consts[i].name.get());
  113. Cell value = consts[i].val;
  114. // Handle dynamically set constants
  115. if (value.m_type == KindOfUninit) {
  116. value = cls->clsCnsGet(consts[i].name);
  117. }
  118. assert(value.m_type != KindOfUninit);
  119. arrayInit.set(name, cellAsCVarRef(value));
  120. }
  121. }
  122. return arrayInit.toArray();
  123. }
  124. Variant HHVM_FUNCTION(get_class_vars, const String& className) {
  125. const Class* cls = Unit::loadClass(className.get());
  126. if (!cls) {
  127. return false;
  128. }
  129. cls->initialize();
  130. auto const propInfo = cls->declProperties();
  131. auto const numDeclProps = cls->numDeclProperties();
  132. auto const numSProps = cls->numStaticProperties();
  133. // The class' instance property initialization template is in different
  134. // places, depending on whether it has any request-dependent initializers
  135. // (i.e. constants)
  136. auto const& declPropInitVec = cls->declPropInit();
  137. auto const propVals = !cls->pinitVec().empty()
  138. ? cls->getPropData()
  139. : &declPropInitVec;
  140. assert(propVals != nullptr);
  141. assert(propVals->size() == numDeclProps);
  142. // For visibility checks
  143. CallerFrame cf;
  144. auto ctx = arGetContextClass(cf());
  145. ArrayInit arr(numDeclProps + numSProps, ArrayInit::Map{});
  146. for (size_t i = 0; i < numDeclProps; ++i) {
  147. auto const name = const_cast<StringData*>(propInfo[i].name.get());
  148. // Empty names are used for invisible/private parent properties; skip them.
  149. assert(name->size() != 0);
  150. if (Class::IsPropAccessible(propInfo[i], ctx)) {
  151. auto const value = &((*propVals)[i]);
  152. arr.set(name, tvAsCVarRef(value));
  153. }
  154. }
  155. for (auto const& sprop : cls->staticProperties()) {
  156. auto const lookup = cls->getSProp(ctx, sprop.name);
  157. if (lookup.accessible) {
  158. arr.set(
  159. const_cast<StringData*>(sprop.name.get()),
  160. tvAsCVarRef(lookup.prop)
  161. );
  162. }
  163. }
  164. return arr.toArray();
  165. }
  166. ///////////////////////////////////////////////////////////////////////////////
  167. Variant HHVM_FUNCTION(get_class, const Variant& object /* = null_variant */) {
  168. if (object.isNull()) {
  169. // No arg passed.
  170. String ret;
  171. CallerFrame cf;
  172. auto cls = arGetContextClassImpl<true>(cf());
  173. if (cls) {
  174. ret = String(cls->nameStr());
  175. }
  176. if (ret.empty()) {
  177. raise_warning("get_class() called without object from outside a class");
  178. return false;
  179. }
  180. return ret;
  181. }
  182. if (!object.isObject()) return false;
  183. return VarNR(object.toObject()->getClassName());
  184. }
  185. Variant HHVM_FUNCTION(get_called_class) {
  186. EagerCallerFrame cf;
  187. ActRec* ar = cf();
  188. if (ar) {
  189. if (ar->hasThis()) {
  190. return Variant(ar->getThis()->getClassName());
  191. }
  192. if (ar->hasClass()) {
  193. return Variant(ar->getClass()->preClass()->name(),
  194. Variant::PersistentStrInit{});
  195. }
  196. }
  197. raise_warning("get_called_class() called from outside a class");
  198. return Variant(false);
  199. }
  200. Variant HHVM_FUNCTION(get_parent_class,
  201. const Variant& object /* = null_variant */) {
  202. if (object.isNull()) {
  203. CallerFrame cf;
  204. Class* cls = arGetContextClass(cf());
  205. if (cls && cls->parent()) {
  206. return String(cls->parentStr());
  207. }
  208. return false;
  209. }
  210. Variant class_name;
  211. if (object.isObject()) {
  212. class_name = HHVM_FN(get_class)(object);
  213. } else if (object.isString()) {
  214. class_name = object;
  215. } else {
  216. return false;
  217. }
  218. const Class* cls = Unit::loadClass(class_name.toString().get());
  219. if (cls) {
  220. auto parentClass = cls->parentStr();
  221. if (!parentClass.empty()) {
  222. return VarNR(parentClass);
  223. }
  224. }
  225. return false;
  226. }
  227. static bool is_a_impl(const Variant& class_or_object, const String& class_name,
  228. bool allow_string, bool subclass_only) {
  229. if (class_or_object.isString() && !allow_string) {
  230. return false;
  231. }
  232. if (!(class_or_object.isString() || class_or_object.isObject())) {
  233. return false;
  234. }
  235. const Class* cls = get_cls(class_or_object);
  236. if (!cls) return false;
  237. if (cls->attrs() & AttrTrait) return false;
  238. const Class* other = Unit::lookupClass(class_name.get());
  239. if (!other) return false;
  240. if (other->attrs() & AttrTrait) return false;
  241. if (other == cls) return !subclass_only;
  242. return cls->classof(other);
  243. }
  244. bool HHVM_FUNCTION(is_a, const Variant& class_or_object,
  245. const String& class_name,
  246. bool allow_string /* = false */) {
  247. return is_a_impl(class_or_object, class_name, allow_string, false);
  248. }
  249. bool HHVM_FUNCTION(is_subclass_of, const Variant& class_or_object,
  250. const String& class_name,
  251. bool allow_string /* = true */) {
  252. return is_a_impl(class_or_object, class_name, allow_string, true);
  253. }
  254. bool HHVM_FUNCTION(method_exists, const Variant& class_or_object,
  255. const String& method_name) {
  256. const Class* cls = get_cls(class_or_object);
  257. if (!cls) return false;
  258. if (cls->lookupMethod(method_name.get()) != NULL) return true;
  259. if (cls->attrs() & (AttrAbstract | AttrInterface)) {
  260. const Class::InterfaceMap& ifaces = cls->allInterfaces();
  261. for (int i = 0, size = ifaces.size(); i < size; i++) {
  262. if (ifaces[i]->lookupMethod(method_name.get())) return true;
  263. }
  264. }
  265. return false;
  266. }
  267. Variant HHVM_FUNCTION(property_exists, const Variant& class_or_object,
  268. const String& property) {
  269. Class* cls = nullptr;
  270. ObjectData* obj = nullptr;
  271. if (class_or_object.isObject()) {
  272. obj = class_or_object.getObjectData();
  273. cls = obj->getVMClass();
  274. assert(cls);
  275. } else if (class_or_object.isString()) {
  276. cls = Unit::loadClass(class_or_object.toString().get());
  277. if (!cls) return false;
  278. } else {
  279. raise_warning(
  280. "First parameter must either be an object"
  281. " or the name of an existing class"
  282. );
  283. return Variant(Variant::NullInit());
  284. }
  285. auto const lookup = cls->getDeclPropIndex(cls, property.get());
  286. if (lookup.prop != kInvalidSlot) return true;
  287. if (obj &&
  288. UNLIKELY(obj->getAttribute(ObjectData::HasDynPropArr)) &&
  289. obj->dynPropArray()->nvGet(property.get())) {
  290. return true;
  291. }
  292. auto const propInd = cls->lookupSProp(property.get());
  293. return propInd != kInvalidSlot;
  294. }
  295. Array HHVM_FUNCTION(get_object_vars, const Object& object) {
  296. return object->o_toIterArray(ctxClassName(), ObjectData::PreserveRefs);
  297. }
  298. ///////////////////////////////////////////////////////////////////////////////
  299. Variant HHVM_FUNCTION(call_user_method_array, const String& method_name,
  300. VRefParam obj,
  301. const Variant& paramarr) {
  302. return obj.toObject()->o_invoke(method_name, paramarr);
  303. }
  304. ///////////////////////////////////////////////////////////////////////////////
  305. void StandardExtension::initClassobj() {
  306. HHVM_FE(get_declared_classes);
  307. HHVM_FE(get_declared_interfaces);
  308. HHVM_FE(get_declared_traits);
  309. HHVM_FE(class_alias);
  310. HHVM_FE(class_exists);
  311. HHVM_FE(interface_exists);
  312. HHVM_FE(trait_exists);
  313. HHVM_FE(enum_exists);
  314. HHVM_FE(get_class_methods);
  315. HHVM_FE(get_class_constants);
  316. HHVM_FE(get_class_vars);
  317. HHVM_FE(get_class);
  318. HHVM_FE(get_called_class);
  319. HHVM_FE(get_parent_class);
  320. HHVM_FE(is_a);
  321. HHVM_FE(is_subclass_of);
  322. HHVM_FE(method_exists);
  323. HHVM_FE(property_exists);
  324. HHVM_FE(get_object_vars);
  325. HHVM_FE(call_user_method_array);
  326. loadSystemlib("std_classobj");
  327. }
  328. }