PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/runtime/ext/ext_function.cpp

https://github.com/github-ivan/hiphop-php
C++ | 344 lines | 273 code | 48 blank | 23 comment | 48 complexity | b6c49a1fabc806c6613dc162927e5ad4 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- 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 <runtime/ext/ext_function.h>
  18. #include <runtime/ext/ext_json.h>
  19. #include <runtime/ext/ext_class.h>
  20. #include <runtime/base/class_info.h>
  21. #include <runtime/base/fiber_async_func.h>
  22. #include <runtime/base/util/libevent_http_client.h>
  23. #include <runtime/base/server/http_protocol.h>
  24. #include <util/exception.h>
  25. #include <util/util.h>
  26. using namespace std;
  27. using namespace boost;
  28. namespace HPHP {
  29. ///////////////////////////////////////////////////////////////////////////////
  30. static StaticString s_parent("parent");
  31. static StaticString s_self("self");
  32. Array f_get_defined_functions() {
  33. Array ret;
  34. ret.set("internal", ClassInfo::GetSystemFunctions());
  35. ret.set("user", ClassInfo::GetUserFunctions());
  36. return ret;
  37. }
  38. bool f_function_exists(CStrRef function_name) {
  39. return function_exists(function_name);
  40. }
  41. bool f_is_callable(CVarRef v, bool syntax /* = false */,
  42. VRefParam name /* = null */) {
  43. bool ret = true;
  44. if (LIKELY(!syntax)) {
  45. MethodCallPackage mcp;
  46. String classname, methodname;
  47. bool doBind;
  48. ret = get_user_func_handler(v, true, mcp,
  49. classname, methodname, doBind, false);
  50. if (ret && mcp.ci->m_flags & (CallInfo::Protected|CallInfo::Private)) {
  51. classname = mcp.getClassName();
  52. if (!ClassInfo::HasAccess(classname, *mcp.name,
  53. mcp.ci->m_flags & CallInfo::StaticMethod ||
  54. !mcp.obj,
  55. mcp.obj)) {
  56. ret = false;
  57. }
  58. }
  59. if (!name.isReferenced()) return ret;
  60. }
  61. Variant::TypedValueAccessor tv_func = v.getTypedAccessor();
  62. if (Variant::IsString(tv_func)) {
  63. if (name.isReferenced()) name = Variant::GetStringData(tv_func);
  64. return ret;
  65. }
  66. if (Variant::GetAccessorType(tv_func) == KindOfArray) {
  67. CArrRef arr = Variant::GetAsArray(tv_func);
  68. CVarRef clsname = arr.rvalAtRef(0LL);
  69. CVarRef mthname = arr.rvalAtRef(1LL);
  70. if (arr.size() != 2 ||
  71. &clsname == &null_variant ||
  72. &mthname == &null_variant) {
  73. name = v.toString();
  74. return false;
  75. }
  76. Variant::TypedValueAccessor tv_meth = mthname.getTypedAccessor();
  77. if (!Variant::IsString(tv_meth)) {
  78. if (name.isReferenced()) name = v.toString();
  79. return false;
  80. }
  81. Variant::TypedValueAccessor tv_cls = clsname.getTypedAccessor();
  82. if (Variant::GetAccessorType(tv_cls) == KindOfObject) {
  83. name = Variant::GetObjectData(tv_cls)->o_getClassName();
  84. } else if (Variant::IsString(tv_cls)) {
  85. name = Variant::GetStringData(tv_cls);
  86. } else {
  87. name = v.toString();
  88. return false;
  89. }
  90. name = concat3(name, "::", Variant::GetAsString(tv_meth));
  91. return ret;
  92. }
  93. if (Variant::GetAccessorType(tv_func) == KindOfObject) {
  94. ObjectData *d = Variant::GetObjectData(tv_func);
  95. void *extra;
  96. if (d->t___invokeCallInfoHelper(extra)) {
  97. name = d->o_getClassName() + "::__invoke";
  98. return ret;
  99. }
  100. if (name.isReferenced()) {
  101. name = v.toString();
  102. }
  103. }
  104. return false;
  105. }
  106. Variant f_call_user_func(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  107. return f_call_user_func_array(function, _argv);
  108. }
  109. Object f_call_user_func_array_async(CVarRef function, CArrRef params) {
  110. #ifdef CUFA_ASYNC_DEPRECATION_MSG
  111. raise_warning(CUFA_ASYNC_DEPRECATION_MSG);
  112. #else
  113. raise_warning("call_user_func_array_async() is deprecated");
  114. #endif
  115. return FiberAsyncFunc::Start(function, params);
  116. }
  117. Object f_call_user_func_async(int _argc, CVarRef function,
  118. CArrRef _argv /* = null_array */) {
  119. #ifdef CUF_ASYNC_DEPRECATION_MSG
  120. raise_warning(CUF_ASYNC_DEPRECATION_MSG);
  121. #else
  122. raise_warning("call_user_func_async() is deprecated");
  123. #endif
  124. return FiberAsyncFunc::Start(function, _argv);
  125. }
  126. Variant f_check_user_func_async(CVarRef handles, int timeout /* = -1 */) {
  127. if (handles.isArray()) {
  128. return FiberAsyncFunc::Status(handles, timeout);
  129. }
  130. Array ret = FiberAsyncFunc::Status(CREATE_VECTOR1(handles), timeout);
  131. return !ret.empty();
  132. }
  133. Variant f_end_user_func_async(CObjRef handle,
  134. int default_strategy /* = k_GLOBAL_STATE_IGNORE */,
  135. CVarRef additional_strategies /* = null */) {
  136. return FiberAsyncFunc::Result(handle,
  137. (FiberAsyncFunc::Strategy)default_strategy,
  138. additional_strategies);
  139. }
  140. String f_call_user_func_serialized(CStrRef input) {
  141. Variant out;
  142. try {
  143. Variant in = f_unserialize(input);
  144. out.set("ret", f_call_user_func_array(in["func"], in["args"]));
  145. } catch (Object &e) {
  146. out.set("exception", e);
  147. }
  148. return f_serialize(out);
  149. }
  150. Variant f_call_user_func_array_rpc(CStrRef host, int port, CStrRef auth,
  151. int timeout, CVarRef function,
  152. CArrRef params) {
  153. return f_call_user_func_rpc(0, host, port, auth, timeout, function, params);
  154. }
  155. Variant f_call_user_func_rpc(int _argc, CStrRef host, int port, CStrRef auth,
  156. int timeout, CVarRef function,
  157. CArrRef _argv /* = null_array */) {
  158. string shost = host.data();
  159. if (!RuntimeOption::DebuggerRpcHostDomain.empty()) {
  160. unsigned int pos = shost.find(RuntimeOption::DebuggerRpcHostDomain);
  161. if (pos != shost.length() - RuntimeOption::DebuggerRpcHostDomain.size()) {
  162. shost += RuntimeOption::DebuggerRpcHostDomain;
  163. }
  164. }
  165. string url = "http://";
  166. url += shost;
  167. url += ":";
  168. url += lexical_cast<string>(port);
  169. url += "/call_user_func_serialized?auth=";
  170. url += auth.data();
  171. Array blob = CREATE_MAP2("func", function, "args", _argv);
  172. String message = f_serialize(blob);
  173. vector<string> headers;
  174. LibEventHttpClientPtr http = LibEventHttpClient::Get(shost, port);
  175. if (!http->send(url, headers, timeout < 0 ? 0 : timeout, false,
  176. message.data(), message.size())) {
  177. raise_error("Unable to send RPC request");
  178. return false;
  179. }
  180. int code = http->getCode();
  181. if (code <= 0) {
  182. raise_error("Server timed out or unable to find specified URL: %s",
  183. url.c_str());
  184. return false;
  185. }
  186. int len = 0;
  187. char *response = http->recv(len);
  188. String sresponse(response, len, AttachString);
  189. if (code != 200) {
  190. raise_error("Internal server error: %d %s", code,
  191. HttpProtocol::GetReasonString(code));
  192. return false;
  193. }
  194. // This double decoding can be avoided by modifying RPC server to directly
  195. // take PHP serialization format.
  196. Variant res = f_unserialize(f_json_decode(sresponse));
  197. if (!res.isArray()) {
  198. raise_error("Internal protocol error");
  199. return false;
  200. }
  201. if (res.toArray().exists("exception")) {
  202. throw res["exception"];
  203. }
  204. return res["ret"];
  205. }
  206. Variant f_forward_static_call_array(CVarRef function, CArrRef params) {
  207. return f_forward_static_call(0, function, params);
  208. }
  209. Variant f_forward_static_call(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  210. CStrRef cls = FrameInjection::GetClassName();
  211. if (cls.empty()) {
  212. raise_error("Cannot call forward_static_call() "
  213. "when no class scope is active");
  214. return null;
  215. }
  216. return f_call_user_func_array(function, _argv, true);
  217. }
  218. Variant f_get_called_class() {
  219. CStrRef cls = FrameInjection::GetStaticClassName(
  220. ThreadInfo::s_threadInfo.getNoCheck());
  221. return cls.size() ? Variant(cls.get()) : Variant(false);
  222. }
  223. String f_create_function(CStrRef args, CStrRef code) {
  224. throw NotSupportedException(__func__, "dynamic coding");
  225. }
  226. ///////////////////////////////////////////////////////////////////////////////
  227. Variant f_func_get_arg(int arg_num) {
  228. throw FatalErrorException("bad HPHP code generation");
  229. }
  230. Variant func_get_arg(int num_args, CArrRef params, CArrRef args, int pos) {
  231. FUNCTION_INJECTION_BUILTIN(func_get_arg);
  232. if (num_args <= params.size()) {
  233. if (pos >= 0 && pos < num_args) {
  234. return params.rvalAt(pos);
  235. }
  236. } else {
  237. if (pos >= 0) {
  238. int index = pos - params.size();
  239. if (index < 0) {
  240. return params.rvalAt(pos);
  241. }
  242. if (index < args.size()) {
  243. return args.rvalAt(index);
  244. }
  245. }
  246. }
  247. return false;
  248. }
  249. Array f_func_get_args() {
  250. throw FatalErrorException("bad HPHP code generation");
  251. }
  252. Array func_get_args(int num_args, CArrRef params, CArrRef args) {
  253. FUNCTION_INJECTION_BUILTIN(func_get_args);
  254. if (params.empty() && args.empty()) return Array::Create();
  255. if (args.empty()) {
  256. if (num_args < params.size()) {
  257. return params.slice(0, num_args, false);
  258. }
  259. return params;
  260. }
  261. Array derefArgs;
  262. for (ArrayIter iter(args); iter; ++iter) {
  263. derefArgs.append(iter.second());
  264. }
  265. if (params.empty()) return derefArgs;
  266. ASSERT(num_args > params.size());
  267. Array ret = Array(params).merge(derefArgs);
  268. return ret;
  269. }
  270. int f_func_num_args() {
  271. // we shouldn't be here, since HPHP code generation will inline this function
  272. ASSERT(false);
  273. return -1;
  274. }
  275. ///////////////////////////////////////////////////////////////////////////////
  276. void f_register_postsend_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  277. g_context->registerShutdownFunction(function, _argv,
  278. ExecutionContext::PostSend);
  279. }
  280. void f_register_shutdown_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  281. g_context->registerShutdownFunction(function, _argv,
  282. ExecutionContext::ShutDown);
  283. }
  284. void f_register_cleanup_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  285. g_context->registerShutdownFunction(function, _argv,
  286. ExecutionContext::CleanUp);
  287. }
  288. bool f_register_tick_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  289. g_context->registerTickFunction(function, _argv);
  290. return true;
  291. }
  292. void f_unregister_tick_function(CVarRef function_name) {
  293. g_context->unregisterTickFunction(function_name);
  294. }
  295. ///////////////////////////////////////////////////////////////////////////////
  296. }