2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
18 #include <runtime/ext/ext_spl.h>
19 #include <runtime/ext/ext_math.h>
20 #include <runtime/ext/ext_class.h>
22 #include <system/lib/systemlib.h>
25 ///////////////////////////////////////////////////////////////////////////////
27 static StaticString
s_spl_autoload("spl_autoload");
28 static StaticString
s_spl_autoload_call("spl_autoload_call");
29 static StaticString
s_default_extensions(".inc,.php");
31 #define SPL_ADD_CLASS(cls) ret.set(#cls, #cls)
33 Array
f_spl_classes() {
35 SPL_ADD_CLASS(AppendIterator
);
36 SPL_ADD_CLASS(ArrayIterator
);
37 SPL_ADD_CLASS(ArrayObject
);
38 SPL_ADD_CLASS(BadFunctionCallException
);
39 SPL_ADD_CLASS(BadMethodCallException
);
40 SPL_ADD_CLASS(CachingIterator
);
41 SPL_ADD_CLASS(Countable
);
42 SPL_ADD_CLASS(DirectoryIterator
);
43 SPL_ADD_CLASS(DomainException
);
44 SPL_ADD_CLASS(EmptyIterator
);
45 SPL_ADD_CLASS(FilesystemIterator
);
46 SPL_ADD_CLASS(FilterIterator
);
47 SPL_ADD_CLASS(GlobIterator
);
48 SPL_ADD_CLASS(InfiniteIterator
);
49 SPL_ADD_CLASS(InvalidArgumentException
);
50 SPL_ADD_CLASS(IteratorIterator
);
51 SPL_ADD_CLASS(LengthException
);
52 SPL_ADD_CLASS(LimitIterator
);
53 SPL_ADD_CLASS(LogicException
);
54 SPL_ADD_CLASS(MultipleIterator
);
55 SPL_ADD_CLASS(NoRewindIterator
);
56 SPL_ADD_CLASS(OuterIterator
);
57 SPL_ADD_CLASS(OutOfBoundsException
);
58 SPL_ADD_CLASS(OutOfRangeException
);
59 SPL_ADD_CLASS(OverflowException
);
60 SPL_ADD_CLASS(ParentIterator
);
61 SPL_ADD_CLASS(RangeException
);
62 SPL_ADD_CLASS(RecursiveArrayIterator
);
63 SPL_ADD_CLASS(RecursiveCachingIterator
);
64 SPL_ADD_CLASS(RecursiveDirectoryIterator
);
65 SPL_ADD_CLASS(RecursiveFilterIterator
);
66 SPL_ADD_CLASS(RecursiveIterator
);
67 SPL_ADD_CLASS(RecursiveIteratorIterator
);
68 SPL_ADD_CLASS(RecursiveRegexIterator
);
69 SPL_ADD_CLASS(RecursiveTreeIterator
);
70 SPL_ADD_CLASS(RegexIterator
);
71 SPL_ADD_CLASS(RuntimeException
);
72 SPL_ADD_CLASS(SeekableIterator
);
73 SPL_ADD_CLASS(SplDoublyLinkedList
);
74 SPL_ADD_CLASS(SplFileInfo
);
75 SPL_ADD_CLASS(SplFileObject
);
76 SPL_ADD_CLASS(SplFixedArray
);
77 SPL_ADD_CLASS(SplHeap
);
78 SPL_ADD_CLASS(SplMinHeap
);
79 SPL_ADD_CLASS(SplMaxHeap
);
80 SPL_ADD_CLASS(SplObjectStorage
);
81 SPL_ADD_CLASS(SplObserver
);
82 SPL_ADD_CLASS(SplPriorityQueue
);
83 SPL_ADD_CLASS(SplQueue
);
84 SPL_ADD_CLASS(SplStack
);
85 SPL_ADD_CLASS(SplSubject
);
86 SPL_ADD_CLASS(SplTempFileObject
);
87 SPL_ADD_CLASS(UnderflowException
);
88 SPL_ADD_CLASS(UnexpectedValueException
);
92 void throw_spl_exception(const char *fmt
, ...) {
96 Util::string_vsnprintf(msg
, fmt
, ap
);
99 throw Object(SystemLib::AllocExceptionObject(Variant(msg
)));
102 static bool s_inited
= false;
103 static int64 s_hash_mask_handle
= 0;
104 static Mutex s_mutex
;
106 String
f_spl_object_hash(CObjRef obj
) {
111 s_hash_mask_handle
|= f_mt_rand(); s_hash_mask_handle
<<= 16;
112 s_hash_mask_handle
|= f_mt_rand(); s_hash_mask_handle
<<= 16;
113 s_hash_mask_handle
|= f_mt_rand(); s_hash_mask_handle
<<= 16;
114 s_hash_mask_handle
|= f_mt_rand();
120 snprintf(buf
, sizeof(buf
), "%032llx", s_hash_mask_handle
^ (int64
)obj
.get());
121 return String(buf
, CopyString
);
124 Variant
f_hphp_get_this() {
126 return g_vmContext
->getThis();
128 return FrameInjection::GetThis();
132 Variant
f_class_implements(CVarRef obj
, bool autoload
/* = true */) {
134 if (obj
.isString()) {
135 clsname
= obj
.toString();
136 } else if (obj
.isObject()) {
137 clsname
= obj
.toObject()->o_getClassName();
142 const ClassInfo
*info
= ClassInfo::FindClassInterfaceOrTrait(clsname
);
144 if (!autoload
) return false;
145 AutoloadHandler::s_instance
->invokeHandler(clsname
);
146 return f_class_implements(clsname
, false);
149 Array
ret(Array::Create());
150 ClassInfo::InterfaceVec ifs
;
151 info
->getAllInterfacesVec(ifs
);
152 for (unsigned int i
= 0; i
< ifs
.size(); i
++) {
153 ret
.set(ifs
[i
], ifs
[i
]);
159 Variant
f_class_parents(CVarRef obj
, bool autoload
/* = true */) {
161 if (obj
.isString()) {
162 clsname
= obj
.toString();
163 } else if (obj
.isObject()) {
164 clsname
= obj
.toObject()->o_getClassName();
169 const ClassInfo
*info
= ClassInfo::FindClassInterfaceOrTrait(clsname
);
171 if (!autoload
) return false;
172 AutoloadHandler::s_instance
->invokeHandler(clsname
);
173 return f_class_parents(clsname
, false);
176 Array
ret(Array::Create());
177 ClassInfo::ClassVec parents
;
178 info
->getAllParentsVec(parents
);
179 for (unsigned int i
= 0; i
< parents
.size(); i
++) {
180 ret
.set(parents
[i
], parents
[i
]);
186 Variant
f_class_uses(CVarRef obj
, bool autoload
/* = true */) {
188 if (obj
.isString()) {
189 clsname
= obj
.toString();
190 } else if (obj
.isObject()) {
191 clsname
= obj
.toObject()->o_getClassName();
196 const ClassInfo
*info
= ClassInfo::FindClassInterfaceOrTrait(clsname
);
198 if (!autoload
) return false;
199 AutoloadHandler::s_instance
->invokeHandler(clsname
);
200 return f_class_uses(clsname
, false);
203 Array
ret(Array::Create());
204 const ClassInfo::TraitVec
&traits
= info
->getTraitsVec();
205 for (unsigned int i
= 0; i
< traits
.size(); i
++) {
206 ret
.set(traits
[i
], traits
[i
]);
212 Variant
f_iterator_apply(CVarRef obj
, CVarRef func
,
213 CArrRef params
/* = null_array */) {
214 if (!obj
.instanceof("Traversable")) {
217 Object pobj
= obj
.toObject();
218 pobj
->o_invoke("rewind", null_array
, -1);
220 while (same(pobj
->o_invoke("valid", null_array
, -1), true)) {
221 if (!same(f_call_user_func_array(func
, params
), true)) {
225 pobj
->o_invoke("next", null_array
, -1);
230 Variant
f_iterator_count(CVarRef obj
) {
231 if (!obj
.instanceof("Traversable")) {
234 Object pobj
= obj
.toObject();
235 pobj
->o_invoke("rewind", null_array
, -1);
237 while (same(pobj
->o_invoke("valid", null_array
, -1), true)) {
239 pobj
->o_invoke("next", null_array
, -1);
244 Variant
f_iterator_to_array(CVarRef obj
, bool use_keys
/* = true */) {
245 if (!obj
.instanceof("Traversable")) {
248 Array
ret(Array::Create());
249 Object pobj
= obj
.toObject();
250 pobj
->o_invoke("rewind", null_array
, -1);
251 while (same(pobj
->o_invoke("valid", null_array
, -1), true)) {
252 Variant val
= pobj
->o_invoke("current", null_array
, -1);
254 Variant key
= pobj
->o_invoke("key", null_array
, -1);
259 pobj
->o_invoke("next", null_array
, -1);
264 bool f_spl_autoload_register(CVarRef autoload_function
/* = null_variant */,
265 bool throws
/* = true */,
266 bool prepend
/* = false */) {
267 if (autoload_function
.same(s_spl_autoload_call
)) {
269 throw_spl_exception("Function spl_autoload_call()"
270 "cannot be registered");
274 CVarRef func
= autoload_function
.isNull() ?
275 s_spl_autoload
: autoload_function
;
276 bool res
= AutoloadHandler::s_instance
->addHandler(func
, prepend
);
277 if (!res
&& throws
) {
278 throw_spl_exception("Invalid autoload_function specified");
283 bool f_spl_autoload_unregister(CVarRef autoload_function
) {
284 if (autoload_function
.same(s_spl_autoload_call
)) {
285 AutoloadHandler::s_instance
->removeAllHandlers();
287 AutoloadHandler::s_instance
->removeHandler(autoload_function
);
292 Variant
f_spl_autoload_functions() {
293 CArrRef handlers
= AutoloadHandler::s_instance
->getHandlers();
294 if (handlers
.isNull())
297 return handlers
.values();
300 void f_spl_autoload_call(CStrRef class_name
) {
301 AutoloadHandler::s_instance
->invokeHandler(class_name
, NULL
, true);
305 class ExtensionList
: public RequestEventHandler
{
307 virtual void requestInit() {
308 extensions
= CREATE_VECTOR2(String(".inc"), String(".php"));
310 virtual void requestShutdown() {
317 IMPLEMENT_STATIC_REQUEST_LOCAL(ExtensionList
, s_extension_list
);
320 String
f_spl_autoload_extensions(CStrRef file_extensions
/* = null_string */) {
321 if (!file_extensions
.isNull()) {
322 s_extension_list
->extensions
= StringUtil::Explode(file_extensions
, ",")
324 return file_extensions
;
326 return StringUtil::Implode(s_extension_list
->extensions
, ",");
329 void f_spl_autoload(CStrRef class_name
,
330 CStrRef file_extensions
/* = null_string */) {
331 Array ext
= file_extensions
.isNull()
332 ? s_extension_list
->extensions
333 : StringUtil::Explode(file_extensions
, ",").toArray();
334 String lClass
= StringUtil::ToLower(class_name
);
335 Globals
*g
= get_globals();
337 for (ArrayIter
iter(ext
); iter
; ++iter
) {
338 String fileName
= lClass
+ iter
.second();
339 include(fileName
, true, g
, "", false);
340 if (f_class_exists(class_name
, false)) {
346 if (!found
&& !AutoloadHandler::s_instance
->isRunning()) {
347 throw_spl_exception("Class %s could not be loaded", class_name
.c_str());
351 ///////////////////////////////////////////////////////////////////////////////