2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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/ext_spl.h"
19 #include "hphp/runtime/ext/ext_math.h"
20 #include "hphp/runtime/ext/ext_class.h"
22 #include "hphp/system/systemlib.h"
25 IMPLEMENT_DEFAULT_EXTENSION(SPL
);
26 ///////////////////////////////////////////////////////////////////////////////
29 s_spl_autoload("spl_autoload"),
30 s_spl_autoload_call("spl_autoload_call"),
31 s_default_extensions(".inc,.php"),
37 s_getIterator("getIterator");
39 const StaticString spl_classes
[] = {
40 StaticString("AppendIterator"),
41 StaticString("ArrayIterator"),
42 StaticString("ArrayObject"),
43 StaticString("BadFunctionCallException"),
44 StaticString("BadMethodCallException"),
45 StaticString("CachingIterator"),
46 StaticString("Countable"),
47 StaticString("DirectoryIterator"),
48 StaticString("DomainException"),
49 StaticString("EmptyIterator"),
50 StaticString("FilesystemIterator"),
51 StaticString("FilterIterator"),
52 StaticString("GlobIterator"),
53 StaticString("InfiniteIterator"),
54 StaticString("InvalidArgumentException"),
55 StaticString("IteratorIterator"),
56 StaticString("LengthException"),
57 StaticString("LimitIterator"),
58 StaticString("LogicException"),
59 StaticString("MultipleIterator"),
60 StaticString("NoRewindIterator"),
61 StaticString("OuterIterator"),
62 StaticString("OutOfBoundsException"),
63 StaticString("OutOfRangeException"),
64 StaticString("OverflowException"),
65 StaticString("ParentIterator"),
66 StaticString("RangeException"),
67 StaticString("RecursiveArrayIterator"),
68 StaticString("RecursiveCachingIterator"),
69 StaticString("RecursiveDirectoryIterator"),
70 StaticString("RecursiveFilterIterator"),
71 StaticString("RecursiveIterator"),
72 StaticString("RecursiveIteratorIterator"),
73 StaticString("RecursiveRegexIterator"),
74 StaticString("RecursiveTreeIterator"),
75 StaticString("RegexIterator"),
76 StaticString("RuntimeException"),
77 StaticString("SeekableIterator"),
78 StaticString("SplDoublyLinkedList"),
79 StaticString("SplFileInfo"),
80 StaticString("SplFileObject"),
81 StaticString("SplFixedArray"),
82 StaticString("SplHeap"),
83 StaticString("SplMinHeap"),
84 StaticString("SplMaxHeap"),
85 StaticString("SplObjectStorage"),
86 StaticString("SplObserver"),
87 StaticString("SplPriorityQueue"),
88 StaticString("SplQueue"),
89 StaticString("SplStack"),
90 StaticString("SplSubject"),
91 StaticString("SplTempFileObject"),
92 StaticString("UnderflowException"),
93 StaticString("UnexpectedValueException"),
96 Array
f_spl_classes() {
97 const size_t num_classes
= sizeof(spl_classes
) / sizeof(spl_classes
[0]);
98 ArrayInit
ret(num_classes
);
99 for (size_t i
= 0; i
< num_classes
; ++i
) {
100 ret
.set(spl_classes
[i
], spl_classes
[i
]);
105 void throw_spl_exception(const char *fmt
, ...) ATTRIBUTE_PRINTF(1,2);
106 void throw_spl_exception(const char *fmt
, ...) {
110 Util::string_vsnprintf(msg
, fmt
, ap
);
113 throw Object(SystemLib::AllocExceptionObject(Variant(msg
)));
116 static bool s_inited
= false;
117 static int64_t s_hash_mask_handle
= 0;
118 static Mutex s_mutex
;
120 String
f_spl_object_hash(CObjRef obj
) {
125 s_hash_mask_handle
|= f_mt_rand(); s_hash_mask_handle
<<= 16;
126 s_hash_mask_handle
|= f_mt_rand(); s_hash_mask_handle
<<= 16;
127 s_hash_mask_handle
|= f_mt_rand(); s_hash_mask_handle
<<= 16;
128 s_hash_mask_handle
|= f_mt_rand();
134 snprintf(buf
, sizeof(buf
), "%032" PRIx64
,
135 s_hash_mask_handle
^ (int64_t)obj
.get());
136 return String(buf
, CopyString
);
139 int64_t f_hphp_object_pointer(CObjRef obj
) { return (int64_t)obj
.get();}
141 Variant
f_hphp_get_this() {
142 return g_vmContext
->getThis();
145 Variant
f_class_implements(CVarRef obj
, bool autoload
/* = true */) {
147 if (obj
.isString()) {
148 cls
= Unit::getClass(obj
.getStringData(), autoload
);
152 } else if (obj
.isObject()) {
153 cls
= obj
.getObjectData()->getVMClass();
157 Array
ret(Array::Create());
158 const Class::InterfaceMap
& ifaces
= cls
->allInterfaces();
159 for (int i
= 0, size
= ifaces
.size(); i
< size
; i
++) {
160 ret
.set(ifaces
[i
]->nameRef(), ifaces
[i
]->nameRef());
165 Variant
f_class_parents(CVarRef obj
, bool autoload
/* = true */) {
167 if (obj
.isString()) {
168 cls
= Unit::getClass(obj
.getStringData(), autoload
);
172 } else if (obj
.isObject()) {
173 cls
= obj
.getObjectData()->getVMClass();
177 Array
ret(Array::Create());
178 for (cls
= cls
->parent(); cls
; cls
= cls
->parent()) {
179 auto& clsName
= cls
->nameRef();
180 ret
.set(clsName
, clsName
);
185 Variant
f_class_uses(CVarRef obj
, bool autoload
/* = true */) {
187 if (obj
.isString()) {
188 cls
= Unit::getClass(obj
.getStringData(), autoload
);
192 } else if (obj
.isObject()) {
193 cls
= obj
.getObjectData()->getVMClass();
197 Array
ret(Array::Create());
198 for (auto& elem
: cls
->usedTraits()) {
199 auto& traitName
= elem
->nameRef();
200 ret
.set(traitName
, traitName
);
205 Object
get_traversable_object_iterator(CVarRef obj
) {
206 if (!obj
.instanceof(SystemLib::s_TraversableClass
)) {
207 raise_error("Argument must implement interface Traversable");
210 bool isIteratorAggregate
;
211 Object itObj
= obj
.getObjectData()
212 ->iterableObject(isIteratorAggregate
, true);
214 if (!isIteratorAggregate
) {
215 if (obj
.instanceof(SystemLib::s_IteratorAggregateClass
)) {
216 raise_error("Objects returned by getIterator() must be traversable or "
217 "implement interface Iterator");
220 "Class %s must implement interface Traversable as part of either "
221 "Iterator or IteratorAggregate",
222 obj
.toObject()->o_getClassName()->data()
230 Variant
f_iterator_apply(CVarRef obj
, CVarRef func
,
231 CArrRef params
/* = null_array */) {
232 Object pobj
= get_traversable_object_iterator(obj
);
233 pobj
->o_invoke_few_args(s_rewind
, 0);
235 while (same(pobj
->o_invoke_few_args(s_valid
, 0), true)) {
236 if (!same(vm_call_user_func(func
, params
), true)) {
240 pobj
->o_invoke_few_args(s_next
, 0);
245 Variant
f_iterator_count(CVarRef obj
) {
246 Object pobj
= get_traversable_object_iterator(obj
);
247 pobj
->o_invoke_few_args(s_rewind
, 0);
249 while (same(pobj
->o_invoke_few_args(s_valid
, 0), true)) {
251 pobj
->o_invoke_few_args(s_next
, 0);
256 Variant
f_iterator_to_array(CVarRef obj
, bool use_keys
/* = true */) {
257 Object pobj
= get_traversable_object_iterator(obj
);
258 Array
ret(Array::Create());
260 pobj
->o_invoke_few_args(s_rewind
, 0);
261 while (same(pobj
->o_invoke_few_args(s_valid
, 0), true)) {
262 Variant val
= pobj
->o_invoke_few_args(s_current
, 0);
264 Variant key
= pobj
->o_invoke_few_args(s_key
, 0);
269 pobj
->o_invoke_few_args(s_next
, 0);
274 bool f_spl_autoload_register(CVarRef autoload_function
/* = null_variant */,
275 bool throws
/* = true */,
276 bool prepend
/* = false */) {
277 if (same(autoload_function
, s_spl_autoload_call
)) {
279 throw_spl_exception("Function spl_autoload_call()"
280 "cannot be registered");
284 CVarRef func
= autoload_function
.isNull() ?
285 s_spl_autoload
: autoload_function
;
286 bool res
= AutoloadHandler::s_instance
->addHandler(func
, prepend
);
287 if (!res
&& throws
) {
288 throw_spl_exception("Invalid autoload_function specified");
293 bool f_spl_autoload_unregister(CVarRef autoload_function
) {
294 if (same(autoload_function
, s_spl_autoload_call
)) {
295 AutoloadHandler::s_instance
->removeAllHandlers();
297 AutoloadHandler::s_instance
->removeHandler(autoload_function
);
302 Variant
f_spl_autoload_functions() {
303 CArrRef handlers
= AutoloadHandler::s_instance
->getHandlers();
304 if (handlers
.isNull())
307 return handlers
.values();
310 void f_spl_autoload_call(CStrRef class_name
) {
311 AutoloadHandler::s_instance
->invokeHandler(class_name
, true);
315 class ExtensionList
: public RequestEventHandler
{
317 virtual void requestInit() {
318 extensions
= CREATE_VECTOR2(String(".inc"), String(".php"));
320 virtual void requestShutdown() {
327 IMPLEMENT_STATIC_REQUEST_LOCAL(ExtensionList
, s_extension_list
);
330 String
f_spl_autoload_extensions(CStrRef file_extensions
/* = null_string */) {
331 if (!file_extensions
.isNull()) {
332 s_extension_list
->extensions
= StringUtil::Explode(file_extensions
, ",")
334 return file_extensions
;
336 return StringUtil::Implode(s_extension_list
->extensions
, ",");
339 void f_spl_autoload(CStrRef class_name
,
340 CStrRef file_extensions
/* = null_string */) {
341 Array ext
= file_extensions
.isNull()
342 ? s_extension_list
->extensions
343 : StringUtil::Explode(file_extensions
, ",").toArray();
344 String lClass
= StringUtil::ToLower(class_name
);
346 for (ArrayIter
iter(ext
); iter
; ++iter
) {
347 String fileName
= lClass
+ iter
.second().toString();
348 include(fileName
, true, "", false);
349 if (f_class_exists(class_name
, false)) {
355 if (!found
&& !AutoloadHandler::s_instance
->isRunning()) {
356 throw_spl_exception("Class %s could not be loaded", class_name
.c_str());
360 ///////////////////////////////////////////////////////////////////////////////