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