1 
2 /*
3   +------------------------------------------------------------------------+
4   | Zephir Language                                                        |
5   +------------------------------------------------------------------------+
6   | Copyright (c) 2011-2017 Zephir Team (http://www.zephir-lang.com)       |
7   +------------------------------------------------------------------------+
8   | This source file is subject to the New BSD License that is bundled     |
9   | with this package in the file docs/LICENSE.txt.                        |
10   |                                                                        |
11   | If you did not receive a copy of the license and are unable to         |
12   | obtain it through the world-wide-web, please send an email             |
13   | to license@zephir-lang.com so we can send you a copy immediately.      |
14   +------------------------------------------------------------------------+
15   | Authors: Andres Gutierrez <andres@zephir-lang.com>                     |
16   |          Eduar Carvajal <eduar@zephir-lang.com>                        |
17   |          Vladimir Kolesnikov <vladimir@extrememember.com>              |
18   +------------------------------------------------------------------------+
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <php.h>
26 #include "php_ext.h"
27 
28 #include <Zend/zend_closures.h>
29 
30 #include "kernel/main.h"
31 #include "kernel/memory.h"
32 #include "kernel/object.h"
33 #include "kernel/exception.h"
34 #include "kernel/fcall.h"
35 #include "kernel/array.h"
36 #include "kernel/operators.h"
37 
38 
39 /**
40  * Reads class constant from string name and returns its value
41  */
zephir_get_class_constant(zval * return_value,zend_class_entry * ce,char * constant_name,unsigned int constant_length TSRMLS_DC)42 int zephir_get_class_constant(zval *return_value, zend_class_entry *ce, char *constant_name, unsigned int constant_length TSRMLS_DC) {
43 
44 	zval **result_ptr;
45 
46 	if (zend_hash_find(&ce->constants_table, constant_name, constant_length, (void **) &result_ptr) != SUCCESS) {
47 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Undefined class constant '%s::%s'", ce->name, constant_name);
48 		return FAILURE;
49 	}
50 
51 	ZVAL_ZVAL(return_value, *result_ptr, 1, 0);
52 	return SUCCESS;
53 }
54 
55 /**
56  * Check if class is instance of
57  */
zephir_instance_of(zval * result,const zval * object,const zend_class_entry * ce TSRMLS_DC)58 int zephir_instance_of(zval *result, const zval *object, const zend_class_entry *ce TSRMLS_DC) {
59 
60 	if (Z_TYPE_P(object) != IS_OBJECT) {
61 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "instanceof expects an object instance");
62 		ZVAL_FALSE(result);
63 		return FAILURE;
64 	}
65 
66 	ZVAL_BOOL(result, instanceof_function(Z_OBJCE_P(object), ce TSRMLS_CC));
67 	return SUCCESS;
68 }
69 
zephir_instance_of_ev(const zval * object,const zend_class_entry * ce TSRMLS_DC)70 int zephir_instance_of_ev(const zval *object, const zend_class_entry *ce TSRMLS_DC) {
71 
72 	if (Z_TYPE_P(object) != IS_OBJECT) {
73 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "instanceof expects an object instance");
74 		return 0;
75 	}
76 
77 	return instanceof_function(Z_OBJCE_P(object), ce TSRMLS_CC);
78 }
79 
80 /**
81  * Check if an object is instance of a class
82  */
zephir_is_instance_of(zval * object,const char * class_name,unsigned int class_length TSRMLS_DC)83 int zephir_is_instance_of(zval *object, const char *class_name, unsigned int class_length TSRMLS_DC) {
84 
85 	zend_class_entry *ce, *temp_ce;
86 
87 	if (Z_TYPE_P(object) == IS_OBJECT) {
88 
89 		ce = Z_OBJCE_P(object);
90 		if (ce->name_length == class_length) {
91 		  	if (!zend_binary_strcasecmp(ce->name, ce->name_length, class_name, class_length)) {
92                             return 1;
93                         }
94 		}
95 
96 		temp_ce = zend_fetch_class(class_name, class_length, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
97 		if (temp_ce) {
98 			return instanceof_function(ce, temp_ce TSRMLS_CC);
99 		}
100 	}
101 
102 	return 0;
103 }
104 
zephir_zval_is_traversable(zval * object TSRMLS_DC)105 int zephir_zval_is_traversable(zval *object TSRMLS_DC) {
106 
107 	zend_class_entry *ce;
108 	zend_uint i;
109 
110 	if (Z_TYPE_P(object) == IS_OBJECT) {
111 		ce = Z_OBJCE_P(object);
112 
113 		if (ce->get_iterator || (ce->parent && ce->parent->get_iterator)) {
114 			return 1;
115 		}
116 
117 		for (i = 0; i < ce->num_interfaces; i++) {
118 			if (ce->interfaces[i] == zend_ce_aggregate ||
119 				ce->interfaces[i] == zend_ce_iterator ||
120 				ce->interfaces[i] == zend_ce_traversable
121 			) {
122 				return 1;
123 			}
124 		}
125 	}
126 
127 	return 0;
128 }
129 
130 /**
131  * Returns a class name into a zval result
132  */
zephir_get_class(zval * result,zval * object,int lower TSRMLS_DC)133 void zephir_get_class(zval *result, zval *object, int lower TSRMLS_DC) {
134 
135 	zend_class_entry *ce;
136 
137 	if (Z_TYPE_P(object) == IS_OBJECT) {
138 
139 		ce = Z_OBJCE_P(object);
140 		Z_STRLEN_P(result) = ce->name_length;
141 		Z_STRVAL_P(result) = (char *) emalloc(ce->name_length + 1);
142 		memcpy(Z_STRVAL_P(result), ce->name, ce->name_length);
143 		Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
144 		Z_TYPE_P(result) = IS_STRING;
145 
146 		if (lower) {
147 			zend_str_tolower(Z_STRVAL_P(result), Z_STRLEN_P(result));
148 		}
149 
150 	} else {
151 		ZVAL_NULL(result);
152 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_class expects an object");
153 	}
154 }
155 
156 /**
157  * Returns a class name into a zval result
158  */
zephir_get_class_ns(zval * result,zval * object,int lower TSRMLS_DC)159 void zephir_get_class_ns(zval *result, zval *object, int lower TSRMLS_DC) {
160 
161 	int found = 0;
162 	zend_class_entry *ce;
163 	unsigned int i, class_length;
164 	const char *cursor, *class_name;
165 
166 	if (Z_TYPE_P(object) != IS_OBJECT) {
167 		if (Z_TYPE_P(object) != IS_STRING) {
168 			ZVAL_NULL(result);
169 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_class_ns expects an object");
170 			return;
171 		}
172 	}
173 
174 	if (Z_TYPE_P(object) == IS_OBJECT) {
175 		ce = Z_OBJCE_P(object);
176 		class_name = ce->name;
177 		class_length = ce->name_length;
178 	} else {
179 		class_name = Z_STRVAL_P(object);
180 		class_length = Z_STRLEN_P(object);
181 	}
182 
183 	if (!class_length) {
184 		ZVAL_NULL(result);
185 		return;
186 	}
187 
188 	i = class_length;
189 	cursor = (char *) (class_name + class_length - 1);
190 
191 	while (i > 0) {
192 		if ((*cursor) == '\\') {
193 			found = 1;
194 			break;
195 		}
196 		cursor--;
197 		i--;
198 	}
199 
200 	if (found) {
201 		Z_STRLEN_P(result) = class_length - i;
202 		Z_STRVAL_P(result) = (char *) emalloc(class_length - i + 1);
203 		memcpy(Z_STRVAL_P(result), class_name + i, class_length - i);
204 		Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
205 		Z_TYPE_P(result) = IS_STRING;
206 	} else {
207 		ZVAL_STRINGL(result, class_name, class_length, 1);
208 	}
209 
210 	if (lower) {
211 		zend_str_tolower(Z_STRVAL_P(result), Z_STRLEN_P(result));
212 	}
213 
214 }
215 
216 /**
217  * Returns a namespace from a class name
218  */
zephir_get_ns_class(zval * result,zval * object,int lower TSRMLS_DC)219 void zephir_get_ns_class(zval *result, zval *object, int lower TSRMLS_DC) {
220 
221 	zend_class_entry *ce;
222 	int found = 0;
223 	unsigned int i, j, class_length;
224 	const char *cursor, *class_name;
225 
226 	if (Z_TYPE_P(object) != IS_OBJECT) {
227 		if (Z_TYPE_P(object) != IS_STRING) {
228 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_ns_class expects an object");
229 			ZVAL_NULL(result);
230 			return;
231 		}
232 	}
233 
234 	if (Z_TYPE_P(object) == IS_OBJECT) {
235 		ce = Z_OBJCE_P(object);
236 		class_name = ce->name;
237 		class_length = ce->name_length;
238 	} else {
239 		class_name = Z_STRVAL_P(object);
240 		class_length = Z_STRLEN_P(object);
241 	}
242 
243 	if (!class_length) {
244 		ZVAL_NULL(result);
245 		return;
246 	}
247 
248 	j = 0;
249 	i = class_length;
250 	cursor = (char *) (class_name + class_length - 1);
251 
252 	while (i > 0) {
253 		if ((*cursor) == '\\') {
254 			found = 1;
255 			break;
256 		}
257 		cursor--;
258 		i--;
259 		j++;
260 	}
261 
262 	if (j > 0) {
263 
264 		if (found) {
265 			Z_STRLEN_P(result) = class_length - j - 1;
266 			Z_STRVAL_P(result) = (char *) emalloc(class_length - j);
267 			memcpy(Z_STRVAL_P(result), class_name, class_length - j - 1);
268 			Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
269 			Z_TYPE_P(result) = IS_STRING;
270 		} else {
271 			ZVAL_EMPTY_STRING(result);
272 		}
273 
274 		if (lower) {
275 			zend_str_tolower(Z_STRVAL_P(result), Z_STRLEN_P(result));
276 		}
277 	} else {
278 		ZVAL_NULL(result);
279 	}
280 
281 }
282 
283 /**
284  * Returns the called in class in the current scope
285  */
zephir_get_called_class(zval * return_value TSRMLS_DC)286 void zephir_get_called_class(zval *return_value TSRMLS_DC) {
287 
288 	if (EG(called_scope)) {
289 		RETURN_STRINGL(EG(called_scope)->name, EG(called_scope)->name_length, 1);
290 	}
291 
292 	if (!EG(scope))  {
293 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_called_class() called from outside a class");
294 	}
295 }
296 
297 /**
298  * Fetches a zend class entry from a zval value
299  */
zephir_fetch_class(const zval * class_name TSRMLS_DC)300 zend_class_entry *zephir_fetch_class(const zval *class_name TSRMLS_DC) {
301 
302 	if (Z_TYPE_P(class_name) == IS_STRING) {
303 		return zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
304 	}
305 
306 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "class name must be a string");
307 	return zend_fetch_class("stdclass", strlen("stdclass"), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
308 }
309 
zephir_fetch_self_class(TSRMLS_D)310 zend_class_entry* zephir_fetch_self_class(TSRMLS_D) {
311 	return zend_fetch_class(NULL, 0, ZEND_FETCH_CLASS_SELF TSRMLS_CC);
312 }
313 
zephir_fetch_parent_class(TSRMLS_D)314 zend_class_entry* zephir_fetch_parent_class(TSRMLS_D) {
315 	return zend_fetch_class(NULL, 0, ZEND_FETCH_CLASS_PARENT TSRMLS_CC);
316 }
317 
zephir_fetch_static_class(TSRMLS_D)318 zend_class_entry* zephir_fetch_static_class(TSRMLS_D) {
319 	return zend_fetch_class(NULL, 0, ZEND_FETCH_CLASS_STATIC TSRMLS_CC);
320 }
321 
322 /**
323  * Checks if a class exist
324  */
zephir_class_exists(const zval * class_name,int autoload TSRMLS_DC)325 int zephir_class_exists(const zval *class_name, int autoload TSRMLS_DC) {
326 
327 	zend_class_entry **ce;
328 
329 	if (Z_TYPE_P(class_name) == IS_STRING) {
330 		if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &ce TSRMLS_CC) == SUCCESS) {
331 			return ((*ce)->ce_flags & (ZEND_ACC_INTERFACE | (ZEND_ACC_TRAIT - ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) == 0;
332 		}
333 		return 0;
334 	}
335 
336 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "class name must be a string");
337 	return 0;
338 }
339 
340 /**
341  * Checks if a interface exist
342  */
zephir_interface_exists(const zval * class_name,int autoload TSRMLS_DC)343 int zephir_interface_exists(const zval *class_name, int autoload TSRMLS_DC) {
344 
345 	zend_class_entry **ce;
346 
347 	if (Z_TYPE_P(class_name) == IS_STRING) {
348 		if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &ce TSRMLS_CC) == SUCCESS) {
349 			return (((*ce)->ce_flags & ZEND_ACC_INTERFACE) > 0);
350 		}
351 		return 0;
352 	}
353 
354 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "interface name must be a string");
355 	return 0;
356 }
357 
358 /**
359  * Clones an object from obj to destination
360  */
zephir_clone(zval * destination,zval * obj TSRMLS_DC)361 int zephir_clone(zval *destination, zval *obj TSRMLS_DC) {
362 
363 	int status = SUCCESS;
364 	zend_class_entry *ce;
365 	zend_object_clone_obj_t clone_call;
366 
367 	if (Z_TYPE_P(obj) != IS_OBJECT) {
368 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "__clone method called on non-object");
369 		status = FAILURE;
370 	} else {
371 		ce = Z_OBJCE_P(obj);
372 		clone_call =  Z_OBJ_HT_P(obj)->clone_obj;
373 		if (!clone_call) {
374 			if (ce) {
375 				php_error_docref(NULL TSRMLS_CC, E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name);
376 			} else {
377 				php_error_docref(NULL TSRMLS_CC, E_ERROR, "Trying to clone an uncloneable object");
378 			}
379 			status = FAILURE;
380 		} else {
381 			if (!EG(exception)) {
382 				Z_OBJVAL_P(destination) = clone_call(obj TSRMLS_CC);
383 				Z_TYPE_P(destination) = IS_OBJECT;
384 				Z_SET_REFCOUNT_P(destination, 1);
385 				Z_UNSET_ISREF_P(destination);
386 				if (EG(exception)) {
387 					zval_ptr_dtor(&destination);
388 				}
389 			}
390 		}
391 	}
392 
393 	return status;
394 }
395 
396 /**
397  * Checks if property exists on object
398  */
zephir_isset_property_quick(zval * object,const char * property_name,unsigned int property_length,unsigned long hash TSRMLS_DC)399 int zephir_isset_property_quick(zval *object, const char *property_name, unsigned int property_length, unsigned long hash TSRMLS_DC) {
400 
401 	if (Z_TYPE_P(object) == IS_OBJECT) {
402 		if (EXPECTED(zend_hash_quick_exists(&Z_OBJCE_P(object)->properties_info, property_name, property_length, hash))) {
403 			return 1;
404 		} else {
405 			return zend_hash_quick_exists(Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), property_name, property_length, hash);
406 		}
407 	}
408 
409 	return 0;
410 }
411 
412 /**
413  * Checks if property exists on object
414  */
zephir_isset_property(zval * object,const char * property_name,unsigned int property_length TSRMLS_DC)415 int zephir_isset_property(zval *object, const char *property_name, unsigned int property_length TSRMLS_DC) {
416 
417 	return zephir_isset_property_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length) TSRMLS_CC);
418 }
419 
420 /**
421  * Checks if string property exists on object
422  */
zephir_isset_property_zval(zval * object,const zval * property TSRMLS_DC)423 int zephir_isset_property_zval(zval *object, const zval *property TSRMLS_DC) {
424 
425 	unsigned long hash;
426 
427 	if (Z_TYPE_P(object) == IS_OBJECT) {
428 		if (Z_TYPE_P(property) == IS_STRING) {
429 
430 			hash = zend_inline_hash_func(Z_STRVAL_P(property), Z_STRLEN_P(property) + 1);
431 
432 			if (EXPECTED(zend_hash_quick_exists(&Z_OBJCE_P(object)->properties_info, Z_STRVAL_P(property), Z_STRLEN_P(property) + 1, hash))) {
433 				return 1;
434 			} else {
435 				return zend_hash_quick_exists(Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), Z_STRVAL_P(property), Z_STRLEN_P(property) + 1, hash);
436 			}
437 		}
438 	}
439 
440 	return 0;
441 }
442 
443 /*
444  * Lookup exact class where a property is defined (precomputed key)
445  *
446  */
zephir_lookup_class_ce_quick(zend_class_entry * ce,const char * property_name,zend_uint property_length,ulong hash TSRMLS_DC)447 static inline zend_class_entry *zephir_lookup_class_ce_quick(zend_class_entry *ce, const char *property_name, zend_uint property_length, ulong hash TSRMLS_DC) {
448 
449 	zend_class_entry *original_ce = ce;
450 
451 	while (ce) {
452 		if (zend_hash_quick_exists(&ce->properties_info, property_name, property_length + 1, hash)) {
453 			return ce;
454 		}
455 		ce = ce->parent;
456 	}
457 	return original_ce;
458 }
459 
460 /**
461  * Lookup exact class where a property is defined
462  *
463  */
zephir_lookup_class_ce(zend_class_entry * ce,const char * property_name,unsigned int property_length TSRMLS_DC)464 static inline zend_class_entry *zephir_lookup_class_ce(zend_class_entry *ce, const char *property_name, unsigned int property_length TSRMLS_DC) {
465 
466 	return zephir_lookup_class_ce_quick(ce, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1) TSRMLS_CC);
467 }
468 
469 /**
470  * Reads a property from an object
471  */
zephir_read_property(zval ** result,zval * object,const char * property_name,zend_uint property_length,int silent TSRMLS_DC)472 int zephir_read_property(zval **result, zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC) {
473 
474 	zval *property;
475 	zend_class_entry *ce, *old_scope;
476 
477 	if (Z_TYPE_P(object) != IS_OBJECT) {
478 
479 		if (silent == PH_NOISY) {
480 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property \"%s\" of non-object", property_name);
481 		}
482 
483 		ALLOC_INIT_ZVAL(*result);
484 		ZVAL_NULL(*result);
485 		return FAILURE;
486 	}
487 
488 	ce = Z_OBJCE_P(object);
489 	if (ce->parent) {
490 		ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC);
491 	}
492 
493 	old_scope = EG(scope);
494 	EG(scope) = ce;
495 
496 	if (!Z_OBJ_HT_P(object)->read_property) {
497 		const char *class_name;
498 		zend_uint class_name_len;
499 
500 		zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
501 		zend_error(E_CORE_ERROR, "Property %s of class %s cannot be read", property_name, class_name);
502 	}
503 
504 	MAKE_STD_ZVAL(property);
505 	ZVAL_STRINGL(property, property_name, property_length, 0);
506 
507 	*result = Z_OBJ_HT_P(object)->read_property(object, property, silent ? BP_VAR_IS : BP_VAR_R, 0 TSRMLS_CC);
508 
509 	Z_ADDREF_PP(result);
510 
511 	if (Z_REFCOUNT_P(property) > 1) {
512 		ZVAL_STRINGL(property, property_name, property_length, 1);
513 	} else {
514 		ZVAL_NULL(property);
515 	}
516 
517 	zval_ptr_dtor(&property);
518 
519 	EG(scope) = old_scope;
520 	return SUCCESS;
521 }
522 
zephir_fetch_property_this_quick(zval * object,const char * property_name,zend_uint property_length,ulong key,int silent TSRMLS_DC)523 zval* zephir_fetch_property_this_quick(zval *object, const char *property_name, zend_uint property_length, ulong key, int silent TSRMLS_DC) {
524 
525 	zval **zv = NULL;
526 	zend_object *zobj;
527 	zend_property_info *property_info;
528 	zend_class_entry *ce, *old_scope;
529 
530 	if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) {
531 
532 		ce = Z_OBJCE_P(object);
533 		if (ce->parent) {
534 			ce = zephir_lookup_class_ce_quick(ce, property_name, property_length, key TSRMLS_CC);
535 		}
536 
537 		old_scope = EG(scope);
538 		EG(scope) = ce;
539 
540 		zobj = zend_objects_get_address(object TSRMLS_CC);
541 
542 		if (zend_hash_quick_find(&ce->properties_info, property_name, property_length + 1, key, (void **) &property_info) == SUCCESS) {
543 			int flag;
544 			if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && property_info->offset >= 0) {
545 				if (zobj->properties) {
546 					zv   = (zval**) zobj->properties_table[property_info->offset];
547 					flag = (zv == NULL) ? 1 : 0;
548 				} else {
549 					zv   = &zobj->properties_table[property_info->offset];
550 					flag = (*zv == NULL) ? 1 : 0;
551 				}
552 			} else if (UNEXPECTED(!zobj->properties)) {
553 				flag = 1;
554 			} else if (UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE)) {
555 				flag = 2;
556 			} else {
557 				flag = 0;
558 			}
559 
560 			if (UNEXPECTED(flag) && zobj->properties) {
561 				if (
562 					(flag == 2 || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE)
563 					&& zv && *zv
564 				) {
565 					flag = 0;
566 				}
567 			}
568 
569 			if (EXPECTED(!flag)) {
570 				EG(scope) = old_scope;
571 				return *zv;
572 			}
573 		}
574 
575 		EG(scope) = old_scope;
576 
577 	} else {
578 		if (silent == PH_NOISY) {
579 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property \"%s\" of non-object", property_name);
580 		}
581 	}
582 
583 	return NULL;
584 }
585 
586 /**
587  * Returns an object's member
588  */
zephir_return_property_quick(zval * return_value,zval ** return_value_ptr,zval * object,char * property_name,unsigned int property_length,unsigned long key TSRMLS_DC)589 int zephir_return_property_quick(zval *return_value, zval **return_value_ptr, zval *object, char *property_name, unsigned int property_length, unsigned long key TSRMLS_DC) {
590 
591 	zval **zv;
592 	zend_object *zobj;
593 	zend_property_info *property_info;
594 	zend_class_entry *ce, *old_scope;
595 
596 	if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) {
597 
598 		ce = Z_OBJCE_P(object);
599 		if (ce->parent) {
600 			ce = zephir_lookup_class_ce_quick(ce, property_name, property_length, key TSRMLS_CC);
601 		}
602 
603 		old_scope = EG(scope);
604 		EG(scope) = ce;
605 
606 		zobj = zend_objects_get_address(object TSRMLS_CC);
607 
608 		if (zend_hash_quick_find(&ce->properties_info, property_name, property_length + 1, key, (void **) &property_info) == SUCCESS) {
609 			int flag;
610 			if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && property_info->offset >= 0) {
611 				if (zobj->properties) {
612 					zv   = (zval**) zobj->properties_table[property_info->offset];
613 					flag = (zv == NULL) ? 1 : 0;
614 				} else {
615 					zv   = &zobj->properties_table[property_info->offset];
616 					flag = (*zv == NULL) ? 1 : 0;
617 				}
618 			} else if (UNEXPECTED(!zobj->properties)) {
619 				flag = 1;
620 			} else if (UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE)) {
621 				flag = 2;
622 			} else {
623 				flag = 0;
624 			}
625 
626 			if (UNEXPECTED(flag) && zobj->properties) {
627 				if (
628 					(flag == 2 || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE)
629 					&& zv && *zv
630 				) {
631 					flag = 0;
632 				}
633 			}
634 
635 			if (EXPECTED(!flag)) {
636 				EG(scope) = old_scope;
637 
638 				if (return_value_ptr) {
639 					zval_ptr_dtor(return_value_ptr);
640 					Z_ADDREF_PP(zv);
641 					*return_value_ptr = *zv;
642 				}
643 				else {
644 					ZVAL_ZVAL(return_value, *zv, 1, 0);
645 				}
646 
647 				return SUCCESS;
648 			}
649 		}
650 
651 		EG(scope) = old_scope;
652 
653 	} else {
654 		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property \"%s\" of non-object", property_name);
655 	}
656 
657 	ZVAL_NULL(return_value);
658 	return FAILURE;
659 }
660 
661 /**
662  * Returns an object's member
663  */
zephir_return_property(zval * return_value,zval ** return_value_ptr,zval * object,char * property_name,unsigned int property_length TSRMLS_DC)664 int zephir_return_property(zval *return_value, zval **return_value_ptr, zval *object, char *property_name, unsigned int property_length TSRMLS_DC) {
665 
666 	return zephir_return_property_quick(return_value, return_value_ptr, object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1) TSRMLS_CC);
667 }
668 
669 /**
670  * Reads a property from an object
671  */
zephir_read_property_zval(zval ** result,zval * object,zval * property,int flags TSRMLS_DC)672 int zephir_read_property_zval(zval **result, zval *object, zval *property, int flags TSRMLS_DC) {
673 
674 	if (UNEXPECTED(Z_TYPE_P(property) != IS_STRING)) {
675 
676 		if ((flags & PH_NOISY) == PH_NOISY) {
677 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot access empty property %d", Z_TYPE_P(property));
678 		}
679 
680 		*result = ZEPHIR_GLOBAL(global_null);
681 		Z_ADDREF_P(*result);
682 		return FAILURE;
683 	}
684 
685 	return zephir_read_property(result, object, Z_STRVAL_P(property), Z_STRLEN_P(property), flags TSRMLS_CC);
686 }
687 
688 /**
689  * Checks whether obj is an object and updates property with long value
690  */
zephir_update_property_long(zval * object,char * property_name,unsigned int property_length,long value TSRMLS_DC)691 int zephir_update_property_long(zval *object, char *property_name, unsigned int property_length, long value TSRMLS_DC) {
692 
693 	zval *v;
694 
695 	ALLOC_ZVAL(v);
696 	Z_UNSET_ISREF_P(v);
697 	Z_SET_REFCOUNT_P(v, 0);
698 	ZVAL_LONG(v, value);
699 
700 	return zephir_update_property_zval(object, property_name, property_length, v TSRMLS_CC);
701 }
702 
703 /**
704  * Checks whether obj is an object and updates property with string value
705  */
zephir_update_property_string(zval * object,char * property_name,unsigned int property_length,char * str,unsigned int str_length TSRMLS_DC)706 int zephir_update_property_string(zval *object, char *property_name, unsigned int property_length, char *str, unsigned int str_length TSRMLS_DC) {
707 
708 	zval *value;
709 	int res;
710 
711 	ALLOC_ZVAL(value);
712 	Z_UNSET_ISREF_P(value);
713 	Z_SET_REFCOUNT_P(value, 0);
714 	ZVAL_STRINGL(value, str, str_length, 1);
715 
716 	res = zephir_update_property_zval(object, property_name, property_length, value TSRMLS_CC);
717 	if (res == SUCCESS) {
718 		return SUCCESS;
719 	}
720 
721 	return FAILURE;
722 }
723 
724 /**
725  * Checks whether obj is an object and updates property with bool value
726  */
zephir_update_property_bool(zval * object,char * property_name,unsigned int property_length,int value TSRMLS_DC)727 int zephir_update_property_bool(zval *object, char *property_name, unsigned int property_length, int value TSRMLS_DC) {
728 	return zephir_update_property_zval(object, property_name, property_length, value ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);
729 }
730 
731 /**
732  * Checks whether obj is an object and updates property with null value
733  */
zephir_update_property_null(zval * object,char * property_name,unsigned int property_length TSRMLS_DC)734 int zephir_update_property_null(zval *object, char *property_name, unsigned int property_length TSRMLS_DC) {
735 	return zephir_update_property_zval(object, property_name, property_length, ZEPHIR_GLOBAL(global_null) TSRMLS_CC);
736 }
737 
738 /**
739  * Checks whether obj is an object and updates property with another zval
740  */
zephir_update_property_zval(zval * object,const char * property_name,unsigned int property_length,zval * value TSRMLS_DC)741 int zephir_update_property_zval(zval *object, const char *property_name, unsigned int property_length, zval *value TSRMLS_DC){
742 
743 	zend_class_entry *ce, *old_scope;
744 	zval *property;
745 
746 	old_scope = EG(scope);
747 	if (Z_TYPE_P(object) != IS_OBJECT) {
748 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object");
749 		return FAILURE;
750 	}
751 
752 	ce = Z_OBJCE_P(object);
753 	if (ce->parent) {
754 		ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC);
755 	}
756 
757 	EG(scope) = ce;
758 
759 	if (!Z_OBJ_HT_P(object)->write_property) {
760 		const char *class_name;
761 		zend_uint class_name_len;
762 
763 		zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
764 		zend_error(E_CORE_ERROR, "Property %s of class %s cannot be updated", property_name, class_name);
765 	}
766 
767 	MAKE_STD_ZVAL(property);
768 	ZVAL_STRINGL(property, property_name, property_length, 0);
769 
770 	Z_OBJ_HT_P(object)->write_property(object, property, value, 0 TSRMLS_CC);
771 
772 	if (Z_REFCOUNT_P(property) > 1) {
773 		ZVAL_STRINGL(property, property_name, property_length, 1);
774 	} else {
775 		ZVAL_NULL(property);
776 	}
777 
778 	zval_ptr_dtor(&property);
779 
780 	EG(scope) = old_scope;
781 	return SUCCESS;
782 }
783 
784 /**
785  * Updates properties on this_ptr (quick)
786  * If a variable is not defined in the class definition, this fallbacks to update_property_zval
787  * function ignores magic methods or dynamic properties
788  */
zephir_update_property_this_quick(zval * object,const char * property_name,zend_uint property_length,zval * value,ulong key TSRMLS_DC)789 int zephir_update_property_this_quick(zval *object, const char *property_name, zend_uint property_length, zval *value, ulong key TSRMLS_DC){
790 
791 	zend_class_entry *ce, *old_scope;
792 
793 	if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
794 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object");
795 		return FAILURE;
796 	}
797 
798 	ce = Z_OBJCE_P(object);
799 	if (ce->parent) {
800 		ce = zephir_lookup_class_ce_quick(ce, property_name, property_length, key TSRMLS_CC);
801 	}
802 
803 	old_scope = EG(scope);
804 	EG(scope) = ce;
805 
806 	{
807 		zend_object *zobj;
808 		zval **variable_ptr;
809 		zend_property_info *property_info;
810 
811 		zobj = zend_objects_get_address(object TSRMLS_CC);
812 
813 		if (EXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_length + 1, key, (void **) &property_info) == SUCCESS)) {
814 			assert(property_info != NULL);
815 
816 			/** This is as zend_std_write_property, but we're not interesed in validate properties visibility */
817 			if (property_info->offset >= 0 ? (zobj->properties ? ((variable_ptr = (zval**) zobj->properties_table[property_info->offset]) != NULL) : (*(variable_ptr = &zobj->properties_table[property_info->offset]) != NULL)) : (EXPECTED(zobj->properties != NULL) && EXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length + 1, property_info->h, (void **) &variable_ptr) == SUCCESS))) {
818 
819 				if (EXPECTED(*variable_ptr != value)) {
820 
821 					/* if we are assigning reference, we shouldn't move it, but instead assign variable to the same pointer */
822 					if (PZVAL_IS_REF(*variable_ptr)) {
823 
824 						zval garbage = **variable_ptr; /* old value should be destroyed */
825 
826 						/* To check: can't *variable_ptr be some system variable like error_zval here? */
827 						Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value);
828 						(*variable_ptr)->value = value->value;
829 						if (Z_REFCOUNT_P(value) > 0) {
830 							zval_copy_ctor(*variable_ptr);
831 						} else {
832 							efree(value);
833 						}
834 						zval_dtor(&garbage);
835 
836 					} else {
837 						zval *garbage = *variable_ptr;
838 
839 						/* if we assign referenced variable, we should separate it */
840 						Z_ADDREF_P(value);
841 						if (PZVAL_IS_REF(value)) {
842 							SEPARATE_ZVAL(&value);
843 						}
844 						*variable_ptr = value;
845 						zval_ptr_dtor(&garbage);
846 					}
847 				}
848 
849 			}
850 		} else {
851 			EG(scope) = old_scope;
852 			return zephir_update_property_zval(object, property_name, property_length, value TSRMLS_CC);
853 		}
854 	}
855 
856 	EG(scope) = old_scope;
857 
858 	return SUCCESS;
859 }
860 
861 /**
862  * Updates properties on this_ptr
863  * Variables must be defined in the class definition. This function ignores magic methods or dynamic properties
864  */
zephir_update_property_this(zval * object,char * property_name,unsigned int property_length,zval * value TSRMLS_DC)865 int zephir_update_property_this(zval *object, char *property_name, unsigned int property_length, zval *value TSRMLS_DC) {
866 
867 	return zephir_update_property_this_quick(object, property_name, property_length, value, zend_inline_hash_func(property_name, property_length + 1) TSRMLS_CC);
868 }
869 
870 /**
871  * Checks whether obj is an object and updates zval property with another zval
872  */
zephir_update_property_zval_zval(zval * object,zval * property,zval * value TSRMLS_DC)873 int zephir_update_property_zval_zval(zval *object, zval *property, zval *value TSRMLS_DC) {
874 
875 	if (Z_TYPE_P(property) != IS_STRING) {
876 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Property should be string");
877 		return FAILURE;
878 	}
879 
880 	return zephir_update_property_zval(object, Z_STRVAL_P(property), Z_STRLEN_P(property), value TSRMLS_CC);
881 }
882 
883 /**
884  * Updates an array property
885  */
zephir_update_property_array(zval * object,const char * property,zend_uint property_length,const zval * index,zval * value TSRMLS_DC)886 int zephir_update_property_array(zval *object, const char *property, zend_uint property_length, const zval *index, zval *value TSRMLS_DC) {
887 
888 	zval *tmp;
889 	int separated = 0;
890 
891 	if (Z_TYPE_P(object) == IS_OBJECT) {
892 
893 		zephir_read_property(&tmp, object, property, property_length, PH_NOISY TSRMLS_CC);
894 
895 		Z_DELREF_P(tmp);
896 
897 		/** Separation only when refcount > 1 */
898 		if (Z_REFCOUNT_P(tmp) > 1) {
899 			if (!Z_ISREF_P(tmp)) {
900 				zval *new_zv;
901 				ALLOC_ZVAL(new_zv);
902 				INIT_PZVAL_COPY(new_zv, tmp);
903 				tmp = new_zv;
904 				zval_copy_ctor(new_zv);
905 				Z_SET_REFCOUNT_P(tmp, 0);
906 				Z_UNSET_ISREF_P(tmp);
907 				separated = 1;
908 			}
909 		}
910 
911 		/** Convert the value to array if not is an array */
912 		if (Z_TYPE_P(tmp) != IS_ARRAY) {
913 			if (separated) {
914 				convert_to_array(tmp);
915 			} else {
916 				zval *new_zv;
917 				ALLOC_ZVAL(new_zv);
918 				INIT_PZVAL_COPY(new_zv, tmp);
919 				tmp = new_zv;
920 				zval_copy_ctor(new_zv);
921 				Z_SET_REFCOUNT_P(tmp, 0);
922 				Z_UNSET_ISREF_P(tmp);
923 				array_init(tmp);
924 				separated = 1;
925 			}
926 		}
927 
928 		Z_ADDREF_P(value);
929 
930 		if (Z_TYPE_P(index) == IS_STRING) {
931 			zend_symtable_update(Z_ARRVAL_P(tmp), Z_STRVAL_P(index), Z_STRLEN_P(index) + 1, &value, sizeof(zval*), NULL);
932 		} else if (Z_TYPE_P(index) == IS_LONG) {
933 			zend_hash_index_update(Z_ARRVAL_P(tmp), Z_LVAL_P(index), &value, sizeof(zval *), NULL);
934 		} else if (Z_TYPE_P(index) == IS_NULL) {
935 			zend_hash_next_index_insert(Z_ARRVAL_P(tmp), (void**)&value, sizeof(zval*), NULL);
936 		}
937 
938 		if (separated) {
939 			zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC);
940 		}
941 	}
942 
943 	return SUCCESS;
944 }
945 
946 /**
947  * Multiple array-offset update
948  */
zephir_update_property_array_multi(zval * object,const char * property,zend_uint property_length,zval ** value TSRMLS_DC,const char * types,int types_length,int types_count,...)949 int zephir_update_property_array_multi(zval *object, const char *property, zend_uint property_length, zval **value TSRMLS_DC, const char *types, int types_length, int types_count, ...) {
950 	va_list ap;
951 	zval *tmp_arr;
952 	int separated = 0;
953 
954 	if (Z_TYPE_P(object) == IS_OBJECT) {
955 
956 		zephir_read_property(&tmp_arr, object, property, property_length, PH_NOISY TSRMLS_CC);
957 
958 		Z_DELREF_P(tmp_arr);
959 
960 		/** Separation only when refcount > 1 */
961 		if (Z_REFCOUNT_P(tmp_arr) > 1) {
962 			if (!Z_ISREF_P(tmp_arr)) {
963 				zval *new_zv;
964 				ALLOC_ZVAL(new_zv);
965 				INIT_PZVAL_COPY(new_zv, tmp_arr);
966 				tmp_arr = new_zv;
967 				zval_copy_ctor(new_zv);
968 				Z_SET_REFCOUNT_P(tmp_arr, 0);
969 				Z_UNSET_ISREF_P(tmp_arr);
970 				separated = 1;
971 			}
972 		}
973 
974 		/** Convert the value to array if not is an array */
975 		if (Z_TYPE_P(tmp_arr) != IS_ARRAY) {
976 			if (separated) {
977 				convert_to_array(tmp_arr);
978 			} else {
979 				zval *new_zv;
980 				ALLOC_ZVAL(new_zv);
981 				INIT_PZVAL_COPY(new_zv, tmp_arr);
982 				tmp_arr = new_zv;
983 				zval_copy_ctor(new_zv);
984 				Z_SET_REFCOUNT_P(tmp_arr, 0);
985 				Z_UNSET_ISREF_P(tmp_arr);
986 				array_init(tmp_arr);
987 				separated = 1;
988 			}
989 		}
990 
991 		va_start(ap, types_count);
992 		zephir_array_update_multi_ex(&tmp_arr, value, types, types_length, types_count, ap TSRMLS_CC);
993 		va_end(ap);
994 
995 		if (separated) {
996 			zephir_update_property_zval(object, property, property_length, tmp_arr TSRMLS_CC);
997 		}
998 	}
999 
1000 	return SUCCESS;
1001 }
1002 
1003 /**
1004  * Updates an array property using a string index
1005  */
zephir_update_property_array_string(zval * object,char * property,unsigned int property_length,char * index,unsigned int index_length,zval * value TSRMLS_DC)1006 int zephir_update_property_array_string(zval *object, char *property, unsigned int property_length, char *index, unsigned int index_length, zval *value TSRMLS_DC) {
1007 
1008 	zval *tmp;
1009 	int separated = 0;
1010 
1011 	if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) {
1012 
1013 		zephir_read_property(&tmp, object, property, property_length, PH_NOISY_CC);
1014 
1015 		Z_DELREF_P(tmp);
1016 
1017 		/** Separation only when refcount > 1 */
1018 		if (Z_REFCOUNT_P(tmp) > 1) {
1019 			if (!Z_ISREF_P(tmp)) {
1020 				zval *new_zv;
1021 				ALLOC_ZVAL(new_zv);
1022 				INIT_PZVAL_COPY(new_zv, tmp);
1023 				tmp = new_zv;
1024 				zval_copy_ctor(new_zv);
1025 				Z_SET_REFCOUNT_P(tmp, 0);
1026 				Z_UNSET_ISREF_P(tmp);
1027 				separated = 1;
1028 			}
1029 		}
1030 
1031 		/** Convert the value to array if not is an array */
1032 		if (Z_TYPE_P(tmp) != IS_ARRAY) {
1033 			if (separated) {
1034 				convert_to_array(tmp);
1035 			} else {
1036 				zval *new_zv;
1037 				ALLOC_ZVAL(new_zv);
1038 				INIT_PZVAL_COPY(new_zv, tmp);
1039 				tmp = new_zv;
1040 				zval_copy_ctor(new_zv);
1041 				Z_SET_REFCOUNT_P(tmp, 0);
1042 				Z_UNSET_ISREF_P(tmp);
1043 				array_init(tmp);
1044 				separated = 1;
1045 			}
1046 		}
1047 
1048 		Z_ADDREF_P(value);
1049 
1050 		zend_hash_update(Z_ARRVAL_P(tmp), index, index_length, &value, sizeof(zval *), NULL);
1051 
1052 		if (separated) {
1053 			zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC);
1054 		}
1055 
1056 	}
1057 
1058 	return SUCCESS;
1059 }
1060 
1061 /**
1062  * Appends a zval value to an array property
1063  */
zephir_update_property_array_append(zval * object,char * property,unsigned int property_length,zval * value TSRMLS_DC)1064 int zephir_update_property_array_append(zval *object, char *property, unsigned int property_length, zval *value TSRMLS_DC) {
1065 
1066 	zval *tmp;
1067 	int separated = 0;
1068 
1069 	if (Z_TYPE_P(object) != IS_OBJECT) {
1070 		return SUCCESS;
1071 	}
1072 
1073 	zephir_read_property(&tmp, object, property, property_length, PH_NOISY_CC);
1074 
1075 	Z_DELREF_P(tmp);
1076 
1077 	/** Separation only when refcount > 1 */
1078 	if (Z_REFCOUNT_P(tmp) > 1) {
1079 		if (!Z_ISREF_P(tmp)) {
1080 			zval *new_zv;
1081 			ALLOC_ZVAL(new_zv);
1082 			INIT_PZVAL_COPY(new_zv, tmp);
1083 			tmp = new_zv;
1084 			zval_copy_ctor(new_zv);
1085 			Z_SET_REFCOUNT_P(tmp, 0);
1086 			Z_UNSET_ISREF_P(tmp);
1087 			separated = 1;
1088 		}
1089 	}
1090 
1091 	/** Convert the value to array if not is an array */
1092 	if (Z_TYPE_P(tmp) != IS_ARRAY) {
1093 		if (separated) {
1094 			convert_to_array(tmp);
1095 		} else {
1096 			zval *new_zv;
1097 			ALLOC_ZVAL(new_zv);
1098 			INIT_PZVAL_COPY(new_zv, tmp);
1099 			tmp = new_zv;
1100 			zval_copy_ctor(new_zv);
1101 			Z_SET_REFCOUNT_P(tmp, 0);
1102 			Z_UNSET_ISREF_P(tmp);
1103 			array_init(tmp);
1104 			separated = 1;
1105 		}
1106 	}
1107 
1108 	Z_ADDREF_P(value);
1109 	add_next_index_zval(tmp, value);
1110 
1111 	if (separated) {
1112 		zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC);
1113 	}
1114 
1115 	return SUCCESS;
1116 }
1117 
1118 /**
1119  * Intializes an object property with an empty array
1120  */
zephir_update_property_empty_array(zend_class_entry * ce,zval * object,char * property_name,unsigned int property_length TSRMLS_DC)1121 int zephir_update_property_empty_array(zend_class_entry *ce, zval *object, char *property_name, unsigned int property_length TSRMLS_DC) {
1122 
1123 	zval *empty_array;
1124 	int res;
1125 
1126 	ALLOC_INIT_ZVAL(empty_array);
1127 	array_init(empty_array);
1128 
1129 	res = zephir_update_property_zval(object, property_name, property_length, empty_array TSRMLS_CC);
1130 	zval_ptr_dtor(&empty_array);
1131 	return res;
1132 }
1133 
zephir_unset_property(zval * object,const char * name TSRMLS_DC)1134 int zephir_unset_property(zval* object, const char* name TSRMLS_DC)
1135 {
1136 	if (Z_TYPE_P(object) == IS_OBJECT) {
1137 		zval member;
1138 		zend_class_entry *old_scope;
1139 
1140 		INIT_PZVAL(&member);
1141 		ZVAL_STRING(&member, name, 0);
1142 		old_scope = EG(scope);
1143 		EG(scope) = Z_OBJCE_P(object);
1144 
1145 		Z_OBJ_HT_P(object)->unset_property(object, &member, 0 TSRMLS_CC);
1146 
1147 		EG(scope) = old_scope;
1148 
1149 		return SUCCESS;
1150 	}
1151 
1152 	return FAILURE;
1153 }
1154 
1155 /**
1156  * Unsets an index in an array property
1157  */
zephir_unset_property_array(zval * object,char * property,unsigned int property_length,zval * index TSRMLS_DC)1158 int zephir_unset_property_array(zval *object, char *property, unsigned int property_length, zval *index TSRMLS_DC) {
1159 
1160 	zval *tmp;
1161 	int separated = 0;
1162 
1163 	if (Z_TYPE_P(object) == IS_OBJECT) {
1164 
1165 		zephir_read_property(&tmp, object, property, property_length, PH_NOISY_CC);
1166 		Z_DELREF_P(tmp);
1167 
1168 		/** Separation only when refcount > 1 */
1169 		if (Z_REFCOUNT_P(tmp) > 1) {
1170 			if (!Z_ISREF_P(tmp)) {
1171 				zval *new_zv;
1172 				ALLOC_ZVAL(new_zv);
1173 				INIT_PZVAL_COPY(new_zv, tmp);
1174 				tmp = new_zv;
1175 				zval_copy_ctor(new_zv);
1176 				Z_SET_REFCOUNT_P(tmp, 0);
1177 				Z_UNSET_ISREF_P(tmp);
1178 				separated = 1;
1179 			}
1180 		}
1181 
1182 		zephir_array_unset(&tmp, index, PH_SEPARATE);
1183 
1184 		if (separated) {
1185 			zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC);
1186 		}
1187 	}
1188 
1189 	return SUCCESS;
1190 }
1191 
1192 /**
1193  * Check if a method is implemented on certain object
1194  */
zephir_method_exists(const zval * object,const zval * method_name TSRMLS_DC)1195 int zephir_method_exists(const zval *object, const zval *method_name TSRMLS_DC){
1196 
1197 	char *lcname = zend_str_tolower_dup(Z_STRVAL_P(method_name), Z_STRLEN_P(method_name));
1198 	int res = zephir_method_exists_ex(object, lcname, Z_STRLEN_P(method_name) + 1 TSRMLS_CC);
1199 	efree(lcname);
1200 	return res;
1201 }
1202 
1203 /**
1204  * Check if method exists on certain object using explicit char param
1205  *
1206  * @param object
1207  * @param method_name
1208  * @param method_length strlen(method_name)+1
1209  */
zephir_method_exists_ex(const zval * object,const char * method_name,unsigned int method_len TSRMLS_DC)1210 int zephir_method_exists_ex(const zval *object, const char *method_name, unsigned int method_len TSRMLS_DC){
1211 
1212 	return zephir_method_quick_exists_ex(object, method_name, method_len, zend_inline_hash_func(method_name, method_len) TSRMLS_CC);
1213 }
1214 
1215 /**
1216  * Check if method exists on certain object using explicit char param
1217  */
zephir_method_quick_exists_ex(const zval * object,const char * method_name,unsigned int method_len,unsigned long hash TSRMLS_DC)1218 int zephir_method_quick_exists_ex(const zval *object, const char *method_name, unsigned int method_len, unsigned long hash TSRMLS_DC){
1219 
1220 	zend_class_entry *ce;
1221 
1222 	if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) {
1223 		ce = Z_OBJCE_P(object);
1224 	} else {
1225 		if (Z_TYPE_P(object) == IS_STRING) {
1226 			ce = zend_fetch_class(Z_STRVAL_P(object), Z_STRLEN_P(object), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
1227 		} else {
1228 			return FAILURE;
1229 		}
1230 	}
1231 
1232 	while (ce) {
1233 		if (zend_hash_quick_exists(&ce->function_table, method_name, method_len, hash)) {
1234 			return SUCCESS;
1235 		}
1236 		ce = ce->parent;
1237 	}
1238 
1239 	return FAILURE;
1240 }
1241 
zephir_fetch_static_property_ce(zend_class_entry * ce,const char * property,int len TSRMLS_DC)1242 zval* zephir_fetch_static_property_ce(zend_class_entry *ce, const char *property, int len TSRMLS_DC) {
1243 	assert(ce != NULL);
1244 	return zend_read_static_property(ce, property, len, (zend_bool) ZEND_FETCH_CLASS_SILENT TSRMLS_CC);
1245 }
1246 
zephir_read_static_property_ce(zval ** result,zend_class_entry * ce,const char * property,int len TSRMLS_DC)1247 int zephir_read_static_property_ce(zval **result, zend_class_entry *ce, const char *property, int len TSRMLS_DC) {
1248 	zval *tmp;
1249 	tmp = zephir_fetch_static_property_ce(ce, property, len TSRMLS_CC);
1250 	if (tmp) {
1251 		if (!Z_ISREF_P(tmp)) {
1252 			*result = tmp;
1253 			Z_ADDREF_PP(result);
1254 		} else {
1255 			ALLOC_INIT_ZVAL(*result);
1256 			ZVAL_ZVAL(*result, tmp, 1, 0);
1257 		}
1258 		return SUCCESS;
1259 	}
1260 	ALLOC_INIT_ZVAL(*result);
1261 	return FAILURE;
1262 }
1263 
zephir_std_get_static_property(zend_class_entry * ce,const char * property_name,int property_name_len,ulong hash_value,zend_bool silent,zend_property_info ** property_info TSRMLS_DC)1264 static zval **zephir_std_get_static_property(zend_class_entry *ce, const char *property_name, int property_name_len, ulong hash_value, zend_bool silent, zend_property_info **
1265 	property_info TSRMLS_DC)
1266 {
1267 	zend_property_info *temp_property_info;
1268 
1269 	if (!hash_value) {
1270 		hash_value = zend_hash_func(property_name, property_name_len + 1);
1271 	}
1272 
1273 	if (!property_info || !*property_info) {
1274 
1275 		if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len + 1, hash_value, (void **) &temp_property_info)==FAILURE)) {
1276 			if (!silent) {
1277 				zend_error(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
1278 			}
1279 			return NULL;
1280 		}
1281 
1282 		#ifndef ZEPHIR_RELEASE
1283 		/*if (UNEXPECTED(!zend_verify_property_access(temp_property_info, ce TSRMLS_CC))) {
1284 			if (!silent) {
1285 				zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(temp_property_info->flags), ce->name, property_name);
1286 			}
1287 			return NULL;
1288 		}
1289 
1290 		if (UNEXPECTED((temp_property_info->flags & ZEND_ACC_STATIC) == 0)) {
1291 			if (!silent) {
1292 				zend_error(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
1293 			}
1294 			return NULL;
1295 		}*/
1296 		#endif
1297 
1298 		zend_update_class_constants(ce TSRMLS_CC);
1299 
1300 		if (property_info) {
1301 			*property_info = temp_property_info;
1302 		}
1303 
1304 	} else {
1305 		temp_property_info = *property_info;
1306 	}
1307 
1308 	if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL) || UNEXPECTED(CE_STATIC_MEMBERS(ce)[temp_property_info->offset] == NULL)) {
1309 		if (!silent) {
1310 			zend_error(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
1311 		}
1312 		return NULL;
1313 	}
1314 
1315 	return &CE_STATIC_MEMBERS(ce)[temp_property_info->offset];
1316 }
1317 
zephir_update_static_property_ex(zend_class_entry * scope,const char * name,int name_length,zval ** value,zend_property_info ** property_info TSRMLS_DC)1318 static int zephir_update_static_property_ex(zend_class_entry *scope, const char *name, int name_length, zval **value, zend_property_info **property_info TSRMLS_DC)
1319 {
1320 	zval **property; zval *tmp, **safe_value;
1321 	zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL;
1322 	zend_class_entry *old_scope = EG(scope);
1323 
1324 	/**
1325 	 * We have to protect super globals to avoid them make converted to references
1326 	 */
1327 	if (*value == zephir_globals_ptr->global_null) {
1328 		ALLOC_ZVAL(tmp);
1329 		Z_UNSET_ISREF_P(tmp);
1330 		Z_SET_REFCOUNT_P(tmp, 0);
1331 		ZVAL_NULL(tmp);
1332 		safe_value = &tmp;
1333 	} else {
1334 		if (*value == zephir_globals_ptr->global_true) {
1335 			ALLOC_ZVAL(tmp);
1336 			Z_UNSET_ISREF_P(tmp);
1337 			Z_SET_REFCOUNT_P(tmp, 0);
1338 			ZVAL_BOOL(tmp, 1);
1339 			safe_value = &tmp;
1340 		} else {
1341 			if (*value == zephir_globals_ptr->global_false) {
1342 				ALLOC_ZVAL(tmp);
1343 				Z_UNSET_ISREF_P(tmp);
1344 				Z_SET_REFCOUNT_P(tmp, 0);
1345 				ZVAL_BOOL(tmp, 0);
1346 				safe_value = &tmp;
1347 			} else {
1348 				safe_value = value;
1349 			}
1350 		}
1351 	}
1352 
1353 	EG(scope) = scope;
1354 	property = zephir_std_get_static_property(scope, name, name_length, zend_inline_hash_func(name, name_length + 1), 0, property_info TSRMLS_CC);
1355 	EG(scope) = old_scope;
1356 
1357 	if (!property) {
1358 		return FAILURE;
1359 	} else {
1360 		if (*property != *safe_value) {
1361 			if (PZVAL_IS_REF(*property)) {
1362 				zval_dtor(*property);
1363 				Z_TYPE_PP(property) = Z_TYPE_PP(safe_value);
1364 				(*property)->value = (*safe_value)->value;
1365 				if (Z_REFCOUNT_PP(safe_value) > 0) {
1366 					zval_copy_ctor(*property);
1367 				} else {
1368 					efree(*safe_value);
1369 					*safe_value = NULL;
1370 				}
1371 			} else {
1372 				zval *garbage = *property;
1373 
1374 				Z_ADDREF_PP(safe_value);
1375 				if (Z_ISREF_PP(safe_value)) {
1376 					SEPARATE_ZVAL(safe_value);
1377 				}
1378 				*property = *safe_value;
1379 				zval_ptr_dtor(&garbage);
1380 			}
1381 		}
1382 		return SUCCESS;
1383 	}
1384 }
1385 
1386 /**
1387  * Query a static property value from a zend_class_entry
1388  */
zephir_read_static_property(zval ** result,const char * class_name,unsigned int class_length,char * property_name,unsigned int property_length TSRMLS_DC)1389 int zephir_read_static_property(zval **result, const char *class_name, unsigned int class_length, char *property_name,
1390 	unsigned int property_length TSRMLS_DC) {
1391 	zend_class_entry **ce;
1392 	if (zend_lookup_class(class_name, class_length, &ce TSRMLS_CC) == SUCCESS) {
1393 		return zephir_read_static_property_ce(result, *ce, property_name, property_length TSRMLS_CC);
1394 	}
1395 	return FAILURE;
1396 }
1397 
zephir_update_static_property_ce(zend_class_entry * ce,const char * name,int len,zval ** value TSRMLS_DC)1398 int zephir_update_static_property_ce(zend_class_entry *ce, const char *name, int len, zval **value TSRMLS_DC) {
1399 	assert(ce != NULL);
1400 	return zephir_update_static_property_ex(ce, name, len, value, NULL TSRMLS_CC);
1401 }
1402 
zephir_update_static_property_ce_cache(zend_class_entry * ce,const char * name,int len,zval ** value,zend_property_info ** property_info TSRMLS_DC)1403 int zephir_update_static_property_ce_cache(zend_class_entry *ce, const char *name, int len, zval **value, zend_property_info **property_info TSRMLS_DC) {
1404 	assert(ce != NULL);
1405 	return zephir_update_static_property_ex(ce, name, len, value, property_info TSRMLS_CC);
1406 }
1407 
1408 /*
1409  * Multiple array-offset update
1410  */
zephir_update_static_property_array_multi_ce(zend_class_entry * ce,const char * property,zend_uint property_length,zval ** value TSRMLS_DC,const char * types,int types_length,int types_count,...)1411 int zephir_update_static_property_array_multi_ce(zend_class_entry *ce, const char *property, zend_uint property_length, zval **value TSRMLS_DC, const char *types, int types_length, int types_count, ...) {
1412 
1413 	va_list ap;
1414 	zval *tmp_arr;
1415 	int separated = 0;
1416 
1417 	tmp_arr = zephir_fetch_static_property_ce(ce, property, property_length TSRMLS_CC);
1418 	if (!tmp_arr) {
1419 		ALLOC_INIT_ZVAL(tmp_arr);
1420 		array_init(tmp_arr);
1421 		separated = 1;
1422 	}
1423 
1424 	/** Separation only when refcount > 1 */
1425 	if (Z_REFCOUNT_P(tmp_arr) > 1) {
1426 		if (!Z_ISREF_P(tmp_arr)) {
1427 			zval *new_zv;
1428 			ALLOC_ZVAL(new_zv);
1429 			INIT_PZVAL_COPY(new_zv, tmp_arr);
1430 			tmp_arr = new_zv;
1431 			zval_copy_ctor(new_zv);
1432 			Z_SET_REFCOUNT_P(tmp_arr, 0);
1433 			Z_UNSET_ISREF_P(tmp_arr);
1434 			separated = 1;
1435 		}
1436 	}
1437 
1438 	/** Convert the value to array if not is an array */
1439 	if (Z_TYPE_P(tmp_arr) != IS_ARRAY) {
1440 		if (separated) {
1441 			convert_to_array(tmp_arr);
1442 		} else {
1443 			zval *new_zv;
1444 			ALLOC_ZVAL(new_zv);
1445 			INIT_PZVAL_COPY(new_zv, tmp_arr);
1446 			tmp_arr = new_zv;
1447 			zval_copy_ctor(new_zv);
1448 			Z_SET_REFCOUNT_P(tmp_arr, 0);
1449 			Z_UNSET_ISREF_P(tmp_arr);
1450 			array_init(tmp_arr);
1451 			separated = 1;
1452 		}
1453 	}
1454 
1455 	va_start(ap, types_count);
1456 	zephir_array_update_multi_ex(&tmp_arr, value, types, types_length, types_count, ap TSRMLS_CC);
1457 	va_end(ap);
1458 
1459 	if (separated) {
1460 		zephir_update_static_property_ce(ce, property, property_length, &tmp_arr TSRMLS_CC);
1461 	}
1462 
1463 	return SUCCESS;
1464 }
1465 
1466 /**
1467  * Update a static property
1468  */
zephir_update_static_property(const char * class_name,unsigned int class_length,char * name,unsigned int name_length,zval ** value TSRMLS_DC)1469 int zephir_update_static_property(const char *class_name, unsigned int class_length, char *name, unsigned int name_length, zval **value TSRMLS_DC){
1470 	zend_class_entry **ce;
1471 	if (zend_lookup_class(class_name, class_length, &ce TSRMLS_CC) == SUCCESS) {
1472 		return zephir_update_static_property_ce(*ce, name, name_length, value TSRMLS_CC);
1473 	}
1474 	return FAILURE;
1475 }
1476 
zephir_read_class_property(zval ** result,int type,const char * property,int len TSRMLS_DC)1477 int zephir_read_class_property(zval **result, int type, const char *property, int len TSRMLS_DC) {
1478 	zend_class_entry *ce;
1479 
1480 	type |= (ZEND_FETCH_CLASS_SILENT | ZEND_FETCH_CLASS_NO_AUTOLOAD);
1481 	type &= ZEND_FETCH_CLASS_MASK;
1482 	ce    = zend_fetch_class(NULL, 0, type TSRMLS_CC);
1483 
1484 	if (EXPECTED(ce != NULL)) {
1485 		return zephir_read_static_property_ce(result, ce, property, len TSRMLS_CC);
1486 	}
1487 
1488 	return FAILURE;
1489 }
1490 
1491 /**
1492  * Creates a new instance dynamically. Call constructor without parameters
1493  */
zephir_create_instance(zval * return_value,const zval * class_name TSRMLS_DC)1494 int zephir_create_instance(zval *return_value, const zval *class_name TSRMLS_DC){
1495 
1496 	zend_class_entry *ce;
1497 
1498 	if (Z_TYPE_P(class_name) != IS_STRING) {
1499 		zephir_throw_exception_string(spl_ce_RuntimeException, SL("Invalid class name") TSRMLS_CC);
1500 		return FAILURE;
1501 	}
1502 
1503 	ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
1504 	if (!ce) {
1505 		ZVAL_NULL(return_value);
1506 		return FAILURE;
1507 	}
1508 
1509 	object_init_ex(return_value, ce);
1510 	if (zephir_has_constructor_ce(ce)) {
1511 		return zephir_call_class_method_aparams(NULL, ce, zephir_fcall_method, return_value, SL("__construct"), NULL, 0, 0, NULL TSRMLS_CC);
1512 	}
1513 
1514 	return SUCCESS;
1515 }
1516 
1517 /**
1518  * Creates a new instance dynamically calling constructor with parameters
1519  */
zephir_create_instance_params(zval * return_value,const zval * class_name,zval * params TSRMLS_DC)1520 int zephir_create_instance_params(zval *return_value, const zval *class_name, zval *params TSRMLS_DC){
1521 
1522 	int outcome;
1523 	zend_class_entry *ce;
1524 
1525 	if (Z_TYPE_P(class_name) != IS_STRING) {
1526 		zephir_throw_exception_string(spl_ce_RuntimeException, SL("Invalid class name") TSRMLS_CC);
1527 		return FAILURE;
1528 	}
1529 
1530 	if (Z_TYPE_P(params) != IS_ARRAY) {
1531 		zephir_throw_exception_string(spl_ce_RuntimeException, SL("Instantiation parameters must be an array") TSRMLS_CC);
1532 		return FAILURE;
1533 	}
1534 
1535 	ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
1536 	if (!ce) {
1537 		ZVAL_NULL(return_value);
1538 		return FAILURE;
1539 	}
1540 
1541 	object_init_ex(return_value, ce);
1542 	outcome = SUCCESS;
1543 
1544 	if (zephir_has_constructor_ce(ce)) {
1545 
1546 		int param_count = zend_hash_num_elements(Z_ARRVAL_P(params));
1547 		zval *static_params[10];
1548 		zval **params_ptr, **params_arr = NULL;
1549 
1550 		if (param_count > 0) {
1551 			HashPosition pos;
1552 			zval **item;
1553 			int i = 0;
1554 
1555 			if (EXPECTED(param_count <= 10)) {
1556 				params_ptr = static_params;
1557 			} else {
1558 				params_arr = emalloc(param_count * sizeof(zval*));
1559 				params_ptr = params_arr;
1560 			}
1561 
1562 			for (
1563 				zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(params), &pos);
1564 				zend_hash_get_current_data_ex(Z_ARRVAL_P(params), (void**) &item, &pos) == SUCCESS;
1565 				zend_hash_move_forward_ex(Z_ARRVAL_P(params), &pos), ++i
1566 			) {
1567 				params_ptr[i] = *item;
1568 			}
1569 		} else {
1570 			params_ptr = NULL;
1571 		}
1572 
1573 		outcome = zephir_call_class_method_aparams(NULL, ce, zephir_fcall_method, return_value, SL("__construct"), NULL, 0, param_count, params_ptr TSRMLS_CC);
1574 
1575 		if (UNEXPECTED(params_arr != NULL)) {
1576 			efree(params_arr);
1577 		}
1578 	}
1579 
1580 	return outcome;
1581 }
1582 
1583 /**
1584  * Increments an object property
1585  */
zephir_property_incr(zval * object,char * property_name,unsigned int property_length TSRMLS_DC)1586 int zephir_property_incr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC){
1587 
1588 	zval *tmp = NULL;
1589 	zend_class_entry *ce;
1590 	int separated = 0;
1591 
1592 	if (Z_TYPE_P(object) != IS_OBJECT) {
1593 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object");
1594 		return FAILURE;
1595 	}
1596 
1597 	ce = Z_OBJCE_P(object);
1598 	if (ce->parent) {
1599 		ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC);
1600 	}
1601 
1602 	zephir_read_property(&tmp, object, property_name, property_length, 0 TSRMLS_CC);
1603 	if (tmp) {
1604 
1605 		Z_DELREF_P(tmp);
1606 
1607 		/** Separation only when refcount > 1 */
1608 		if (Z_REFCOUNT_P(tmp) > 1) {
1609 			if (!Z_ISREF_P(tmp)) {
1610 				zval *new_zv;
1611 				ALLOC_ZVAL(new_zv);
1612 				INIT_PZVAL_COPY(new_zv, tmp);
1613 				tmp = new_zv;
1614 				zval_copy_ctor(new_zv);
1615 				Z_SET_REFCOUNT_P(tmp, 0);
1616 				Z_UNSET_ISREF_P(tmp);
1617 				separated = 1;
1618 			}
1619 		}
1620 
1621 		zephir_increment(tmp);
1622 
1623 		if (separated) {
1624 			zephir_update_property_zval(object, property_name, property_length, tmp TSRMLS_CC);
1625 		}
1626 	}
1627 
1628 	return SUCCESS;
1629 }
1630 
1631 /**
1632  * Decrements an object property
1633  */
zephir_property_decr(zval * object,char * property_name,unsigned int property_length TSRMLS_DC)1634 int zephir_property_decr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC){
1635 
1636 	zval *tmp = NULL;
1637 	zend_class_entry *ce;
1638 	int separated = 0;
1639 
1640 	if (Z_TYPE_P(object) != IS_OBJECT) {
1641 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object");
1642 		return FAILURE;
1643 	}
1644 
1645 	ce = Z_OBJCE_P(object);
1646 	if (ce->parent) {
1647 		ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC);
1648 	}
1649 
1650 	zephir_read_property(&tmp, object, property_name, property_length, 0 TSRMLS_CC);
1651 	if (tmp) {
1652 
1653 		Z_DELREF_P(tmp);
1654 
1655 		/** Separation only when refcount > 1 */
1656 		if (Z_REFCOUNT_P(tmp) > 1) {
1657 			if (!Z_ISREF_P(tmp)) {
1658 				zval *new_zv;
1659 				ALLOC_ZVAL(new_zv);
1660 				INIT_PZVAL_COPY(new_zv, tmp);
1661 				tmp = new_zv;
1662 				zval_copy_ctor(new_zv);
1663 				Z_SET_REFCOUNT_P(tmp, 0);
1664 				Z_UNSET_ISREF_P(tmp);
1665 				separated = 1;
1666 			}
1667 		}
1668 
1669 		zephir_decrement(tmp);
1670 
1671 		if (separated) {
1672 			zephir_update_property_zval(object, property_name, property_length, tmp TSRMLS_CC);
1673 		}
1674 	}
1675 
1676 	return SUCCESS;
1677 }
1678 
1679 /**
1680  * Fetches a property using a const char
1681  */
zephir_fetch_property(zval ** result,zval * object,const char * property_name,zend_uint property_length,int silent TSRMLS_DC)1682 int zephir_fetch_property(zval **result, zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC) {
1683 
1684 	if (zephir_isset_property(object, property_name, property_length + 1 TSRMLS_CC)) {
1685 		zephir_read_property(result, object, property_name, property_length, 0 TSRMLS_CC);
1686 		return 1;
1687 	}
1688 
1689 	*result = ZEPHIR_GLOBAL(global_null);
1690 	Z_ADDREF_P(*result);
1691 	return 0;
1692 }
1693 
1694 /**
1695  * Fetches a property using a zval property
1696  */
zephir_fetch_property_zval(zval ** result,zval * object,zval * property,int silent TSRMLS_DC)1697 int zephir_fetch_property_zval(zval **result, zval *object, zval *property, int silent TSRMLS_DC) {
1698 
1699 	if (UNEXPECTED(Z_TYPE_P(property) != IS_STRING)) {
1700 		*result = ZEPHIR_GLOBAL(global_null);
1701 		Z_ADDREF_P(*result);
1702 		return 0;
1703 	}
1704 
1705 	if (zephir_isset_property(object, Z_STRVAL_P(property), Z_STRLEN_P(property) + 1 TSRMLS_CC)) {
1706 		zephir_read_property(result, object, Z_STRVAL_P(property), Z_STRLEN_P(property), 0 TSRMLS_CC);
1707 		return 1;
1708 	}
1709 
1710 	*result = ZEPHIR_GLOBAL(global_null);
1711 	Z_ADDREF_P(*result);
1712 	return 0;
1713 }
1714 
1715 /**
1716  * Creates a closure
1717  */
zephir_create_closure_ex(zval * return_value,zval * this_ptr,zend_class_entry * ce,const char * method_name,zend_uint method_length TSRMLS_DC)1718 int zephir_create_closure_ex(zval *return_value, zval *this_ptr, zend_class_entry *ce, const char *method_name, zend_uint method_length TSRMLS_DC) {
1719 
1720 	zend_function *function_ptr;
1721 
1722 	if (zend_hash_find(&ce->function_table, method_name, method_length, (void**) &function_ptr) == FAILURE) {
1723 		ZVAL_NULL(return_value);
1724 		return FAILURE;
1725 	}
1726 
1727 	zend_create_closure(return_value, function_ptr, ce, this_ptr TSRMLS_CC);
1728 	return SUCCESS;
1729 }
1730 
zephir_free_object_storage(void * object TSRMLS_DC)1731 void zephir_free_object_storage(void *object TSRMLS_DC)
1732 {
1733 	zend_object_std_dtor((zend_object*)object TSRMLS_CC);
1734 	efree(object);
1735 }
1736