PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/ext/spl/ext_spl.cpp

https://gitlab.com/iranjith4/hhvm
C++ | 384 lines | 316 code | 44 blank | 24 comment | 44 complexity | 63e4e396ed38ece821ed8e13f185a4f0 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/spl/ext_spl.h"
  18. #include "hphp/runtime/ext/std/ext_std_classobj.h"
  19. #include "hphp/runtime/ext/std/ext_std_math.h"
  20. #include "hphp/runtime/ext/std/ext_std_file.h"
  21. #include "hphp/runtime/ext/string/ext_string.h"
  22. #include "hphp/runtime/base/autoload-handler.h"
  23. #include "hphp/runtime/base/array-init.h"
  24. #include "hphp/runtime/base/comparisons.h"
  25. #include "hphp/runtime/base/directory.h"
  26. #include "hphp/runtime/base/glob-stream-wrapper.h"
  27. #include "hphp/runtime/base/request-event-handler.h"
  28. #include "hphp/runtime/base/stream-wrapper-registry.h"
  29. #include "hphp/runtime/base/string-util.h"
  30. #include "hphp/runtime/vm/vm-regs.h"
  31. #include "hphp/system/systemlib.h"
  32. #include "hphp/util/string-vsnprintf.h"
  33. namespace HPHP {
  34. ///////////////////////////////////////////////////////////////////////////////
  35. const StaticString
  36. s_spl_autoload("spl_autoload"),
  37. s_spl_autoload_call("spl_autoload_call"),
  38. s_rewind("rewind"),
  39. s_valid("valid"),
  40. s_next("next"),
  41. s_current("current"),
  42. s_key("key"),
  43. s_getIterator("getIterator"),
  44. s_directory_iterator("DirectoryIterator");
  45. void throw_spl_exception(ATTRIBUTE_PRINTF_STRING const char *fmt, ...)
  46. ATTRIBUTE_PRINTF(1,2);
  47. void throw_spl_exception(const char *fmt, ...) {
  48. va_list ap;
  49. va_start(ap, fmt);
  50. std::string msg;
  51. string_vsnprintf(msg, fmt, ap);
  52. va_end(ap);
  53. SystemLib::throwExceptionObject(Variant(msg));
  54. }
  55. static bool s_inited = false;
  56. static int64_t s_hash_mask_handle = 0;
  57. static Mutex s_mutex;
  58. String HHVM_FUNCTION(spl_object_hash, const Object& obj) {
  59. if (!s_inited) {
  60. Lock lock(s_mutex);
  61. if (!s_inited) {
  62. HHVM_FN(mt_srand)();
  63. s_hash_mask_handle |= HHVM_FN(mt_rand)(); s_hash_mask_handle <<= 16;
  64. s_hash_mask_handle |= HHVM_FN(mt_rand)(); s_hash_mask_handle <<= 16;
  65. s_hash_mask_handle |= HHVM_FN(mt_rand)(); s_hash_mask_handle <<= 16;
  66. s_hash_mask_handle |= HHVM_FN(mt_rand)();
  67. s_inited = true;
  68. }
  69. }
  70. char buf[33];
  71. // Using the object address here would interfere with a moving GC algorithm.
  72. // See t6299529.
  73. snprintf(buf, sizeof(buf), "%032" PRIx64,
  74. s_hash_mask_handle ^ (int64_t)obj.get());
  75. return String(buf, CopyString);
  76. }
  77. // Using the object address here could interfere with a moving GC algorithm.
  78. // See t6299529.
  79. int64_t HHVM_FUNCTION(hphp_object_pointer, const Object& obj) {
  80. return (int64_t)obj.get();
  81. }
  82. Variant HHVM_FUNCTION(hphp_get_this) {
  83. return Variant{g_context->getThis()};
  84. }
  85. Variant HHVM_FUNCTION(class_implements, const Variant& obj,
  86. bool autoload /* = true */) {
  87. Class* cls;
  88. if (obj.isString()) {
  89. cls = Unit::getClass(obj.getStringData(), autoload);
  90. if (!cls) {
  91. String err = "class_implements(): Class %s does not exist";
  92. if (autoload) {
  93. err += " and could not be loaded";
  94. }
  95. raise_warning(err.c_str(), obj.toString().c_str());
  96. return false;
  97. }
  98. } else if (obj.isObject()) {
  99. cls = obj.getObjectData()->getVMClass();
  100. } else {
  101. raise_warning("class_implements(): object or string expected");
  102. return false;
  103. }
  104. Array ret(Array::Create());
  105. const Class::InterfaceMap& ifaces = cls->allInterfaces();
  106. for (int i = 0, size = ifaces.size(); i < size; i++) {
  107. ret.set(ifaces[i]->nameStr(), VarNR(ifaces[i]->name()));
  108. }
  109. return ret;
  110. }
  111. Variant HHVM_FUNCTION(class_parents, const Variant& obj,
  112. bool autoload /* = true */) {
  113. Class* cls;
  114. if (obj.isString()) {
  115. cls = Unit::getClass(obj.getStringData(), autoload);
  116. if (!cls) {
  117. String err = "class_parents(): Class %s does not exist";
  118. if (autoload) {
  119. err += " and could not be loaded";
  120. }
  121. raise_warning(err.c_str(), obj.toString().c_str());
  122. return false;
  123. }
  124. } else if (obj.isObject()) {
  125. cls = obj.getObjectData()->getVMClass();
  126. } else {
  127. raise_warning("class_parents(): object or string expected");
  128. return false;
  129. }
  130. Array ret(Array::Create());
  131. for (cls = cls->parent(); cls; cls = cls->parent()) {
  132. ret.set(cls->nameStr(), VarNR(cls->name()));
  133. }
  134. return ret;
  135. }
  136. Variant HHVM_FUNCTION(class_uses, const Variant& obj,
  137. bool autoload /* = true */) {
  138. Class* cls;
  139. if (obj.isString()) {
  140. cls = Unit::getClass(obj.getStringData(), autoload);
  141. if (!cls) {
  142. String err = "class_uses(): Class %s does not exist";
  143. if (autoload) {
  144. err += " and could not be loaded";
  145. }
  146. raise_warning(err.c_str(), obj.toString().c_str());
  147. return false;
  148. }
  149. } else if (obj.isObject()) {
  150. cls = obj.getObjectData()->getVMClass();
  151. } else {
  152. raise_warning("class_uses(): object or string expected");
  153. return false;
  154. }
  155. auto &usedTraits = cls->preClass()->usedTraits();
  156. ArrayInit ret(usedTraits.size(), ArrayInit::Map{});
  157. for (auto const& traitName : usedTraits) {
  158. ret.set(StrNR(traitName), VarNR(traitName));
  159. }
  160. return ret.toArray();
  161. }
  162. #define CHECK_TRAVERSABLE_IMPL(obj, ret) \
  163. if (!obj.isObject() || \
  164. !obj.getObjectData()->instanceof(SystemLib::s_TraversableClass)) { \
  165. raise_recoverable_error("Argument must implement interface Traversable"); \
  166. return ret; \
  167. }
  168. Object get_traversable_object_iterator(const Variant& obj) {
  169. bool isIteratorAggregate;
  170. Object itObj = obj.getObjectData()
  171. ->iterableObject(isIteratorAggregate, true);
  172. if (!isIteratorAggregate) {
  173. if (!obj.getObjectData()->instanceof(
  174. SystemLib::s_IteratorAggregateClass)) {
  175. raise_error("Objects returned by getIterator() must be traversable or "
  176. "implement interface Iterator");
  177. } else {
  178. raise_error(
  179. "Class %s must implement interface Traversable as part of either "
  180. "Iterator or IteratorAggregate",
  181. obj.toObject()->getClassName().data()
  182. );
  183. }
  184. }
  185. return itObj;
  186. }
  187. Variant HHVM_FUNCTION(iterator_apply, const Variant& obj, const Variant& func,
  188. const Array& params /* = null_array */) {
  189. VMRegAnchor _;
  190. CHECK_TRAVERSABLE_IMPL(obj, 0);
  191. Object pobj = get_traversable_object_iterator(obj);
  192. pobj->o_invoke_few_args(s_rewind, 0);
  193. int64_t count = 0;
  194. while (same(pobj->o_invoke_few_args(s_valid, 0), true)) {
  195. if (!same(vm_call_user_func(func, params), true)) {
  196. break;
  197. }
  198. ++count;
  199. pobj->o_invoke_few_args(s_next, 0);
  200. }
  201. return count;
  202. }
  203. Variant HHVM_FUNCTION(iterator_count, const Variant& obj) {
  204. VMRegAnchor _;
  205. CHECK_TRAVERSABLE_IMPL(obj, 0);
  206. Object pobj = get_traversable_object_iterator(obj);
  207. pobj->o_invoke_few_args(s_rewind, 0);
  208. int64_t count = 0;
  209. while (same(pobj->o_invoke_few_args(s_valid, 0), true)) {
  210. ++count;
  211. pobj->o_invoke_few_args(s_next, 0);
  212. }
  213. return count;
  214. }
  215. Array HHVM_FUNCTION(iterator_to_array, const Variant& obj,
  216. bool use_keys /* = true */) {
  217. VMRegAnchor _;
  218. Array ret(Array::Create());
  219. CHECK_TRAVERSABLE_IMPL(obj, ret);
  220. Object pobj = get_traversable_object_iterator(obj);
  221. pobj->o_invoke_few_args(s_rewind, 0);
  222. while (same(pobj->o_invoke_few_args(s_valid, 0), true)) {
  223. Variant val = pobj->o_invoke_few_args(s_current, 0);
  224. if (use_keys) {
  225. Variant key = pobj->o_invoke_few_args(s_key, 0);
  226. ret.set(key, val);
  227. } else {
  228. ret.append(val);
  229. }
  230. pobj->o_invoke_few_args(s_next, 0);
  231. }
  232. return ret;
  233. }
  234. bool HHVM_FUNCTION(spl_autoload_register,
  235. const Variant& autoload_function /* = null_variant */,
  236. bool throws /* = true */,
  237. bool prepend /* = false */) {
  238. if (same(autoload_function, s_spl_autoload_call)) {
  239. if (throws) {
  240. throw_spl_exception("Function spl_autoload_call()"
  241. "cannot be registered");
  242. }
  243. return false;
  244. }
  245. const Variant& func = autoload_function.isNull() ?
  246. s_spl_autoload : autoload_function;
  247. bool res = AutoloadHandler::s_instance->addHandler(func, prepend);
  248. if (!res && throws) {
  249. throw_spl_exception("Invalid autoload_function specified");
  250. }
  251. return res;
  252. }
  253. bool HHVM_FUNCTION(spl_autoload_unregister, const Variant& autoload_function) {
  254. if (same(autoload_function, s_spl_autoload_call)) {
  255. AutoloadHandler::s_instance->removeAllHandlers();
  256. } else {
  257. AutoloadHandler::s_instance->removeHandler(autoload_function);
  258. }
  259. return true;
  260. }
  261. Variant HHVM_FUNCTION(spl_autoload_functions) {
  262. const Array& handlers = AutoloadHandler::s_instance->getHandlers();
  263. if (handlers.isNull()) {
  264. return false;
  265. } else {
  266. return handlers.values();
  267. }
  268. }
  269. void HHVM_FUNCTION(spl_autoload_call, const String& class_name) {
  270. AutoloadHandler::s_instance->autoloadClass(class_name, true);
  271. }
  272. namespace {
  273. struct ExtensionList final : RequestEventHandler {
  274. void requestInit() override {
  275. extensions = make_packed_array(String(".inc"), String(".php"));
  276. }
  277. void requestShutdown() override {
  278. extensions.reset();
  279. }
  280. void vscan(IMarker& mark) const override {
  281. mark(extensions);
  282. }
  283. Array extensions;
  284. };
  285. IMPLEMENT_STATIC_REQUEST_LOCAL(ExtensionList, s_extension_list);
  286. }
  287. String HHVM_FUNCTION(spl_autoload_extensions,
  288. const String& file_extensions /* = null_string */) {
  289. if (!file_extensions.empty()) {
  290. s_extension_list->extensions = StringUtil::Explode(file_extensions, ",")
  291. .toArray();
  292. return file_extensions;
  293. }
  294. return StringUtil::Implode(s_extension_list->extensions, ",");
  295. }
  296. ///////////////////////////////////////////////////////////////////////////////
  297. template <class T>
  298. static req::ptr<T> getDir(const Object& dir_iter) {
  299. static_assert(std::is_base_of<Directory, T>::value,
  300. "Only cast to directories");
  301. return cast<T>(*dir_iter->o_realProp("dir", 0, s_directory_iterator));
  302. }
  303. static Variant HHVM_METHOD(DirectoryIterator, hh_readdir) {
  304. auto dir = getDir<Directory>(ObjNR(this_).asObject());
  305. if (auto array_dir = dyn_cast<ArrayDirectory>(dir)) {
  306. auto prop = this_->o_realProp("dirName", 0, s_directory_iterator);
  307. *prop = array_dir->path();
  308. }
  309. return HHVM_FN(readdir)(Resource(dir));
  310. }
  311. static int64_t HHVM_METHOD(GlobIterator, count) {
  312. return getDir<ArrayDirectory>(ObjNR(this_).asObject())->size();
  313. }
  314. ///////////////////////////////////////////////////////////////////////////////
  315. struct SPLExtension final : Extension {
  316. SPLExtension() : Extension("spl", "0.2") { }
  317. void moduleLoad(const IniSetting::Map& ini, Hdf config) override {
  318. HHVM_ME(DirectoryIterator, hh_readdir);
  319. HHVM_ME(GlobIterator, count);
  320. }
  321. void moduleInit() override {
  322. HHVM_FE(spl_object_hash);
  323. HHVM_FE(hphp_object_pointer);
  324. HHVM_FE(hphp_get_this);
  325. HHVM_FE(class_implements);
  326. HHVM_FE(class_parents);
  327. HHVM_FE(class_uses);
  328. HHVM_FE(iterator_apply);
  329. HHVM_FE(iterator_count);
  330. HHVM_FE(iterator_to_array);
  331. HHVM_FE(spl_autoload_call);
  332. HHVM_FE(spl_autoload_extensions);
  333. HHVM_FE(spl_autoload_functions);
  334. HHVM_FE(spl_autoload_register);
  335. HHVM_FE(spl_autoload_unregister);
  336. loadSystemlib();
  337. }
  338. } s_SPL_extension;
  339. ///////////////////////////////////////////////////////////////////////////////
  340. }