zend_objects.c (7e8bd05c) zend_objects.c (345e0255)
1/*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2004 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$ */
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
28
29ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handle handle TSRMLS_DC)
30{
31 zend_function *destructor = object->ce->destructor;
32
33 if (destructor) {
34 zval zobj, *obj = &zobj;
35 zval *old_exception;
36
37 if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
38 if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
39 /* Ensure that if we're calling a private function, we're allowed to do so.
40 */
41 if (object->ce != EG(scope)) {
42 zend_class_entry *ce = object->ce;
43
44 zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
45 "Call to private %s::__destruct() from context '%s'%s",
46 ce->name,
47 EG(scope) ? EG(scope)->name : "",
48 EG(in_execution) ? "" : " during shutdown ignored");
49 return;
50 }
51 } else {
52 /* Ensure that if we're calling a protected function, we're allowed to do so.
53 */
54 if (!zend_check_protected(destructor->common.scope, EG(scope))) {
55 zend_class_entry *ce = object->ce;
56
57 zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
58 "Call to protected %s::__destruct() from context '%s'%s",
59 ce->name,
60 EG(scope) ? EG(scope)->name : "",
61 EG(in_execution) ? "" : " during shutdown ignored");
62 return;
63 }
64 }
65 }
66
67 zobj.type = IS_OBJECT;
68 zobj.value.obj.handle = handle;
69 zobj.value.obj.handlers = &std_object_handlers;
70 INIT_PZVAL(obj);
71
72 /* Make sure that destructors are protected from previously thrown exceptions.
73 * For example, if an exception was thrown in a function and when the function's
74 * local variable destruction results in a destructor being called.
75 */
76 old_exception = EG(exception);
77 EG(exception) = NULL;
78 zend_call_method_with_0_params(&obj, object->ce, &object->ce->destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
79 if (old_exception) {
80 if (EG(exception)) {
81 zend_error(E_ERROR, "Ignoring exception from %s::__destruct() while an exception is already active", object->ce->name);
82 zval_ptr_dtor(&EG(exception));
83 }
84 EG(exception) = old_exception;
85 }
86 }
87}
88
89ZEND_API void zend_objects_free_object_storage(zend_object *object TSRMLS_DC)
90{
91 zend_hash_destroy(object->properties);
92 FREE_HASHTABLE(object->properties);
93 efree(object);
94}
95
96ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type TSRMLS_DC)
97{
98 zend_object_value retval;
99
100 *object = emalloc(sizeof(zend_object));
101 (*object)->ce = class_type;
102 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);
103 retval.handlers = &std_object_handlers;
104 (*object)->in_get = 0;
105 (*object)->in_set = 0;
1/*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2004 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$ */
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
28
29ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handle handle TSRMLS_DC)
30{
31 zend_function *destructor = object->ce->destructor;
32
33 if (destructor) {
34 zval zobj, *obj = &zobj;
35 zval *old_exception;
36
37 if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
38 if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
39 /* Ensure that if we're calling a private function, we're allowed to do so.
40 */
41 if (object->ce != EG(scope)) {
42 zend_class_entry *ce = object->ce;
43
44 zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
45 "Call to private %s::__destruct() from context '%s'%s",
46 ce->name,
47 EG(scope) ? EG(scope)->name : "",
48 EG(in_execution) ? "" : " during shutdown ignored");
49 return;
50 }
51 } else {
52 /* Ensure that if we're calling a protected function, we're allowed to do so.
53 */
54 if (!zend_check_protected(destructor->common.scope, EG(scope))) {
55 zend_class_entry *ce = object->ce;
56
57 zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
58 "Call to protected %s::__destruct() from context '%s'%s",
59 ce->name,
60 EG(scope) ? EG(scope)->name : "",
61 EG(in_execution) ? "" : " during shutdown ignored");
62 return;
63 }
64 }
65 }
66
67 zobj.type = IS_OBJECT;
68 zobj.value.obj.handle = handle;
69 zobj.value.obj.handlers = &std_object_handlers;
70 INIT_PZVAL(obj);
71
72 /* Make sure that destructors are protected from previously thrown exceptions.
73 * For example, if an exception was thrown in a function and when the function's
74 * local variable destruction results in a destructor being called.
75 */
76 old_exception = EG(exception);
77 EG(exception) = NULL;
78 zend_call_method_with_0_params(&obj, object->ce, &object->ce->destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
79 if (old_exception) {
80 if (EG(exception)) {
81 zend_error(E_ERROR, "Ignoring exception from %s::__destruct() while an exception is already active", object->ce->name);
82 zval_ptr_dtor(&EG(exception));
83 }
84 EG(exception) = old_exception;
85 }
86 }
87}
88
89ZEND_API void zend_objects_free_object_storage(zend_object *object TSRMLS_DC)
90{
91 zend_hash_destroy(object->properties);
92 FREE_HASHTABLE(object->properties);
93 efree(object);
94}
95
96ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type TSRMLS_DC)
97{
98 zend_object_value retval;
99
100 *object = emalloc(sizeof(zend_object));
101 (*object)->ce = class_type;
102 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);
103 retval.handlers = &std_object_handlers;
104 (*object)->in_get = 0;
105 (*object)->in_set = 0;
106 (*object)->in_unset = 0;
107 (*object)->in_isset = 0;
106 return retval;
107}
108
109ZEND_API zend_object *zend_objects_get_address(zval *zobject TSRMLS_DC)
110{
111 return (zend_object *)zend_object_store_get_object(zobject TSRMLS_CC);
112}
113
114static void zval_add_ref_or_clone(zval **p)
115{
116 if (Z_TYPE_PP(p) == IS_OBJECT) {
117 TSRMLS_FETCH();
118
119 if (Z_OBJ_HANDLER_PP(p, clone_obj) == NULL) {
120 zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", Z_OBJCE_PP(p)->name);
121 } else {
122 zval *orig = *p;
123
124 ALLOC_ZVAL(*p);
125 **p = *orig;
126 INIT_PZVAL(*p);
127 (*p)->value.obj = Z_OBJ_HT_PP(p)->clone_obj(*p TSRMLS_CC);
128 }
129 } else {
130 (*p)->refcount++;
131 }
132}
133
134ZEND_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)
135{
136 if (EG(ze1_compatibility_mode)) {
137 zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref_or_clone, (void *) NULL /* Not used anymore */, sizeof(zval *));
138 } else {
139 zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *));
140 }
141 if (old_object->ce->clone) {
142 zval *new_obj;
143
144 MAKE_STD_ZVAL(new_obj);
145 new_obj->type = IS_OBJECT;
146 new_obj->value.obj = new_obj_val;
147 zval_copy_ctor(new_obj);
148
149 zend_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
150
151 zval_ptr_dtor(&new_obj);
152 }
153}
154
155ZEND_API zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC)
156{
157 zend_object_value new_obj_val;
158 zend_object *old_object;
159 zend_object *new_object;
160 zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
161
162 /* assume that create isn't overwritten, so when clone depends on the
163 * overwritten one then it must itself be overwritten */
164 old_object = zend_objects_get_address(zobject TSRMLS_CC);
165 new_obj_val = zend_objects_new(&new_object, old_object->ce TSRMLS_CC);
166
167 ALLOC_HASHTABLE(new_object->properties);
168 zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
169
170 zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
171
172 return new_obj_val;
173}
174
175/*
176 * Local variables:
177 * tab-width: 4
178 * c-basic-offset: 4
179 * indent-tabs-mode: t
180 * End:
181 */
108 return retval;
109}
110
111ZEND_API zend_object *zend_objects_get_address(zval *zobject TSRMLS_DC)
112{
113 return (zend_object *)zend_object_store_get_object(zobject TSRMLS_CC);
114}
115
116static void zval_add_ref_or_clone(zval **p)
117{
118 if (Z_TYPE_PP(p) == IS_OBJECT) {
119 TSRMLS_FETCH();
120
121 if (Z_OBJ_HANDLER_PP(p, clone_obj) == NULL) {
122 zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", Z_OBJCE_PP(p)->name);
123 } else {
124 zval *orig = *p;
125
126 ALLOC_ZVAL(*p);
127 **p = *orig;
128 INIT_PZVAL(*p);
129 (*p)->value.obj = Z_OBJ_HT_PP(p)->clone_obj(*p TSRMLS_CC);
130 }
131 } else {
132 (*p)->refcount++;
133 }
134}
135
136ZEND_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)
137{
138 if (EG(ze1_compatibility_mode)) {
139 zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref_or_clone, (void *) NULL /* Not used anymore */, sizeof(zval *));
140 } else {
141 zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *));
142 }
143 if (old_object->ce->clone) {
144 zval *new_obj;
145
146 MAKE_STD_ZVAL(new_obj);
147 new_obj->type = IS_OBJECT;
148 new_obj->value.obj = new_obj_val;
149 zval_copy_ctor(new_obj);
150
151 zend_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
152
153 zval_ptr_dtor(&new_obj);
154 }
155}
156
157ZEND_API zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC)
158{
159 zend_object_value new_obj_val;
160 zend_object *old_object;
161 zend_object *new_object;
162 zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
163
164 /* assume that create isn't overwritten, so when clone depends on the
165 * overwritten one then it must itself be overwritten */
166 old_object = zend_objects_get_address(zobject TSRMLS_CC);
167 new_obj_val = zend_objects_new(&new_object, old_object->ce TSRMLS_CC);
168
169 ALLOC_HASHTABLE(new_object->properties);
170 zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
171
172 zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
173
174 return new_obj_val;
175}
176
177/*
178 * Local variables:
179 * tab-width: 4
180 * c-basic-offset: 4
181 * indent-tabs-mode: t
182 * End:
183 */