2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_BUILTIN_FUNCTIONS_H_
18 #define incl_HPHP_BUILTIN_FUNCTIONS_H_
20 #include "hphp/runtime/base/type-variant.h"
21 #include "hphp/runtime/base/variable-unserializer.h"
22 #include "hphp/runtime/vm/bytecode.h"
23 #include "hphp/util/functional.h"
24 #include "hphp/util/portability.h"
25 #include "hphp/runtime/base/req-root.h"
28 ///////////////////////////////////////////////////////////////////////////////
29 extern const StaticString s_self
;
30 extern const StaticString s_parent
;
31 extern const StaticString s_static
;
33 extern const StaticString s_cmpWithCollection
;
34 extern const StaticString s_cmpWithVec
;
35 extern const StaticString s_cmpWithDict
;
36 extern const StaticString s_cmpWithKeyset
;
37 extern const StaticString s_cmpWithClsMeth
;
38 extern const StaticString s_cmpWithRecord
;
40 ///////////////////////////////////////////////////////////////////////////////
43 inline String
concat(const String
& s1
, const String
& s2
) {
47 String
concat3(const String
& s1
, const String
& s2
, const String
& s3
);
48 String
concat4(const String
& s1
, const String
& s2
, const String
& s3
,
51 ///////////////////////////////////////////////////////////////////////////////
53 [[noreturn
]] void NEVER_INLINE
throw_missing_this(const Func
* f
);
54 [[noreturn
]] void NEVER_INLINE
throw_has_this_need_static(const Func
* f
);
55 void NEVER_INLINE
throw_invalid_property_name(const String
& name
);
58 void NEVER_INLINE
throw_call_reified_func_without_generics(const Func
* f
);
61 void throw_exception(const Object
& e
);
63 ///////////////////////////////////////////////////////////////////////////////
66 inline bool is_null(const TypedValue
* c
) {
67 assertx(tvIsPlausible(*c
));
71 inline bool is_bool(const TypedValue
* c
) {
72 assertx(tvIsPlausible(*c
));
76 inline bool is_int(const TypedValue
* c
) {
77 assertx(tvIsPlausible(*c
));
81 inline bool is_double(const TypedValue
* c
) {
82 assertx(tvIsPlausible(*c
));
86 inline bool is_string(const TypedValue
* c
) {
87 if (tvIsString(c
)) return true;
89 if (RuntimeOption::EvalIsStringNotices
) {
90 raise_notice("Func used in is_string");
95 if (RuntimeOption::EvalIsStringNotices
) {
96 raise_notice("Class used in is_string");
103 // This function behaves how most callers of raise_array_serialization_notice
104 // should behave: it checks if `tv` *should* have a provenance tag and then
105 // logs a serialization notice of some kind if so.
107 // If we trace through call sites of the bare function, we'll find a number of
108 // places where we're incorrectly losing provenance logs. Clean this up soon.
109 inline void maybe_raise_array_serialization_notice(
110 SerializationSite site
, const TypedValue
* tv
) {
111 assertx(isArrayLikeType(tv
->m_type
));
112 auto const ad
= tv
->m_data
.parr
;
113 if (RuntimeOption::EvalLogArrayProvenance
&& arrprov::arrayWantsTag(ad
)) {
114 raise_array_serialization_notice(site
, ad
);
118 inline bool is_array(const TypedValue
* c
, bool logOnHackArrays
) {
119 assertx(tvIsPlausible(*c
));
122 maybe_raise_array_serialization_notice(SerializationSite::IsArray
, c
);
126 if (tvIsClsMeth(c
)) {
127 if (!RO::EvalHackArrDVArrs
&& RO::EvalIsCompatibleClsMethType
) {
128 if (RO::EvalIsVecNotices
) raise_notice(Strings::CLSMETH_COMPAT_IS_ARR
);
134 auto const hacLogging
= [&](const char* msg
) {
135 if (RO::EvalHackArrCompatIsArrayNotices
) raise_hackarr_compat_notice(msg
);
137 if (logOnHackArrays
/* let's get rid of this condition if we can */) {
139 hacLogging(Strings::HACKARR_COMPAT_VEC_IS_ARR
);
140 maybe_raise_array_serialization_notice(SerializationSite::IsArray
, c
);
141 } else if (tvIsDict(c
)) {
142 hacLogging(Strings::HACKARR_COMPAT_DICT_IS_ARR
);
143 maybe_raise_array_serialization_notice(SerializationSite::IsArray
, c
);
144 } else if (tvIsKeyset(c
)) {
145 hacLogging(Strings::HACKARR_COMPAT_KEYSET_IS_ARR
);
146 assertx(!arrprov::arrayWantsTag(c
->m_data
.parr
));
152 inline bool is_vec(const TypedValue
* c
) {
153 assertx(tvIsPlausible(*c
));
156 maybe_raise_array_serialization_notice(SerializationSite::IsVec
, c
);
160 auto const hacLogging
= [&](const char* msg
) {
161 if (RO::EvalHackArrCompatIsVecDictNotices
) raise_hackarr_compat_notice(msg
);
163 if (tvIsClsMeth(c
)) {
164 if (RO::EvalHackArrDVArrs
&& RO::EvalIsCompatibleClsMethType
) {
165 if (RO::EvalIsVecNotices
) raise_notice(Strings::CLSMETH_COMPAT_IS_VEC
);
169 if (!RO::EvalHackArrDVArrs
) {
170 hacLogging(Strings::HACKARR_COMPAT_VARR_IS_VEC
);
175 if (tvIsArray(c
) && c
->m_data
.parr
->isVArray()) {
176 hacLogging(Strings::HACKARR_COMPAT_VARR_IS_VEC
);
177 maybe_raise_array_serialization_notice(SerializationSite::IsVec
, c
);
182 inline bool is_dict(const TypedValue
* c
) {
183 assertx(tvIsPlausible(*c
));
186 maybe_raise_array_serialization_notice(SerializationSite::IsDict
, c
);
190 auto const hacLogging
= [&](const char* msg
) {
191 if (RO::EvalHackArrCompatIsVecDictNotices
) raise_hackarr_compat_notice(msg
);
193 if (tvIsArray(c
) && c
->m_data
.parr
->isDArray()) {
194 hacLogging(Strings::HACKARR_COMPAT_DARR_IS_DICT
);
195 maybe_raise_array_serialization_notice(SerializationSite::IsDict
, c
);
200 inline bool is_keyset(const TypedValue
* c
) {
201 assertx(tvIsPlausible(*c
));
202 return tvIsKeyset(c
);
205 inline bool is_varray(const TypedValue
* c
) {
206 assertx(tvIsPlausible(*c
));
208 // Is this line safe? It returns the correct result, but if it logs a notice,
209 // it'll be for is_vec, not is_varray. That may be fine, post-HAM, because
210 // only dynamic calls to is_varray will remain at that point.
211 if (RuntimeOption::EvalHackArrDVArrs
) return is_vec(c
);
213 if (tvIsVArray(c
) || (tvIsArray(c
) && c
->m_data
.parr
->isVArray())) {
214 maybe_raise_array_serialization_notice(SerializationSite::IsVArray
, c
);
218 if (tvIsClsMeth(c
) && RO::EvalIsCompatibleClsMethType
) {
219 if (RO::EvalIsVecNotices
) raise_notice(Strings::CLSMETH_COMPAT_IS_VARR
);
223 auto const hacLogging
= [&](const char* msg
) {
224 if (RO::EvalHackArrCompatIsVecDictNotices
) raise_hackarr_compat_notice(msg
);
227 hacLogging(Strings::HACKARR_COMPAT_VEC_IS_VARR
);
228 maybe_raise_array_serialization_notice(SerializationSite::IsVArray
, c
);
233 inline bool is_darray(const TypedValue
* c
) {
234 assertx(tvIsPlausible(*c
));
236 // Is this line safe? It returns the correct result, but if it logs a notice,
237 // it'll be for is_dict, not is_darray. That may be fine, post-HAM, because
238 // only dynamic calls to is_darray will remain at that point.
239 if (RuntimeOption::EvalHackArrDVArrs
) return is_dict(c
);
241 if (tvIsDArray(c
) || (tvIsArray(c
) && c
->m_data
.parr
->isDArray())) {
242 maybe_raise_array_serialization_notice(SerializationSite::IsDArray
, c
);
246 auto const hacLogging
= [&](const char* msg
) {
247 if (RO::EvalHackArrCompatIsVecDictNotices
) raise_hackarr_compat_notice(msg
);
250 hacLogging(Strings::HACKARR_COMPAT_DICT_IS_DARR
);
251 maybe_raise_array_serialization_notice(SerializationSite::IsDArray
, c
);
256 inline bool is_object(const TypedValue
* c
) {
257 assertx(tvIsPlausible(*c
));
258 return tvIsObject(c
) &&
259 c
->m_data
.pobj
->getVMClass() != SystemLib::s___PHP_Incomplete_ClassClass
;
262 inline bool is_clsmeth(const TypedValue
* c
) {
263 assertx(tvIsPlausible(*c
));
264 return tvIsClsMeth(c
);
267 inline bool is_fun(const TypedValue
* c
) {
268 assertx(tvIsPlausible(*c
));
272 inline bool is_empty_string(const TypedValue
* c
) {
273 return tvIsString(c
) && c
->m_data
.pstr
->empty();
276 ///////////////////////////////////////////////////////////////////////////////
280 * Semantics of is_callable defined here:
281 * http://php.net/manual/en/function.is-callable.php
283 bool is_callable(const Variant
& v
, bool syntax_only
, Variant
* name
);
285 * Equivalent to is_callable(v, false, nullptr)
287 bool is_callable(const Variant
& v
);
288 bool array_is_valid_callback(const Array
& arr
);
290 enum class DecodeFlags
{ Warn
, NoWarn
, LookupOnly
};
292 vm_decode_function(const_variant_ref function
,
296 StringData
*& invName
,
298 DecodeFlags flags
= DecodeFlags::Warn
,
299 bool genericsAlreadyGiven
= false);
302 vm_decode_function(const_variant_ref function
,
304 DecodeFlags flags
= DecodeFlags::Warn
,
305 bool genericsAlreadyGiven
= false) {
306 ctx
.func
= vm_decode_function(function
, nullptr, ctx
.this_
, ctx
.cls
,
307 ctx
.invName
, ctx
.dynamic
, flags
,
308 genericsAlreadyGiven
);
311 std::pair
<Class
*, Func
*> decode_for_clsmeth(
312 const String
& clsName
,
313 const String
& funcName
,
315 StringData
*& invName
,
316 DecodeFlags flags
= DecodeFlags::Warn
);
318 Variant
vm_call_user_func(const_variant_ref function
, const Variant
& params
,
319 bool checkRef
= false,
320 bool allowDynCallNoPointer
= false);
322 Variant
vm_call_user_func(T
&& t
, const Variant
& params
, bool checkRef
= false,
323 bool allowDynCallNoPointer
= false) {
324 const Variant function
{std::forward
<T
>(t
)};
325 return vm_call_user_func(
326 const_variant_ref
{function
}, params
, checkRef
, allowDynCallNoPointer
330 // Invoke an arbitrary user-defined function.
331 // If you're considering calling this function for some new code, don't.
332 Variant
invoke(const String
& function
, const Variant
& params
,
333 bool allowDynCallNoPointer
= false);
335 Variant
invoke_static_method(const String
& s
, const String
& method
,
336 const Variant
& params
, bool fatal
= true);
338 Variant
o_invoke_failed(const char *cls
, const char *meth
,
341 bool is_constructor_name(const char* func
);
342 [[noreturn
]] void throw_instance_method_fatal(const char *name
);
344 [[noreturn
]] void throw_invalid_collection_parameter();
345 [[noreturn
]] void throw_invalid_operation_exception(StringData
*);
346 [[noreturn
]] void throw_division_by_zero_exception();
347 [[noreturn
]] void throw_iterator_not_valid();
348 [[noreturn
]] void throw_collection_property_exception();
349 [[noreturn
]] void throw_collection_compare_exception();
350 [[noreturn
]] void throw_vec_compare_exception();
351 [[noreturn
]] void throw_dict_compare_exception();
352 [[noreturn
]] void throw_keyset_compare_exception();
353 [[noreturn
]] void throw_clsmeth_compare_exception();
354 [[noreturn
]] void throw_record_compare_exception();
355 [[noreturn
]] void throw_rec_non_rec_compare_exception();
356 [[noreturn
]] void throw_param_is_not_container();
357 [[noreturn
]] void throw_invalid_inout_base();
358 [[noreturn
]] void throw_cannot_modify_immutable_object(const char* className
);
359 [[noreturn
]] void throw_cannot_modify_const_object(const char* className
);
360 [[noreturn
]] void throw_object_forbids_dynamic_props(const char* className
);
361 [[noreturn
]] void throw_cannot_modify_const_prop(const char* className
,
362 const char* propName
);
363 [[noreturn
]] void throw_cannot_modify_static_const_prop(const char* className
,
364 const char* propName
);
365 [[noreturn
]] void throw_late_init_prop(const Class
* cls
,
366 const StringData
* propName
,
368 [[noreturn
]] void throw_parameter_wrong_type(TypedValue tv
,
370 unsigned int arg_num
,
373 void check_collection_cast_to_array();
375 Object
create_object_only(const String
& s
);
376 Object
create_object(const String
& s
, const Array
¶ms
, bool init
= true);
377 Object
init_object(const String
& s
, const Array
¶ms
, ObjectData
* o
);
379 [[noreturn
]] void throw_object(const Object
& e
);
380 #if ((__GNUC__ != 4) || (__GNUC_MINOR__ != 8))
381 // gcc-4.8 has a bug that causes incorrect code if we
382 // define this function.
383 [[noreturn
]] void throw_object(Object
&& e
);
387 void throw_object(const String
& s
, const Array
& params
, bool init
= true) {
388 throw_object(create_object(s
, params
, init
));
391 void throw_missing_arguments_nr(const char *fn
, int expected
, int got
)
393 __attribute__((__cold__
));
396 * Handler for exceptions thrown from user functions that we don't
397 * allow exception propagation from. E.g., object destructors or
398 * certain callback hooks (user profiler). Implemented in
399 * program-functions.cpp.
401 void handle_destructor_exception(const char* situation
= "Destructor");
404 * Deprecated wrappers for raising certain types of warnings.
406 * Don't use in new code.
408 void raise_bad_type_warning(ATTRIBUTE_PRINTF_STRING
const char *fmt
, ...)
409 ATTRIBUTE_PRINTF(1,2);
410 void raise_expected_array_warning(const char* fn
= nullptr);
411 void raise_expected_array_or_collection_warning(const char* fn
= nullptr);
412 void raise_invalid_argument_warning(ATTRIBUTE_PRINTF_STRING
const char *fmt
, ...)
413 ATTRIBUTE_PRINTF(1,2) __attribute__((__cold__
));
416 * Unsetting ClassName::StaticProperty.
418 Variant
throw_fatal_unset_static_property(const char *s
, const char *prop
);
420 // unserializable default value arguments such as TimeStamp::Current()
421 // are serialized as "\x01"
422 char const kUnserializableString
[] = "\x01";
425 * Serialize/unserialize a variant into/from a string. We need these
426 * two functions in runtime/base, as there are functions in
427 * runtime/base that depend on these two functions.
429 String
f_serialize(const Variant
& value
);
430 String
serialize_keep_dvarrays(const Variant
& value
);
431 Variant
unserialize_ex(const String
& str
,
432 VariableUnserializer::Type type
,
433 const Array
& options
= null_array
);
434 Variant
unserialize_ex(const char* str
, int len
,
435 VariableUnserializer::Type type
,
436 const Array
& options
= null_array
);
438 inline Variant
unserialize_from_buffer(const char* str
, int len
,
439 VariableUnserializer::Type type
,
440 const Array
& options
= null_array
) {
441 return unserialize_ex(str
, len
, type
, options
);
444 inline Variant
unserialize_from_string(const String
& str
,
445 VariableUnserializer::Type type
,
446 const Array
& options
= null_array
) {
447 return unserialize_from_buffer(str
.data(), str
.size(), type
, options
);
450 String
resolve_include(const String
& file
, const char* currentDir
,
451 bool (*tryFile
)(const String
& file
, void* ctx
),
453 Variant
include_impl_invoke(const String
& file
, bool once
= false,
454 const char *currentDir
= "",
455 bool callByHPHPInvoke
= false);
456 Variant
require(const String
& file
, bool once
, const char* currentDir
,
459 bool function_exists(const String
& function_name
);
461 ///////////////////////////////////////////////////////////////////////////////