Annotation of embedaddon/php/Zend/zend_object_handlers.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 2.00 of the Zend license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.zend.com/license/2_00.txt. |
11: | If you did not receive a copy of the Zend license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@zend.com so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Andi Gutmans <andi@zend.com> |
16: | Zeev Suraski <zeev@zend.com> |
17: +----------------------------------------------------------------------+
18: */
19:
20: /* $Id: zend_object_handlers.c 321634 2012-01-01 13:15:04Z felipe $ */
21:
22: #include "zend.h"
23: #include "zend_globals.h"
24: #include "zend_variables.h"
25: #include "zend_API.h"
26: #include "zend_objects.h"
27: #include "zend_objects_API.h"
28: #include "zend_object_handlers.h"
29: #include "zend_interfaces.h"
30: #include "zend_closures.h"
31: #include "zend_compile.h"
32:
33: #define DEBUG_OBJECT_HANDLERS 0
34:
35: #define Z_OBJ_P(zval_p) zend_objects_get_address(zval_p TSRMLS_CC)
36:
37: /*
38: __X accessors explanation:
39:
40: if we have __get and property that is not part of the properties array is
41: requested, we call __get handler. If it fails, we return uninitialized.
42:
43: if we have __set and property that is not part of the properties array is
44: set, we call __set handler. If it fails, we do not change the array.
45:
46: for both handlers above, when we are inside __get/__set, no further calls for
47: __get/__set for this property of this object will be made, to prevent endless
48: recursion and enable accessors to change properties array.
49:
50: if we have __call and method which is not part of the class function table is
51: called, we cal __call handler.
52: */
53:
54: ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC) /* {{{ */
55: {
56: zend_object *zobj;
57: zobj = Z_OBJ_P(object);
58: return zobj->properties;
59: }
60: /* }}} */
61:
62: ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
63: {
64: *is_temp = 0;
65: return zend_std_get_properties(object TSRMLS_CC);
66: }
67: /* }}} */
68:
69: static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC) /* {{{ */
70: {
71: zval *retval = NULL;
72: zend_class_entry *ce = Z_OBJCE_P(object);
73:
74: /* __get handler is called with one argument:
75: property name
76:
77: it should return whether the call was successfull or not
78: */
79:
80: SEPARATE_ARG_IF_REF(member);
81:
82: zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member);
83:
84: zval_ptr_dtor(&member);
85:
86: if (retval) {
87: Z_DELREF_P(retval);
88: }
89:
90: return retval;
91: }
92: /* }}} */
93:
94: static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
95: {
96: zval *retval = NULL;
97: int result;
98: zend_class_entry *ce = Z_OBJCE_P(object);
99:
100: SEPARATE_ARG_IF_REF(member);
101: Z_ADDREF_P(value);
102:
103: /* __set handler is called with two arguments:
104: property name
105: value to be set
106:
107: it should return whether the call was successfull or not
108: */
109: zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value);
110:
111: zval_ptr_dtor(&member);
112: zval_ptr_dtor(&value);
113:
114: if (retval) {
115: result = i_zend_is_true(retval) ? SUCCESS : FAILURE;
116: zval_ptr_dtor(&retval);
117: return result;
118: } else {
119: return FAILURE;
120: }
121: }
122: /* }}} */
123:
124: static void zend_std_call_unsetter(zval *object, zval *member TSRMLS_DC) /* {{{ */
125: {
126: zend_class_entry *ce = Z_OBJCE_P(object);
127:
128: /* __unset handler is called with one argument:
129: property name
130: */
131:
132: SEPARATE_ARG_IF_REF(member);
133:
134: zend_call_method_with_1_params(&object, ce, &ce->__unset, ZEND_UNSET_FUNC_NAME, NULL, member);
135:
136: zval_ptr_dtor(&member);
137: }
138: /* }}} */
139:
140: static zval *zend_std_call_issetter(zval *object, zval *member TSRMLS_DC) /* {{{ */
141: {
142: zval *retval = NULL;
143: zend_class_entry *ce = Z_OBJCE_P(object);
144:
145: /* __isset handler is called with one argument:
146: property name
147:
148: it should return whether the property is set or not
149: */
150:
151: SEPARATE_ARG_IF_REF(member);
152:
153: zend_call_method_with_1_params(&object, ce, &ce->__isset, ZEND_ISSET_FUNC_NAME, &retval, member);
154:
155: zval_ptr_dtor(&member);
156:
157: return retval;
158: }
159: /* }}} */
160:
161: static int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC) /* {{{ */
162: {
163: switch (property_info->flags & ZEND_ACC_PPP_MASK) {
164: case ZEND_ACC_PUBLIC:
165: return 1;
166: case ZEND_ACC_PROTECTED:
167: return zend_check_protected(property_info->ce, EG(scope));
168: case ZEND_ACC_PRIVATE:
169: if ((ce==EG(scope) || property_info->ce == EG(scope)) && EG(scope)) {
170: return 1;
171: } else {
172: return 0;
173: }
174: break;
175: }
176: return 0;
177: }
178: /* }}} */
179:
180: static inline zend_bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class) /* {{{ */
181: {
182: child_class = child_class->parent;
183: while (child_class) {
184: if (child_class == parent_class) {
185: return 1;
186: }
187: child_class = child_class->parent;
188: }
189:
190: return 0;
191: }
192: /* }}} */
193:
194: ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC) /* {{{ */
195: {
196: zend_property_info *property_info = NULL;
197: zend_property_info *scope_property_info;
198: zend_bool denied_access = 0;
199: ulong h;
200:
201: if (Z_STRVAL_P(member)[0] == '\0') {
202: if (!silent) {
203: if (Z_STRLEN_P(member) == 0) {
204: zend_error(E_ERROR, "Cannot access empty property");
205: } else {
206: zend_error(E_ERROR, "Cannot access property started with '\\0'");
207: }
208: }
209: return NULL;
210: }
211: h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
212: if (zend_hash_quick_find(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &property_info)==SUCCESS) {
213: if(property_info->flags & ZEND_ACC_SHADOW) {
214: /* if it's a shadow - go to access it's private */
215: property_info = NULL;
216: } else {
217: if (zend_verify_property_access(property_info, ce TSRMLS_CC)) {
218: if (property_info->flags & ZEND_ACC_CHANGED
219: && !(property_info->flags & ZEND_ACC_PRIVATE)) {
220: /* We still need to make sure that we're not in a context
221: * where the right property is a different 'statically linked' private
222: * continue checking below...
223: */
224: } else {
225: if (!silent && (property_info->flags & ZEND_ACC_STATIC)) {
226: zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name, Z_STRVAL_P(member));
227: }
228: return property_info;
229: }
230: } else {
231: /* Try to look in the scope instead */
232: denied_access = 1;
233: }
234: }
235: }
236: if (EG(scope) != ce
237: && is_derived_class(ce, EG(scope))
238: && EG(scope)
239: && zend_hash_quick_find(&EG(scope)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &scope_property_info)==SUCCESS
240: && scope_property_info->flags & ZEND_ACC_PRIVATE) {
241: return scope_property_info;
242: } else if (property_info) {
243: if (denied_access) {
244: /* Information was available, but we were denied access. Error out. */
245: if (silent) {
246: return NULL;
247: }
248: zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, Z_STRVAL_P(member));
249: } else {
250: /* fall through, return property_info... */
251: }
252: } else {
253: EG(std_property_info).flags = ZEND_ACC_PUBLIC;
254: EG(std_property_info).name = Z_STRVAL_P(member);
255: EG(std_property_info).name_length = Z_STRLEN_P(member);
256: EG(std_property_info).h = h;
257: EG(std_property_info).ce = ce;
258: property_info = &EG(std_property_info);
259: }
260: return property_info;
261: }
262: /* }}} */
263:
264: ZEND_API int zend_check_property_access(zend_object *zobj, char *prop_info_name, int prop_info_name_len TSRMLS_DC) /* {{{ */
265: {
266: zend_property_info *property_info;
267: char *class_name, *prop_name;
268: zval member;
269:
270: zend_unmangle_property_name(prop_info_name, prop_info_name_len, &class_name, &prop_name);
271: ZVAL_STRING(&member, prop_name, 0);
272: property_info = zend_get_property_info(zobj->ce, &member, 1 TSRMLS_CC);
273: if (!property_info) {
274: return FAILURE;
275: }
276: if (class_name && class_name[0] != '*') {
277: if (!(property_info->flags & ZEND_ACC_PRIVATE)) {
278: /* we we're looking for a private prop but found a non private one of the same name */
279: return FAILURE;
280: } else if (strcmp(prop_info_name+1, property_info->name+1)) {
281: /* we we're looking for a private prop but found a private one of the same name but another class */
282: return FAILURE;
283: }
284: }
285: return zend_verify_property_access(property_info, zobj->ce TSRMLS_CC) ? SUCCESS : FAILURE;
286: }
287: /* }}} */
288:
289: static int zend_get_property_guard(zend_object *zobj, zend_property_info *property_info, zval *member, zend_guard **pguard) /* {{{ */
290: {
291: zend_property_info info;
292: zend_guard stub;
293:
294: if (!property_info) {
295: property_info = &info;
296: info.name = Z_STRVAL_P(member);
297: info.name_length = Z_STRLEN_P(member);
298: info.h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
299: }
300: if (!zobj->guards) {
301: ALLOC_HASHTABLE(zobj->guards);
302: zend_hash_init(zobj->guards, 0, NULL, NULL, 0);
303: } else if (zend_hash_quick_find(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void **) pguard) == SUCCESS) {
304: return SUCCESS;
305: }
306: stub.in_get = 0;
307: stub.in_set = 0;
308: stub.in_unset = 0;
309: stub.in_isset = 0;
310: return zend_hash_quick_add(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
311: }
312: /* }}} */
313:
314: zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
315: {
316: zend_object *zobj;
317: zval *tmp_member = NULL;
318: zval **retval;
319: zval *rv = NULL;
320: zend_property_info *property_info;
321: int silent;
322:
323: silent = (type == BP_VAR_IS);
324: zobj = Z_OBJ_P(object);
325:
326: if (Z_TYPE_P(member) != IS_STRING) {
327: ALLOC_ZVAL(tmp_member);
328: *tmp_member = *member;
329: INIT_PZVAL(tmp_member);
330: zval_copy_ctor(tmp_member);
331: convert_to_string(tmp_member);
332: member = tmp_member;
333: }
334:
335: #if DEBUG_OBJECT_HANDLERS
336: fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
337: #endif
338:
339: /* make zend_get_property_info silent if we have getter - we may want to use it */
340: property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC);
341:
342: if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) {
343: zend_guard *guard = NULL;
344:
345: if (zobj->ce->__get &&
346: zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
347: !guard->in_get) {
348: /* have getter - try with it! */
349: Z_ADDREF_P(object);
350: if (PZVAL_IS_REF(object)) {
351: SEPARATE_ZVAL(&object);
352: }
353: guard->in_get = 1; /* prevent circular getting */
354: rv = zend_std_call_getter(object, member TSRMLS_CC);
355: guard->in_get = 0;
356:
357: if (rv) {
358: retval = &rv;
359: if (!Z_ISREF_P(rv) &&
360: (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)) {
361: if (Z_REFCOUNT_P(rv) > 0) {
362: zval *tmp = rv;
363:
364: ALLOC_ZVAL(rv);
365: *rv = *tmp;
366: zval_copy_ctor(rv);
367: Z_UNSET_ISREF_P(rv);
368: Z_SET_REFCOUNT_P(rv, 0);
369: }
370: if (Z_TYPE_P(rv) != IS_OBJECT) {
371: zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", zobj->ce->name, Z_STRVAL_P(member));
372: }
373: }
374: } else {
375: retval = &EG(uninitialized_zval_ptr);
376: }
377: if (EXPECTED(*retval != object)) {
378: zval_ptr_dtor(&object);
379: } else {
380: Z_DELREF_P(object);
381: }
382: } else {
383: if (zobj->ce->__get && guard && guard->in_get == 1) {
384: if (Z_STRVAL_P(member)[0] == '\0') {
385: if (Z_STRLEN_P(member) == 0) {
386: zend_error(E_ERROR, "Cannot access empty property");
387: } else {
388: zend_error(E_ERROR, "Cannot access property started with '\\0'");
389: }
390: }
391: }
392: if (!silent) {
393: zend_error(E_NOTICE,"Undefined property: %s::$%s", zobj->ce->name, Z_STRVAL_P(member));
394: }
395: retval = &EG(uninitialized_zval_ptr);
396: }
397: }
398: if (tmp_member) {
399: Z_ADDREF_PP(retval);
400: zval_ptr_dtor(&tmp_member);
401: Z_DELREF_PP(retval);
402: }
403: return *retval;
404: }
405: /* }}} */
406:
407: static void zend_std_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
408: {
409: zend_object *zobj;
410: zval *tmp_member = NULL;
411: zval **variable_ptr;
412: zend_property_info *property_info;
413:
414: zobj = Z_OBJ_P(object);
415:
416: if (Z_TYPE_P(member) != IS_STRING) {
417: ALLOC_ZVAL(tmp_member);
418: *tmp_member = *member;
419: INIT_PZVAL(tmp_member);
420: zval_copy_ctor(tmp_member);
421: convert_to_string(tmp_member);
422: member = tmp_member;
423: }
424:
425: property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__set != NULL) TSRMLS_CC);
426:
427: if (property_info && zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) {
428: /* if we already have this value there, we don't actually need to do anything */
429: if (*variable_ptr != value) {
430: /* if we are assigning reference, we shouldn't move it, but instead assign variable
431: to the same pointer */
432: if (PZVAL_IS_REF(*variable_ptr)) {
433: zval garbage = **variable_ptr; /* old value should be destroyed */
434:
435: /* To check: can't *variable_ptr be some system variable like error_zval here? */
436: Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value);
437: (*variable_ptr)->value = value->value;
438: if (Z_REFCOUNT_P(value) > 0) {
439: zval_copy_ctor(*variable_ptr);
440: }
441: zval_dtor(&garbage);
442: } else {
443: zval *garbage = *variable_ptr;
444:
445: /* if we assign referenced variable, we should separate it */
446: Z_ADDREF_P(value);
447: if (PZVAL_IS_REF(value)) {
448: SEPARATE_ZVAL(&value);
449: }
450: *variable_ptr = value;
451: zval_ptr_dtor(&garbage);
452: }
453: }
454: } else {
455: zend_guard *guard = NULL;
456:
457: if (zobj->ce->__set &&
458: zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
459: !guard->in_set) {
460: Z_ADDREF_P(object);
461: if (PZVAL_IS_REF(object)) {
462: SEPARATE_ZVAL(&object);
463: }
464: guard->in_set = 1; /* prevent circular setting */
465: if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) {
466: /* for now, just ignore it - __set should take care of warnings, etc. */
467: }
468: guard->in_set = 0;
469: zval_ptr_dtor(&object);
470: } else if (property_info) {
471: zval **foo;
472:
473: /* if we assign referenced variable, we should separate it */
474: Z_ADDREF_P(value);
475: if (PZVAL_IS_REF(value)) {
476: SEPARATE_ZVAL(&value);
477: }
478: zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void **) &foo);
479: } else if (zobj->ce->__set && guard && guard->in_set == 1) {
480: if (Z_STRVAL_P(member)[0] == '\0') {
481: if (Z_STRLEN_P(member) == 0) {
482: zend_error(E_ERROR, "Cannot access empty property");
483: } else {
484: zend_error(E_ERROR, "Cannot access property started with '\\0'");
485: }
486: }
487: }
488: }
489:
490: if (tmp_member) {
491: zval_ptr_dtor(&tmp_member);
492: }
493: }
494: /* }}} */
495:
496: zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
497: {
498: zend_class_entry *ce = Z_OBJCE_P(object);
499: zval *retval;
500:
501: if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
502: if(offset == NULL) {
503: /* [] construct */
504: ALLOC_INIT_ZVAL(offset);
505: } else {
506: SEPARATE_ARG_IF_REF(offset);
507: }
508: zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
509:
510: zval_ptr_dtor(&offset);
511:
512: if (!retval) {
513: if (!EG(exception)) {
514: zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
515: }
516: return 0;
517: }
518:
519: /* Undo PZVAL_LOCK() */
520: Z_DELREF_P(retval);
521:
522: return retval;
523: } else {
524: zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
525: return 0;
526: }
527: }
528: /* }}} */
529:
530: static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
531: {
532: zend_class_entry *ce = Z_OBJCE_P(object);
533:
534: if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
535: if (!offset) {
536: ALLOC_INIT_ZVAL(offset);
537: } else {
538: SEPARATE_ARG_IF_REF(offset);
539: }
540: zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value);
541: zval_ptr_dtor(&offset);
542: } else {
543: zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
544: }
545: }
546: /* }}} */
547:
548: static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
549: {
550: zend_class_entry *ce = Z_OBJCE_P(object);
551: zval *retval;
552: int result;
553:
554: if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
555: SEPARATE_ARG_IF_REF(offset);
556: zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
557: if (retval) {
558: result = i_zend_is_true(retval);
559: zval_ptr_dtor(&retval);
560: if (check_empty && result && !EG(exception)) {
561: zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
562: if (retval) {
563: result = i_zend_is_true(retval);
564: zval_ptr_dtor(&retval);
565: }
566: }
567: } else {
568: result = 0;
569: }
570: zval_ptr_dtor(&offset);
571: } else {
572: zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
573: return 0;
574: }
575: return result;
576: }
577: /* }}} */
578:
579: static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
580: {
581: zend_object *zobj;
582: zval tmp_member;
583: zval **retval;
584: zend_property_info *property_info;
585:
586: zobj = Z_OBJ_P(object);
587:
588: if (Z_TYPE_P(member) != IS_STRING) {
589: tmp_member = *member;
590: zval_copy_ctor(&tmp_member);
591: convert_to_string(&tmp_member);
592: member = &tmp_member;
593: }
594:
595: #if DEBUG_OBJECT_HANDLERS
596: fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
597: #endif
598:
599: property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC);
600:
601: if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) {
602: zval *new_zval;
603: zend_guard *guard;
604:
605: if (!zobj->ce->__get ||
606: zend_get_property_guard(zobj, property_info, member, &guard) != SUCCESS ||
607: (property_info && guard->in_get)) {
608: /* we don't have access controls - will just add it */
609: new_zval = &EG(uninitialized_zval);
610:
611: /* zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */
612: Z_ADDREF_P(new_zval);
613: zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval);
614: } else {
615: /* we do have getter - fail and let it try again with usual get/set */
616: retval = NULL;
617: }
618: }
619: if (member == &tmp_member) {
620: zval_dtor(member);
621: }
622: return retval;
623: }
624: /* }}} */
625:
626: static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
627: {
628: zend_object *zobj;
629: zval *tmp_member = NULL;
630: zend_property_info *property_info;
631:
632: zobj = Z_OBJ_P(object);
633:
634: if (Z_TYPE_P(member) != IS_STRING) {
635: ALLOC_ZVAL(tmp_member);
636: *tmp_member = *member;
637: INIT_PZVAL(tmp_member);
638: zval_copy_ctor(tmp_member);
639: convert_to_string(tmp_member);
640: member = tmp_member;
641: }
642:
643: property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__unset != NULL) TSRMLS_CC);
644:
645: if (!property_info || zend_hash_quick_del(zobj->properties, property_info->name, property_info->name_length+1, property_info->h) == FAILURE) {
646: zend_guard *guard = NULL;
647:
648: if (zobj->ce->__unset &&
649: zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
650: !guard->in_unset) {
651: /* have unseter - try with it! */
652: Z_ADDREF_P(object);
653: if (PZVAL_IS_REF(object)) {
654: SEPARATE_ZVAL(&object);
655: }
656: guard->in_unset = 1; /* prevent circular unsetting */
657: zend_std_call_unsetter(object, member TSRMLS_CC);
658: guard->in_unset = 0;
659: zval_ptr_dtor(&object);
660: } else if (zobj->ce->__unset && guard && guard->in_unset == 1) {
661: if (Z_STRVAL_P(member)[0] == '\0') {
662: if (Z_STRLEN_P(member) == 0) {
663: zend_error(E_ERROR, "Cannot access empty property");
664: } else {
665: zend_error(E_ERROR, "Cannot access property started with '\\0'");
666: }
667: }
668: }
669: }
670:
671: if (tmp_member) {
672: zval_ptr_dtor(&tmp_member);
673: }
674: }
675: /* }}} */
676:
677: static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
678: {
679: zend_class_entry *ce = Z_OBJCE_P(object);
680:
681: if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
682: SEPARATE_ARG_IF_REF(offset);
683: zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", NULL, offset);
684: zval_ptr_dtor(&offset);
685: } else {
686: zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
687: }
688: }
689: /* }}} */
690:
691: ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
692: {
693: zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function;
694: zval *method_name_ptr, *method_args_ptr;
695: zval *method_result_ptr = NULL;
696: zend_class_entry *ce = Z_OBJCE_P(this_ptr);
697:
698: ALLOC_ZVAL(method_args_ptr);
699: INIT_PZVAL(method_args_ptr);
700: array_init_size(method_args_ptr, ZEND_NUM_ARGS());
701:
702: if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
703: zval_dtor(method_args_ptr);
704: zend_error(E_ERROR, "Cannot get arguments for __call");
705: RETURN_FALSE;
706: }
707:
708: ALLOC_ZVAL(method_name_ptr);
709: INIT_PZVAL(method_name_ptr);
710: ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */
711:
712: /* __call handler is called with two arguments:
713: method name
714: array of method parameters
715:
716: */
717: zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);
718:
719: if (method_result_ptr) {
720: if (Z_ISREF_P(method_result_ptr) || Z_REFCOUNT_P(method_result_ptr) > 1) {
721: RETVAL_ZVAL(method_result_ptr, 1, 1);
722: } else {
723: RETVAL_ZVAL(method_result_ptr, 0, 1);
724: }
725: }
726:
727: /* now destruct all auxiliaries */
728: zval_ptr_dtor(&method_args_ptr);
729: zval_ptr_dtor(&method_name_ptr);
730:
731: /* destruct the function also, then - we have allocated it in get_method */
732: efree(func);
733: }
734: /* }}} */
735:
736: /* Ensures that we're allowed to call a private method.
737: * Returns the function address that should be called, or NULL
738: * if no such function exists.
739: */
740: static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */
741: {
742: if (!ce) {
743: return 0;
744: }
745:
746: /* We may call a private function if:
747: * 1. The class of our object is the same as the scope, and the private
748: * function (EX(fbc)) has the same scope.
749: * 2. One of our parent classes are the same as the scope, and it contains
750: * a private function with the same name that has the same scope.
751: */
752: if (fbc->common.scope == ce && EG(scope) == ce) {
753: /* rule #1 checks out ok, allow the function call */
754: return fbc;
755: }
756:
757:
758: /* Check rule #2 */
759: ce = ce->parent;
760: while (ce) {
761: if (ce == EG(scope)) {
762: if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==SUCCESS
763: && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE
764: && fbc->common.scope == EG(scope)) {
765: return fbc;
766: }
767: break;
768: }
769: ce = ce->parent;
770: }
771: return NULL;
772: }
773: /* }}} */
774:
775: ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */
776: {
777: return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen TSRMLS_CC) != NULL;
778: }
779: /* }}} */
780:
781: /* Ensures that we're allowed to call a protected method.
782: */
783: ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) /* {{{ */
784: {
785: zend_class_entry *fbc_scope = ce;
786:
787: /* Is the context that's calling the function, the same as one of
788: * the function's parents?
789: */
790: while (fbc_scope) {
791: if (fbc_scope==scope) {
792: return 1;
793: }
794: fbc_scope = fbc_scope->parent;
795: }
796:
797: /* Is the function's scope the same as our current object context,
798: * or any of the parents of our context?
799: */
800: while (scope) {
801: if (scope==ce) {
802: return 1;
803: }
804: scope = scope->parent;
805: }
806: return 0;
807: }
808: /* }}} */
809:
810: static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc) /* {{{ */
811: {
812: return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope;
813: }
814: /* }}} */
815:
816: static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */
817: {
818: zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
819: call_user_call->type = ZEND_INTERNAL_FUNCTION;
820: call_user_call->module = ce->module;
821: call_user_call->handler = zend_std_call_user_call;
822: call_user_call->arg_info = NULL;
823: call_user_call->num_args = 0;
824: call_user_call->scope = ce;
825: call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
826: call_user_call->function_name = estrndup(method_name, method_len);
827: call_user_call->pass_rest_by_reference = 0;
828: call_user_call->return_reference = ZEND_RETURN_VALUE;
829:
830: return (union _zend_function *)call_user_call;
831: }
832: /* }}} */
833:
834: static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */
835: {
836: zend_object *zobj;
837: zend_function *fbc;
838: char *lc_method_name;
839: zval *object = *object_ptr;
840: ALLOCA_FLAG(use_heap)
841:
842: lc_method_name = do_alloca(method_len+1, use_heap);
843: /* Create a zend_copy_str_tolower(dest, src, src_length); */
844: zend_str_tolower_copy(lc_method_name, method_name, method_len);
845:
846: zobj = Z_OBJ_P(object);
847: if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) {
848: free_alloca(lc_method_name, use_heap);
849: if (zobj->ce->__call) {
850: return zend_get_user_call_function(zobj->ce, method_name, method_len);
851: } else {
852: return NULL;
853: }
854: }
855:
856: /* Check access level */
857: if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
858: zend_function *updated_fbc;
859:
860: /* Ensure that if we're calling a private function, we're allowed to do so.
861: * If we're not and __call() handler exists, invoke it, otherwise error out.
862: */
863: updated_fbc = zend_check_private_int(fbc, Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC), lc_method_name, method_len TSRMLS_CC);
864: if (updated_fbc) {
865: fbc = updated_fbc;
866: } else {
867: if (zobj->ce->__call) {
868: fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
869: } else {
870: zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
871: }
872: }
873: } else {
874: /* Ensure that we haven't overridden a private function and end up calling
875: * the overriding public function...
876: */
877: if (EG(scope) &&
878: is_derived_class(fbc->common.scope, EG(scope)) &&
879: fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {
880: zend_function *priv_fbc;
881:
882: if (zend_hash_find(&EG(scope)->function_table, lc_method_name, method_len+1, (void **) &priv_fbc)==SUCCESS
883: && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
884: && priv_fbc->common.scope == EG(scope)) {
885: fbc = priv_fbc;
886: }
887: }
888: if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
889: /* Ensure that if we're calling a protected function, we're allowed to do so.
890: * If we're not and __call() handler exists, invoke it, otherwise error out.
891: */
892: if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
893: if (zobj->ce->__call) {
894: fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
895: } else {
896: zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
897: }
898: }
899: }
900: }
901:
902: free_alloca(lc_method_name, use_heap);
903: return fbc;
904: }
905: /* }}} */
906:
907: ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
908: {
909: zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function;
910: zval *method_name_ptr, *method_args_ptr;
911: zval *method_result_ptr = NULL;
912: zend_class_entry *ce = EG(scope);
913:
914: ALLOC_ZVAL(method_args_ptr);
915: INIT_PZVAL(method_args_ptr);
916: array_init_size(method_args_ptr, ZEND_NUM_ARGS());
917:
918: if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
919: zval_dtor(method_args_ptr);
920: zend_error(E_ERROR, "Cannot get arguments for " ZEND_CALLSTATIC_FUNC_NAME);
921: RETURN_FALSE;
922: }
923:
924: ALLOC_ZVAL(method_name_ptr);
925: INIT_PZVAL(method_name_ptr);
926: ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */
927:
928: /* __callStatic handler is called with two arguments:
929: method name
930: array of method parameters
931: */
932: zend_call_method_with_2_params(NULL, ce, &ce->__callstatic, ZEND_CALLSTATIC_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);
933:
934: if (method_result_ptr) {
935: if (Z_ISREF_P(method_result_ptr) || Z_REFCOUNT_P(method_result_ptr) > 1) {
936: RETVAL_ZVAL(method_result_ptr, 1, 1);
937: } else {
938: RETVAL_ZVAL(method_result_ptr, 0, 1);
939: }
940: }
941:
942: /* now destruct all auxiliaries */
943: zval_ptr_dtor(&method_args_ptr);
944: zval_ptr_dtor(&method_name_ptr);
945:
946: /* destruct the function also, then - we have allocated it in get_method */
947: efree(func);
948: }
949: /* }}} */
950:
951: static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */
952: {
953: zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function));
954: callstatic_user_call->type = ZEND_INTERNAL_FUNCTION;
955: callstatic_user_call->module = ce->module;
956: callstatic_user_call->handler = zend_std_callstatic_user_call;
957: callstatic_user_call->arg_info = NULL;
958: callstatic_user_call->num_args = 0;
959: callstatic_user_call->scope = ce;
960: callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
961: callstatic_user_call->function_name = estrndup(method_name, method_len);
962: callstatic_user_call->pass_rest_by_reference = 0;
963: callstatic_user_call->return_reference = ZEND_RETURN_VALUE;
964:
965: return (zend_function *)callstatic_user_call;
966: }
967: /* }}} */
968:
969: /* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
970:
971: ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */
972: {
973: zend_function *fbc = NULL;
974: char *lc_class_name, *lc_function_name = NULL;
975:
976: lc_function_name = zend_str_tolower_dup(function_name_strval, function_name_strlen);
977:
978: if (function_name_strlen == ce->name_length && ce->constructor) {
979: lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
980: /* Only change the method to the constructor if the constructor isn't called __construct
981: * we check for __ so we can be binary safe for lowering, we should use ZEND_CONSTRUCTOR_FUNC_NAME
982: */
983: if (!memcmp(lc_class_name, lc_function_name, function_name_strlen) && memcmp(ce->constructor->common.function_name, "__", sizeof("__") - 1)) {
984: fbc = ce->constructor;
985: }
986: efree(lc_class_name);
987: }
988: if (!fbc && zend_hash_find(&ce->function_table, lc_function_name, function_name_strlen+1, (void **) &fbc)==FAILURE) {
989: efree(lc_function_name);
990:
991: if (ce->__call &&
992: EG(This) &&
993: Z_OBJ_HT_P(EG(This))->get_class_entry &&
994: instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
995: return zend_get_user_call_function(ce, function_name_strval, function_name_strlen);
996: } else if (ce->__callstatic) {
997: return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
998: } else {
999: return NULL;
1000: }
1001: }
1002: efree(lc_function_name);
1003:
1004: #if MBO_0
1005: /* right now this function is used for non static method lookup too */
1006: /* Is the function static */
1007: if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
1008: zend_error(E_ERROR, "Cannot call non static method %s::%s() without object", ZEND_FN_SCOPE_NAME(fbc), fbc->common.function_name);
1009: }
1010: #endif
1011: if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
1012: /* No further checks necessary, most common case */
1013: } else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
1014: zend_function *updated_fbc;
1015:
1016: /* Ensure that if we're calling a private function, we're allowed to do so.
1017: */
1018: updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC);
1019: if (updated_fbc) {
1020: fbc = updated_fbc;
1021: } else {
1022: if (ce->__callstatic) {
1023: return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
1024: }
1025: zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : "");
1026: }
1027: } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
1028: /* Ensure that if we're calling a protected function, we're allowed to do so.
1029: */
1030: if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
1031: if (ce->__callstatic) {
1032: return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
1033: }
1034: zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : "");
1035: }
1036: }
1037:
1038: return fbc;
1039: }
1040: /* }}} */
1041:
1042: ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC) /* {{{ */
1043: {
1044: zval **retval = NULL;
1045: zend_class_entry *tmp_ce = ce;
1046: zend_property_info *property_info;
1047: zend_property_info std_property_info;
1048:
1049: if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE) {
1050: std_property_info.flags = ZEND_ACC_PUBLIC;
1051: std_property_info.name = property_name;
1052: std_property_info.name_length = property_name_len;
1053: std_property_info.h = zend_get_hash_value(std_property_info.name, std_property_info.name_length+1);
1054: std_property_info.ce = ce;
1055: property_info = &std_property_info;
1056: }
1057:
1058: #if DEBUG_OBJECT_HANDLERS
1059: zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags));
1060: #endif
1061:
1062: if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) {
1063: if (!silent) {
1064: zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
1065: }
1066: return NULL;
1067: }
1068:
1069: zend_update_class_constants(tmp_ce TSRMLS_CC);
1070:
1071: zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval);
1072:
1073: if (!retval) {
1074: if (silent) {
1075: return NULL;
1076: } else {
1077: zend_error(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
1078: }
1079: }
1080:
1081: return retval;
1082: }
1083: /* }}} */
1084:
1085: ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC) /* {{{ */
1086: {
1087: zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name);
1088: return 0;
1089: }
1090: /* }}} */
1091:
1092: ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC) /* {{{ */
1093: {
1094: zend_object *zobj = Z_OBJ_P(object);
1095: zend_function *constructor = zobj->ce->constructor;
1096:
1097: if (constructor) {
1098: if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) {
1099: /* No further checks necessary */
1100: } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
1101: /* Ensure that if we're calling a private function, we're allowed to do so.
1102: */
1103: if (constructor->common.scope != EG(scope)) {
1104: if (EG(scope)) {
1105: zend_error(E_ERROR, "Call to private %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
1106: } else {
1107: zend_error(E_ERROR, "Call to private %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
1108: }
1109: }
1110: } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) {
1111: /* Ensure that if we're calling a protected function, we're allowed to do so.
1112: * Constructors only have prototype if they are defined by an interface but
1113: * it is the compilers responsibility to take care of the prototype.
1114: */
1115: if (!zend_check_protected(zend_get_function_root_class(constructor), EG(scope))) {
1116: if (EG(scope)) {
1117: zend_error(E_ERROR, "Call to protected %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
1118: } else {
1119: zend_error(E_ERROR, "Call to protected %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
1120: }
1121: }
1122: }
1123: }
1124:
1125: return constructor;
1126: }
1127: /* }}} */
1128:
1129: int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC);
1130:
1131: static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
1132: {
1133: zend_object *zobj1, *zobj2;
1134:
1135: zobj1 = Z_OBJ_P(o1);
1136: zobj2 = Z_OBJ_P(o2);
1137:
1138: if (zobj1->ce != zobj2->ce) {
1139: return 1; /* different classes */
1140: }
1141: return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC);
1142: }
1143: /* }}} */
1144:
1145: static int zend_std_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
1146: {
1147: zend_object *zobj;
1148: int result;
1149: zval **value;
1150: zval *tmp_member = NULL;
1151: zend_property_info *property_info;
1152:
1153: zobj = Z_OBJ_P(object);
1154:
1155: if (Z_TYPE_P(member) != IS_STRING) {
1156: ALLOC_ZVAL(tmp_member);
1157: *tmp_member = *member;
1158: INIT_PZVAL(tmp_member);
1159: zval_copy_ctor(tmp_member);
1160: convert_to_string(tmp_member);
1161: member = tmp_member;
1162: }
1163:
1164: #if DEBUG_OBJECT_HANDLERS
1165: fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
1166: #endif
1167:
1168: property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC);
1169:
1170: if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) {
1171: zend_guard *guard;
1172:
1173: result = 0;
1174: if ((has_set_exists != 2) &&
1175: zobj->ce->__isset &&
1176: zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
1177: !guard->in_isset) {
1178: zval *rv;
1179:
1180: /* have issetter - try with it! */
1181: Z_ADDREF_P(object);
1182: if (PZVAL_IS_REF(object)) {
1183: SEPARATE_ZVAL(&object);
1184: }
1185: guard->in_isset = 1; /* prevent circular getting */
1186: rv = zend_std_call_issetter(object, member TSRMLS_CC);
1187: if (rv) {
1188: result = zend_is_true(rv);
1189: zval_ptr_dtor(&rv);
1190: if (has_set_exists && result) {
1191: if (!EG(exception) && zobj->ce->__get && !guard->in_get) {
1192: guard->in_get = 1;
1193: rv = zend_std_call_getter(object, member TSRMLS_CC);
1194: guard->in_get = 0;
1195: if (rv) {
1196: Z_ADDREF_P(rv);
1197: result = i_zend_is_true(rv);
1198: zval_ptr_dtor(&rv);
1199: } else {
1200: result = 0;
1201: }
1202: } else {
1203: result = 0;
1204: }
1205: }
1206: }
1207: guard->in_isset = 0;
1208: zval_ptr_dtor(&object);
1209: }
1210: } else {
1211: switch (has_set_exists) {
1212: case 0:
1213: result = (Z_TYPE_PP(value) != IS_NULL);
1214: break;
1215: default:
1216: result = zend_is_true(*value);
1217: break;
1218: case 2:
1219: result = 1;
1220: break;
1221: }
1222: }
1223:
1224: if (tmp_member) {
1225: zval_ptr_dtor(&tmp_member);
1226: }
1227: return result;
1228: }
1229: /* }}} */
1230:
1231: zend_class_entry *zend_std_object_get_class(const zval *object TSRMLS_DC) /* {{{ */
1232: {
1233: zend_object *zobj;
1234: zobj = Z_OBJ_P(object);
1235:
1236: return zobj->ce;
1237: }
1238: /* }}} */
1239:
1240: int zend_std_object_get_class_name(const zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) /* {{{ */
1241: {
1242: zend_object *zobj;
1243: zend_class_entry *ce;
1244: zobj = Z_OBJ_P(object);
1245:
1246: if (parent) {
1247: if (!zobj->ce->parent) {
1248: return FAILURE;
1249: }
1250: ce = zobj->ce->parent;
1251: } else {
1252: ce = zobj->ce;
1253: }
1254:
1255: *class_name_len = ce->name_length;
1256: *class_name = estrndup(ce->name, ce->name_length);
1257: return SUCCESS;
1258: }
1259: /* }}} */
1260:
1261: ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */
1262: {
1263: zval *retval;
1264: zend_class_entry *ce;
1265:
1266: switch (type) {
1267: case IS_STRING:
1268: ce = Z_OBJCE_P(readobj);
1269: if (ce->__tostring &&
1270: (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
1271: if (EG(exception)) {
1272: if (retval) {
1273: zval_ptr_dtor(&retval);
1274: }
1275: zend_error(E_ERROR, "Method %s::__toString() must not throw an exception", ce->name);
1276: return FAILURE;
1277: }
1278: if (Z_TYPE_P(retval) == IS_STRING) {
1279: INIT_PZVAL(writeobj);
1280: if (readobj == writeobj) {
1281: zval_dtor(readobj);
1282: }
1283: ZVAL_ZVAL(writeobj, retval, 1, 1);
1284: if (Z_TYPE_P(writeobj) != type) {
1285: convert_to_explicit_type(writeobj, type);
1286: }
1287: return SUCCESS;
1288: } else {
1289: zval_ptr_dtor(&retval);
1290: INIT_PZVAL(writeobj);
1291: if (readobj == writeobj) {
1292: zval_dtor(readobj);
1293: }
1294: ZVAL_EMPTY_STRING(writeobj);
1295: zend_error(E_RECOVERABLE_ERROR, "Method %s::__toString() must return a string value", ce->name);
1296: return SUCCESS;
1297: }
1298: }
1299: return FAILURE;
1300: case IS_BOOL:
1301: INIT_PZVAL(writeobj);
1302: ZVAL_BOOL(writeobj, 1);
1303: return SUCCESS;
1304: case IS_LONG:
1305: ce = Z_OBJCE_P(readobj);
1306: zend_error(E_NOTICE, "Object of class %s could not be converted to int", ce->name);
1307: INIT_PZVAL(writeobj);
1308: if (readobj == writeobj) {
1309: zval_dtor(readobj);
1310: }
1311: ZVAL_LONG(writeobj, 1);
1312: return SUCCESS;
1313: case IS_DOUBLE:
1314: ce = Z_OBJCE_P(readobj);
1315: zend_error(E_NOTICE, "Object of class %s could not be converted to double", ce->name);
1316: INIT_PZVAL(writeobj);
1317: if (readobj == writeobj) {
1318: zval_dtor(readobj);
1319: }
1320: ZVAL_DOUBLE(writeobj, 1);
1321: return SUCCESS;
1322: default:
1323: INIT_PZVAL(writeobj);
1324: Z_TYPE_P(writeobj) = IS_NULL;
1325: break;
1326: }
1327: return FAILURE;
1328: }
1329: /* }}} */
1330:
1331: int zend_std_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
1332: {
1333: zend_class_entry *ce;
1334: if (Z_TYPE_P(obj) != IS_OBJECT) {
1335: return FAILURE;
1336: }
1337:
1338: ce = Z_OBJCE_P(obj);
1339:
1340: if (zend_hash_find(&ce->function_table, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME), (void**)fptr_ptr) == FAILURE) {
1341: return FAILURE;
1342: }
1343:
1344: *ce_ptr = ce;
1345: if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) {
1346: if (zobj_ptr) {
1347: *zobj_ptr = NULL;
1348: }
1349: } else {
1350: if (zobj_ptr) {
1351: *zobj_ptr = obj;
1352: }
1353: }
1354: return SUCCESS;
1355: }
1356: /* }}} */
1357:
1358: ZEND_API zend_object_handlers std_object_handlers = {
1359: zend_objects_store_add_ref, /* add_ref */
1360: zend_objects_store_del_ref, /* del_ref */
1361: zend_objects_clone_obj, /* clone_obj */
1362:
1363: zend_std_read_property, /* read_property */
1364: zend_std_write_property, /* write_property */
1365: zend_std_read_dimension, /* read_dimension */
1366: zend_std_write_dimension, /* write_dimension */
1367: zend_std_get_property_ptr_ptr, /* get_property_ptr_ptr */
1368: NULL, /* get */
1369: NULL, /* set */
1370: zend_std_has_property, /* has_property */
1371: zend_std_unset_property, /* unset_property */
1372: zend_std_has_dimension, /* has_dimension */
1373: zend_std_unset_dimension, /* unset_dimension */
1374: zend_std_get_properties, /* get_properties */
1375: zend_std_get_method, /* get_method */
1376: NULL, /* call_method */
1377: zend_std_get_constructor, /* get_constructor */
1378: zend_std_object_get_class, /* get_class_entry */
1379: zend_std_object_get_class_name, /* get_class_name */
1380: zend_std_compare_objects, /* compare_objects */
1381: zend_std_cast_object_tostring, /* cast_object */
1382: NULL, /* count_elements */
1383: NULL, /* get_debug_info */
1384: zend_std_get_closure, /* get_closure */
1385: };
1386:
1387: /*
1388: * Local variables:
1389: * tab-width: 4
1390: * c-basic-offset: 4
1391: * indent-tabs-mode: t
1392: * End:
1393: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>