1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1998-2014 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_objects.c,v 1.1.1.4 2014/06/15 20:04:04 misho Exp $ */
21:
22: #include "zend.h"
23: #include "zend_globals.h"
24: #include "zend_variables.h"
25: #include "zend_API.h"
26: #include "zend_interfaces.h"
27: #include "zend_exceptions.h"
28:
29: ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce TSRMLS_DC)
30: {
31: object->ce = ce;
32: object->properties = NULL;
33: object->properties_table = NULL;
34: object->guards = NULL;
35: }
36:
37: ZEND_API void zend_object_std_dtor(zend_object *object TSRMLS_DC)
38: {
39: if (object->guards) {
40: zend_hash_destroy(object->guards);
41: FREE_HASHTABLE(object->guards);
42: }
43: if (object->properties) {
44: zend_hash_destroy(object->properties);
45: FREE_HASHTABLE(object->properties);
46: if (object->properties_table) {
47: efree(object->properties_table);
48: }
49: } else if (object->properties_table) {
50: int i;
51:
52: for (i = 0; i < object->ce->default_properties_count; i++) {
53: if (object->properties_table[i]) {
54: zval_ptr_dtor(&object->properties_table[i]);
55: }
56: }
57: efree(object->properties_table);
58: }
59: }
60:
61: ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handle handle TSRMLS_DC)
62: {
63: zend_function *destructor = object ? object->ce->destructor : NULL;
64:
65: if (destructor) {
66: zval *old_exception;
67: zval *obj;
68: zend_object_store_bucket *obj_bucket;
69:
70: if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
71: if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
72: /* Ensure that if we're calling a private function, we're allowed to do so.
73: */
74: if (object->ce != EG(scope)) {
75: zend_class_entry *ce = object->ce;
76:
77: zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
78: "Call to private %s::__destruct() from context '%s'%s",
79: ce->name,
80: EG(scope) ? EG(scope)->name : "",
81: EG(in_execution) ? "" : " during shutdown ignored");
82: return;
83: }
84: } else {
85: /* Ensure that if we're calling a protected function, we're allowed to do so.
86: */
87: if (!zend_check_protected(zend_get_function_root_class(destructor), EG(scope))) {
88: zend_class_entry *ce = object->ce;
89:
90: zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
91: "Call to protected %s::__destruct() from context '%s'%s",
92: ce->name,
93: EG(scope) ? EG(scope)->name : "",
94: EG(in_execution) ? "" : " during shutdown ignored");
95: return;
96: }
97: }
98: }
99:
100: MAKE_STD_ZVAL(obj);
101: Z_TYPE_P(obj) = IS_OBJECT;
102: Z_OBJ_HANDLE_P(obj) = handle;
103: obj_bucket = &EG(objects_store).object_buckets[handle];
104: if (!obj_bucket->bucket.obj.handlers) {
105: obj_bucket->bucket.obj.handlers = &std_object_handlers;
106: }
107: Z_OBJ_HT_P(obj) = obj_bucket->bucket.obj.handlers;
108: zval_copy_ctor(obj);
109:
110: /* Make sure that destructors are protected from previously thrown exceptions.
111: * For example, if an exception was thrown in a function and when the function's
112: * local variable destruction results in a destructor being called.
113: */
114: old_exception = NULL;
115: if (EG(exception)) {
116: if (Z_OBJ_HANDLE_P(EG(exception)) == handle) {
117: zend_error(E_ERROR, "Attempt to destruct pending exception");
118: } else {
119: old_exception = EG(exception);
120: EG(exception) = NULL;
121: }
122: }
123: zend_call_method_with_0_params(&obj, object->ce, &destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
124: if (old_exception) {
125: if (EG(exception)) {
126: zend_exception_set_previous(EG(exception), old_exception TSRMLS_CC);
127: } else {
128: EG(exception) = old_exception;
129: }
130: }
131: zval_ptr_dtor(&obj);
132: }
133: }
134:
135: ZEND_API void zend_objects_free_object_storage(zend_object *object TSRMLS_DC)
136: {
137: zend_object_std_dtor(object TSRMLS_CC);
138: efree(object);
139: }
140:
141: ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type TSRMLS_DC)
142: {
143: zend_object_value retval;
144:
145: *object = emalloc(sizeof(zend_object));
146: (*object)->ce = class_type;
147: (*object)->properties = NULL;
148: (*object)->properties_table = NULL;
149: (*object)->guards = NULL;
150: retval.handle = zend_objects_store_put(*object, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC);
151: retval.handlers = &std_object_handlers;
152: return retval;
153: }
154:
155: ZEND_API zend_object *zend_objects_get_address(const zval *zobject TSRMLS_DC)
156: {
157: return (zend_object *)zend_object_store_get_object(zobject TSRMLS_CC);
158: }
159:
160: ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object_value new_obj_val, zend_object *old_object, zend_object_handle handle TSRMLS_DC)
161: {
162: int i;
163:
164: if (old_object->properties_table) {
165: if (!new_object->properties_table) {
166: new_object->properties_table = emalloc(sizeof(zval*) * old_object->ce->default_properties_count);
167: memset(new_object->properties_table, 0, sizeof(zval*) * old_object->ce->default_properties_count);
168: }
169: for (i = 0; i < old_object->ce->default_properties_count; i++) {
170: if (!new_object->properties) {
171: if (new_object->properties_table[i]) {
172: zval_ptr_dtor(&new_object->properties_table[i]);
173: }
174: }
175: if (!old_object->properties) {
176: new_object->properties_table[i] = old_object->properties_table[i];
177: if (new_object->properties_table[i]) {
178: Z_ADDREF_P(new_object->properties_table[i]);
179: }
180: }
181: }
182: }
183: if (old_object->properties) {
184: if (!new_object->properties) {
185: ALLOC_HASHTABLE(new_object->properties);
186: zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
187: }
188: zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *));
189: if (old_object->properties_table) {
190: HashPosition pos;
191: zend_property_info *prop_info;
192: for (zend_hash_internal_pointer_reset_ex(&old_object->ce->properties_info, &pos);
193: zend_hash_get_current_data_ex(&old_object->ce->properties_info, (void**)&prop_info, &pos) == SUCCESS;
194: zend_hash_move_forward_ex(&old_object->ce->properties_info, &pos)) {
195: if ((prop_info->flags & ZEND_ACC_STATIC) == 0) {
196: if (zend_hash_quick_find(new_object->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&new_object->properties_table[prop_info->offset]) == FAILURE) {
197: new_object->properties_table[prop_info->offset] = NULL;
198: }
199: }
200: }
201: }
202: }
203:
204: if (old_object->ce->clone) {
205: zval *new_obj;
206:
207: MAKE_STD_ZVAL(new_obj);
208: new_obj->type = IS_OBJECT;
209: new_obj->value.obj = new_obj_val;
210: zval_copy_ctor(new_obj);
211:
212: zend_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
213:
214: zval_ptr_dtor(&new_obj);
215: }
216: }
217:
218: ZEND_API zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC)
219: {
220: zend_object_value new_obj_val;
221: zend_object *old_object;
222: zend_object *new_object;
223: zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
224:
225: /* assume that create isn't overwritten, so when clone depends on the
226: * overwritten one then it must itself be overwritten */
227: old_object = zend_objects_get_address(zobject TSRMLS_CC);
228: new_obj_val = zend_objects_new(&new_object, old_object->ce TSRMLS_CC);
229:
230: zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
231:
232: return new_obj_val;
233: }
234:
235: /*
236: * Local variables:
237: * tab-width: 4
238: * c-basic-offset: 4
239: * indent-tabs-mode: t
240: * End:
241: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>