xref: /PHP-7.1/Zend/zend_interfaces.c (revision ccd4716e)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Marcus Boerger <helly@php.net>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 /* $Id$ */
20 
21 #include "zend.h"
22 #include "zend_API.h"
23 #include "zend_interfaces.h"
24 #include "zend_exceptions.h"
25 
26 ZEND_API zend_class_entry *zend_ce_traversable;
27 ZEND_API zend_class_entry *zend_ce_aggregate;
28 ZEND_API zend_class_entry *zend_ce_iterator;
29 ZEND_API zend_class_entry *zend_ce_arrayaccess;
30 ZEND_API zend_class_entry *zend_ce_serializable;
31 
32 /* {{{ zend_call_method
33  Only returns the returned zval if retval_ptr != NULL */
zend_call_method(zval * object,zend_class_entry * obj_ce,zend_function ** fn_proxy,const char * function_name,size_t function_name_len,zval * retval_ptr,int param_count,zval * arg1,zval * arg2)34 ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, size_t function_name_len, zval *retval_ptr, int param_count, zval* arg1, zval* arg2)
35 {
36 	int result;
37 	zend_fcall_info fci;
38 	zval retval;
39 	zval params[2];
40 
41 	if (param_count > 0) {
42 		ZVAL_COPY_VALUE(&params[0], arg1);
43 	}
44 	if (param_count > 1) {
45 		ZVAL_COPY_VALUE(&params[1], arg2);
46 	}
47 
48 	fci.size = sizeof(fci);
49 	fci.object = object ? Z_OBJ_P(object) : NULL;
50 	fci.retval = retval_ptr ? retval_ptr : &retval;
51 	fci.param_count = param_count;
52 	fci.params = params;
53 	fci.no_separation = 1;
54 
55 	if (!fn_proxy && !obj_ce) {
56 		/* no interest in caching and no information already present that is
57 		 * needed later inside zend_call_function. */
58 		ZVAL_STRINGL(&fci.function_name, function_name, function_name_len);
59 		result = zend_call_function(&fci, NULL);
60 		zval_ptr_dtor(&fci.function_name);
61 	} else {
62 		zend_fcall_info_cache fcic;
63 		ZVAL_UNDEF(&fci.function_name); /* Unused */
64 
65 		fcic.initialized = 1;
66 		if (!obj_ce) {
67 			obj_ce = object ? Z_OBJCE_P(object) : NULL;
68 		}
69 		if (!fn_proxy || !*fn_proxy) {
70 			HashTable *function_table = obj_ce ? &obj_ce->function_table : EG(function_table);
71 			fcic.function_handler = zend_hash_str_find_ptr(
72 				function_table, function_name, function_name_len);
73 			if (fcic.function_handler == NULL) {
74 				/* error at c-level */
75 				zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for method %s%s%s", obj_ce ? ZSTR_VAL(obj_ce->name) : "", obj_ce ? "::" : "", function_name);
76 			}
77 			if (fn_proxy) {
78 				*fn_proxy = fcic.function_handler;
79 			}
80 		} else {
81 			fcic.function_handler = *fn_proxy;
82 		}
83 
84 		fcic.calling_scope = obj_ce;
85 		if (object) {
86 			fcic.called_scope = Z_OBJCE_P(object);
87 		} else {
88 			zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data));
89 
90 			if (obj_ce &&
91 			    (!called_scope ||
92 			     !instanceof_function(called_scope, obj_ce))) {
93 				fcic.called_scope = obj_ce;
94 			} else {
95 				fcic.called_scope = called_scope;
96 			}
97 		}
98 		fcic.object = object ? Z_OBJ_P(object) : NULL;
99 		result = zend_call_function(&fci, &fcic);
100 	}
101 	if (result == FAILURE) {
102 		/* error at c-level */
103 		if (!obj_ce) {
104 			obj_ce = object ? Z_OBJCE_P(object) : NULL;
105 		}
106 		if (!EG(exception)) {
107 			zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", obj_ce ? ZSTR_VAL(obj_ce->name) : "", obj_ce ? "::" : "", function_name);
108 		}
109 	}
110 	/* copy arguments back, they might be changed by references */
111 	if (param_count > 0 && Z_ISREF(params[0]) && !Z_ISREF_P(arg1)) {
112 		ZVAL_COPY_VALUE(arg1, &params[0]);
113 	}
114 	if (param_count > 1 && Z_ISREF(params[1]) && !Z_ISREF_P(arg2)) {
115 		ZVAL_COPY_VALUE(arg2, &params[1]);
116 	}
117 	if (!retval_ptr) {
118 		zval_ptr_dtor(&retval);
119 		return NULL;
120 	}
121 	return retval_ptr;
122 }
123 /* }}} */
124 
125 /* iterator interface, c-level functions used by engine */
126 
127 /* {{{ zend_user_it_new_iterator */
zend_user_it_new_iterator(zend_class_entry * ce,zval * object,zval * retval)128 ZEND_API void zend_user_it_new_iterator(zend_class_entry *ce, zval *object, zval *retval)
129 {
130 	zend_call_method_with_0_params(object, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", retval);
131 }
132 /* }}} */
133 
134 /* {{{ zend_user_it_invalidate_current */
zend_user_it_invalidate_current(zend_object_iterator * _iter)135 ZEND_API void zend_user_it_invalidate_current(zend_object_iterator *_iter)
136 {
137 	zend_user_iterator *iter = (zend_user_iterator*)_iter;
138 
139 	if (!Z_ISUNDEF(iter->value)) {
140 		zval_ptr_dtor(&iter->value);
141 		ZVAL_UNDEF(&iter->value);
142 	}
143 }
144 /* }}} */
145 
146 /* {{{ zend_user_it_dtor */
zend_user_it_dtor(zend_object_iterator * _iter)147 static void zend_user_it_dtor(zend_object_iterator *_iter)
148 {
149 	zend_user_iterator *iter = (zend_user_iterator*)_iter;
150 	zval *object = &iter->it.data;
151 
152 	zend_user_it_invalidate_current(_iter);
153 	zval_ptr_dtor(object);
154 }
155 /* }}} */
156 
157 /* {{{ zend_user_it_valid */
zend_user_it_valid(zend_object_iterator * _iter)158 ZEND_API int zend_user_it_valid(zend_object_iterator *_iter)
159 {
160 	if (_iter) {
161 		zend_user_iterator *iter = (zend_user_iterator*)_iter;
162 		zval *object = &iter->it.data;
163 		zval more;
164 		int result;
165 
166 		zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs.zf_valid, "valid", &more);
167 		if (Z_TYPE(more) != IS_UNDEF) {
168 			result = i_zend_is_true(&more);
169 			zval_ptr_dtor(&more);
170 			return result ? SUCCESS : FAILURE;
171 		}
172 	}
173 	return FAILURE;
174 }
175 /* }}} */
176 
177 /* {{{ zend_user_it_get_current_data */
zend_user_it_get_current_data(zend_object_iterator * _iter)178 ZEND_API zval *zend_user_it_get_current_data(zend_object_iterator *_iter)
179 {
180 	zend_user_iterator *iter = (zend_user_iterator*)_iter;
181 	zval *object = &iter->it.data;
182 
183 	if (Z_ISUNDEF(iter->value)) {
184 		zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs.zf_current, "current", &iter->value);
185 	}
186 	return &iter->value;
187 }
188 /* }}} */
189 
190 /* {{{ zend_user_it_get_current_key_default */
191 #if 0
192 static int zend_user_it_get_current_key_default(zend_object_iterator *_iter, char **str_key, uint *str_key_len, ulong *int_key)
193 {
194 	*int_key = _iter->index;
195 	return HASH_KEY_IS_LONG;
196 }
197 #endif
198 /* }}} */
199 
200 /* {{{ zend_user_it_get_current_key */
zend_user_it_get_current_key(zend_object_iterator * _iter,zval * key)201 ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *key)
202 {
203 	zend_user_iterator *iter = (zend_user_iterator*)_iter;
204 	zval *object = &iter->it.data;
205 	zval retval;
206 
207 	zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs.zf_key, "key", &retval);
208 
209 	if (Z_TYPE(retval) != IS_UNDEF) {
210 		ZVAL_ZVAL(key, &retval, 1, 1);
211 	} else {
212 		if (!EG(exception)) {
213 			zend_error(E_WARNING, "Nothing returned from %s::key()", ZSTR_VAL(iter->ce->name));
214 		}
215 
216 		ZVAL_LONG(key, 0);
217 	}
218 }
219 /* }}} */
220 
221 /* {{{ zend_user_it_move_forward */
zend_user_it_move_forward(zend_object_iterator * _iter)222 ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter)
223 {
224 	zend_user_iterator *iter = (zend_user_iterator*)_iter;
225 	zval *object = &iter->it.data;
226 
227 	zend_user_it_invalidate_current(_iter);
228 	zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs.zf_next, "next", NULL);
229 }
230 /* }}} */
231 
232 /* {{{ zend_user_it_rewind */
zend_user_it_rewind(zend_object_iterator * _iter)233 ZEND_API void zend_user_it_rewind(zend_object_iterator *_iter)
234 {
235 	zend_user_iterator *iter = (zend_user_iterator*)_iter;
236 	zval *object = &iter->it.data;
237 
238 	zend_user_it_invalidate_current(_iter);
239 	zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs.zf_rewind, "rewind", NULL);
240 }
241 /* }}} */
242 
243 zend_object_iterator_funcs zend_interface_iterator_funcs_iterator = {
244 	zend_user_it_dtor,
245 	zend_user_it_valid,
246 	zend_user_it_get_current_data,
247 	zend_user_it_get_current_key,
248 	zend_user_it_move_forward,
249 	zend_user_it_rewind,
250 	zend_user_it_invalidate_current
251 };
252 
253 /* {{{ zend_user_it_get_iterator */
zend_user_it_get_iterator(zend_class_entry * ce,zval * object,int by_ref)254 static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
255 {
256 	zend_user_iterator *iterator;
257 
258 	if (by_ref) {
259 		zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
260 		return NULL;
261 	}
262 
263 	iterator = emalloc(sizeof(zend_user_iterator));
264 
265 	zend_iterator_init((zend_object_iterator*)iterator);
266 
267 	ZVAL_COPY(&iterator->it.data, object);
268 	iterator->it.funcs = ce->iterator_funcs.funcs;
269 	iterator->ce = Z_OBJCE_P(object);
270 	ZVAL_UNDEF(&iterator->value);
271 	return (zend_object_iterator*)iterator;
272 }
273 /* }}} */
274 
275 /* {{{ zend_user_it_get_new_iterator */
zend_user_it_get_new_iterator(zend_class_entry * ce,zval * object,int by_ref)276 ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object, int by_ref)
277 {
278 	zval iterator;
279 	zend_object_iterator *new_iterator;
280 	zend_class_entry *ce_it;
281 
282 	zend_user_it_new_iterator(ce, object, &iterator);
283 	ce_it = (Z_TYPE(iterator) == IS_OBJECT) ? Z_OBJCE(iterator) : NULL;
284 
285 	if (!ce_it || !ce_it->get_iterator || (ce_it->get_iterator == zend_user_it_get_new_iterator && Z_OBJ(iterator) == Z_OBJ_P(object))) {
286 		if (!EG(exception)) {
287 			zend_throw_exception_ex(NULL, 0, "Objects returned by %s::getIterator() must be traversable or implement interface Iterator", ce ? ZSTR_VAL(ce->name) : ZSTR_VAL(Z_OBJCE_P(object)->name));
288 		}
289 		zval_ptr_dtor(&iterator);
290 		return NULL;
291 	}
292 
293 	new_iterator = ce_it->get_iterator(ce_it, &iterator, by_ref);
294 	zval_ptr_dtor(&iterator);
295 	return new_iterator;
296 }
297 /* }}} */
298 
299 /* {{{ zend_implement_traversable */
zend_implement_traversable(zend_class_entry * interface,zend_class_entry * class_type)300 static int zend_implement_traversable(zend_class_entry *interface, zend_class_entry *class_type)
301 {
302 	/* check that class_type is traversable at c-level or implements at least one of 'aggregate' and 'Iterator' */
303 	uint32_t i;
304 
305 	if (class_type->get_iterator || (class_type->parent && class_type->parent->get_iterator)) {
306 		return SUCCESS;
307 	}
308 	for (i = 0; i < class_type->num_interfaces; i++) {
309 		if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) {
310 			return SUCCESS;
311 		}
312 	}
313 	zend_error_noreturn(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s",
314 		ZSTR_VAL(class_type->name),
315 		ZSTR_VAL(zend_ce_traversable->name),
316 		ZSTR_VAL(zend_ce_iterator->name),
317 		ZSTR_VAL(zend_ce_aggregate->name));
318 	return FAILURE;
319 }
320 /* }}} */
321 
322 /* {{{ zend_implement_aggregate */
zend_implement_aggregate(zend_class_entry * interface,zend_class_entry * class_type)323 static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entry *class_type)
324 {
325 	uint32_t i;
326 	int t = -1;
327 
328 	if (class_type->get_iterator) {
329 		if (class_type->type == ZEND_INTERNAL_CLASS) {
330 			/* inheritance ensures the class has necessary userland methods */
331 			return SUCCESS;
332 		} else if (class_type->get_iterator != zend_user_it_get_new_iterator) {
333 			/* c-level get_iterator cannot be changed (exception being only Traversable is implmented) */
334 			if (class_type->num_interfaces) {
335 				for (i = 0; i < class_type->num_interfaces; i++) {
336 					if (class_type->interfaces[i] == zend_ce_iterator) {
337 						zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time",
338 									ZSTR_VAL(class_type->name),
339 									ZSTR_VAL(interface->name),
340 									ZSTR_VAL(zend_ce_iterator->name));
341 						return FAILURE;
342 					}
343 					if (class_type->interfaces[i] == zend_ce_traversable) {
344 						t = i;
345 					}
346 				}
347 			}
348 			if (t == -1) {
349 				return FAILURE;
350 			}
351 		}
352 	}
353 	class_type->iterator_funcs.zf_new_iterator = NULL;
354 	class_type->get_iterator = zend_user_it_get_new_iterator;
355 	return SUCCESS;
356 }
357 /* }}} */
358 
359 /* {{{ zend_implement_iterator */
zend_implement_iterator(zend_class_entry * interface,zend_class_entry * class_type)360 static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type)
361 {
362 	if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) {
363 		if (class_type->type == ZEND_INTERNAL_CLASS) {
364 			/* inheritance ensures the class has the necessary userland methods */
365 			return SUCCESS;
366 		} else {
367 			/* c-level get_iterator cannot be changed */
368 			if (class_type->get_iterator == zend_user_it_get_new_iterator) {
369 				zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time",
370 							ZSTR_VAL(class_type->name),
371 							ZSTR_VAL(interface->name),
372 							ZSTR_VAL(zend_ce_aggregate->name));
373 			}
374 			return FAILURE;
375 		}
376 	}
377 	class_type->get_iterator = zend_user_it_get_iterator;
378 	class_type->iterator_funcs.zf_valid = NULL;
379 	class_type->iterator_funcs.zf_current = NULL;
380 	class_type->iterator_funcs.zf_key = NULL;
381 	class_type->iterator_funcs.zf_next = NULL;
382 	class_type->iterator_funcs.zf_rewind = NULL;
383 	if (!class_type->iterator_funcs.funcs) {
384 		class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
385 	}
386 	return SUCCESS;
387 }
388 /* }}} */
389 
390 /* {{{ zend_implement_arrayaccess */
zend_implement_arrayaccess(zend_class_entry * interface,zend_class_entry * class_type)391 static int zend_implement_arrayaccess(zend_class_entry *interface, zend_class_entry *class_type)
392 {
393 #if 0
394 	/* get ht from ce */
395 	if (ht->read_dimension != zend_std_read_dimension
396 	||  ht->write_dimension != zend_std_write_dimension
397 	||  ht->has_dimension != zend_std_has_dimension
398 	||  ht->unset_dimension != zend_std_unset_dimension) {
399 		return FAILURE;
400 	}
401 #endif
402 	return SUCCESS;
403 }
404 /* }}}*/
405 
406 /* {{{ zend_user_serialize */
zend_user_serialize(zval * object,unsigned char ** buffer,size_t * buf_len,zend_serialize_data * data)407 ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
408 {
409 	zend_class_entry * ce = Z_OBJCE_P(object);
410 	zval retval;
411 	int result;
412 
413 	zend_call_method_with_0_params(object, ce, &ce->serialize_func, "serialize", &retval);
414 
415 
416 	if (Z_TYPE(retval) == IS_UNDEF || EG(exception)) {
417 		result = FAILURE;
418 	} else {
419 		switch(Z_TYPE(retval)) {
420 		case IS_NULL:
421 			/* we could also make this '*buf_len = 0' but this allows to skip variables */
422 			zval_ptr_dtor(&retval);
423 			return FAILURE;
424 		case IS_STRING:
425 			*buffer = (unsigned char*)estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
426 			*buf_len = Z_STRLEN(retval);
427 			result = SUCCESS;
428 			break;
429 		default: /* failure */
430 			result = FAILURE;
431 			break;
432 		}
433 		zval_ptr_dtor(&retval);
434 	}
435 
436 	if (result == FAILURE && !EG(exception)) {
437 		zend_throw_exception_ex(NULL, 0, "%s::serialize() must return a string or NULL", ZSTR_VAL(ce->name));
438 	}
439 	return result;
440 }
441 /* }}} */
442 
443 /* {{{ zend_user_unserialize */
zend_user_unserialize(zval * object,zend_class_entry * ce,const unsigned char * buf,size_t buf_len,zend_unserialize_data * data)444 ZEND_API int zend_user_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data)
445 {
446 	zval zdata;
447 
448 	if (UNEXPECTED(object_init_ex(object, ce) != SUCCESS)) {
449 		return FAILURE;
450 	}
451 
452 	ZVAL_STRINGL(&zdata, (char*)buf, buf_len);
453 
454 	zend_call_method_with_1_params(object, ce, &ce->unserialize_func, "unserialize", NULL, &zdata);
455 
456 	zval_ptr_dtor(&zdata);
457 
458 	if (EG(exception)) {
459 		return FAILURE;
460 	} else {
461 		return SUCCESS;
462 	}
463 }
464 /* }}} */
465 
zend_class_serialize_deny(zval * object,unsigned char ** buffer,size_t * buf_len,zend_serialize_data * data)466 ZEND_API int zend_class_serialize_deny(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) /* {{{ */
467 {
468 	zend_class_entry *ce = Z_OBJCE_P(object);
469 	zend_throw_exception_ex(NULL, 0, "Serialization of '%s' is not allowed", ZSTR_VAL(ce->name));
470 	return FAILURE;
471 }
472 /* }}} */
473 
zend_class_unserialize_deny(zval * object,zend_class_entry * ce,const unsigned char * buf,size_t buf_len,zend_unserialize_data * data)474 ZEND_API int zend_class_unserialize_deny(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) /* {{{ */
475 {
476 	zend_throw_exception_ex(NULL, 0, "Unserialization of '%s' is not allowed", ZSTR_VAL(ce->name));
477 	return FAILURE;
478 }
479 /* }}} */
480 
481 /* {{{ zend_implement_serializable */
zend_implement_serializable(zend_class_entry * interface,zend_class_entry * class_type)482 static int zend_implement_serializable(zend_class_entry *interface, zend_class_entry *class_type)
483 {
484 	if (class_type->parent
485 		&& (class_type->parent->serialize || class_type->parent->unserialize)
486 		&& !instanceof_function_ex(class_type->parent, zend_ce_serializable, 1)) {
487 		return FAILURE;
488 	}
489 	if (!class_type->serialize) {
490 		class_type->serialize = zend_user_serialize;
491 	}
492 	if (!class_type->unserialize) {
493 		class_type->unserialize = zend_user_unserialize;
494 	}
495 	return SUCCESS;
496 }
497 /* }}}*/
498 
499 /* {{{ function tables */
500 const zend_function_entry zend_funcs_aggregate[] = {
501 	ZEND_ABSTRACT_ME(iterator, getIterator, NULL)
502 	ZEND_FE_END
503 };
504 
505 const zend_function_entry zend_funcs_iterator[] = {
506 	ZEND_ABSTRACT_ME(iterator, current,  NULL)
507 	ZEND_ABSTRACT_ME(iterator, next,     NULL)
508 	ZEND_ABSTRACT_ME(iterator, key,      NULL)
509 	ZEND_ABSTRACT_ME(iterator, valid,    NULL)
510 	ZEND_ABSTRACT_ME(iterator, rewind,   NULL)
511 	ZEND_FE_END
512 };
513 
514 const zend_function_entry *zend_funcs_traversable    = NULL;
515 
516 ZEND_BEGIN_ARG_INFO_EX(arginfo_arrayaccess_offset, 0, 0, 1)
517 	ZEND_ARG_INFO(0, offset)
518 ZEND_END_ARG_INFO()
519 
520 ZEND_BEGIN_ARG_INFO_EX(arginfo_arrayaccess_offset_get, 0, 0, 1) /* actually this should be return by ref but atm cannot be */
521 	ZEND_ARG_INFO(0, offset)
522 ZEND_END_ARG_INFO()
523 
524 ZEND_BEGIN_ARG_INFO_EX(arginfo_arrayaccess_offset_value, 0, 0, 2)
525 	ZEND_ARG_INFO(0, offset)
526 	ZEND_ARG_INFO(0, value)
527 ZEND_END_ARG_INFO()
528 
529 const zend_function_entry zend_funcs_arrayaccess[] = {
530 	ZEND_ABSTRACT_ME(arrayaccess, offsetExists, arginfo_arrayaccess_offset)
531 	ZEND_ABSTRACT_ME(arrayaccess, offsetGet,    arginfo_arrayaccess_offset_get)
532 	ZEND_ABSTRACT_ME(arrayaccess, offsetSet,    arginfo_arrayaccess_offset_value)
533 	ZEND_ABSTRACT_ME(arrayaccess, offsetUnset,  arginfo_arrayaccess_offset)
534 	ZEND_FE_END
535 };
536 
537 ZEND_BEGIN_ARG_INFO(arginfo_serializable_serialize, 0)
538 	ZEND_ARG_INFO(0, serialized)
539 ZEND_END_ARG_INFO()
540 
541 const zend_function_entry zend_funcs_serializable[] = {
542 	ZEND_ABSTRACT_ME(serializable, serialize,   NULL)
543 	ZEND_FENTRY(unserialize, NULL, arginfo_serializable_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT|ZEND_ACC_CTOR)
544 	ZEND_FE_END
545 };
546 /* }}} */
547 
548 /* {{{ zend_register_interfaces */
zend_register_interfaces(void)549 ZEND_API void zend_register_interfaces(void)
550 {
551 	REGISTER_MAGIC_INTERFACE(traversable, Traversable);
552 
553 	REGISTER_MAGIC_INTERFACE(aggregate, IteratorAggregate);
554 	REGISTER_MAGIC_IMPLEMENT(aggregate, traversable);
555 
556 	REGISTER_MAGIC_INTERFACE(iterator, Iterator);
557 	REGISTER_MAGIC_IMPLEMENT(iterator, traversable);
558 
559 	REGISTER_MAGIC_INTERFACE(arrayaccess, ArrayAccess);
560 
561 	REGISTER_MAGIC_INTERFACE(serializable, Serializable);
562 }
563 /* }}} */
564 
565 /*
566  * Local variables:
567  * tab-width: 4
568  * c-basic-offset: 4
569  * indent-tabs-mode: t
570  * End:
571  */
572