root/Zend/zend_objects.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_object_std_init
  2. zend_object_std_dtor
  3. zend_objects_destroy_object
  4. zend_objects_new
  5. zend_objects_clone_members
  6. zend_objects_clone_obj

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 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    |          Dmitry Stogov <dmitry@zend.com>                             |
  18    +----------------------------------------------------------------------+
  19 */
  20 
  21 /* $Id$ */
  22 
  23 #include "zend.h"
  24 #include "zend_globals.h"
  25 #include "zend_variables.h"
  26 #include "zend_API.h"
  27 #include "zend_interfaces.h"
  28 #include "zend_exceptions.h"
  29 
  30 ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce)
  31 {
  32         zval *p, *end;
  33 
  34         GC_REFCOUNT(object) = 1;
  35         GC_TYPE_INFO(object) = IS_OBJECT;
  36         object->ce = ce;
  37         object->properties = NULL;
  38         zend_objects_store_put(object);
  39         p = object->properties_table;
  40         if (EXPECTED(ce->default_properties_count != 0)) {
  41                 end = p + ce->default_properties_count;
  42                 do {
  43                         ZVAL_UNDEF(p);
  44                         p++;
  45                 } while (p != end);
  46         }
  47         if (UNEXPECTED(ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
  48                 GC_FLAGS(object) |= IS_OBJ_USE_GUARDS;
  49                 Z_PTR_P(p) = NULL;
  50                 ZVAL_UNDEF(p);
  51         }
  52 }
  53 
  54 ZEND_API void zend_object_std_dtor(zend_object *object)
  55 {
  56         zval *p, *end;
  57 
  58         if (object->properties) {
  59                 if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) {
  60                         if (EXPECTED(--GC_REFCOUNT(object->properties) == 0)) {
  61                                 zend_array_destroy(object->properties);
  62                         }
  63                 }
  64         }
  65         p = object->properties_table;
  66         if (EXPECTED(object->ce->default_properties_count)) {
  67                 end = p + object->ce->default_properties_count;
  68                 do {
  69                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
  70                         p++;
  71                 } while (p != end);
  72         }
  73         if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_HAS_GUARDS)) {
  74                 HashTable *guards = Z_PTR_P(p);
  75 
  76                 ZEND_ASSERT(guards != NULL);
  77                 zend_hash_destroy(guards);
  78                 FREE_HASHTABLE(guards);
  79         }
  80 }
  81 
  82 ZEND_API void zend_objects_destroy_object(zend_object *object)
  83 {
  84         zend_function *destructor = object ? object->ce->destructor : NULL;
  85 
  86         if (destructor) {
  87                 zend_object *old_exception;
  88                 zval obj;
  89 
  90                 if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
  91                         if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
  92                                 /* Ensure that if we're calling a private function, we're allowed to do so.
  93                                  */
  94                                 if (object->ce != EG(scope)) {
  95                                         zend_class_entry *ce = object->ce;
  96 
  97                                         if (EG(current_execute_data)) {
  98                                                 zend_throw_error(NULL,
  99                                                         "Call to private %s::__destruct() from context '%s'",
 100                                                         ZSTR_VAL(ce->name),
 101                                                         EG(scope) ? ZSTR_VAL(EG(scope)->name) : "");
 102                                         } else {
 103                                                 zend_error(E_WARNING,
 104                                                         "Call to private %s::__destruct() from context '%s' during shutdown ignored",
 105                                                         ZSTR_VAL(ce->name),
 106                                                         EG(scope) ? ZSTR_VAL(EG(scope)->name) : "");
 107                                         }
 108                                         return;
 109                                 }
 110                         } else {
 111                                 /* Ensure that if we're calling a protected function, we're allowed to do so.
 112                                  */
 113                                 if (!zend_check_protected(zend_get_function_root_class(destructor), EG(scope))) {
 114                                         zend_class_entry *ce = object->ce;
 115 
 116                                         if (EG(current_execute_data)) {
 117                                                 zend_throw_error(NULL,
 118                                                         "Call to protected %s::__destruct() from context '%s'",
 119                                                         ZSTR_VAL(ce->name),
 120                                                         EG(scope) ? ZSTR_VAL(EG(scope)->name) : "");
 121                                         } else {
 122                                                 zend_error(E_WARNING,
 123                                                         "Call to protected %s::__destruct() from context '%s' during shutdown ignored",
 124                                                         ZSTR_VAL(ce->name),
 125                                                         EG(scope) ? ZSTR_VAL(EG(scope)->name) : "");
 126                                         }
 127                                         return;
 128                                 }
 129                         }
 130                 }
 131 
 132                 ZVAL_OBJ(&obj, object);
 133                 Z_ADDREF(obj);
 134 
 135                 /* Make sure that destructors are protected from previously thrown exceptions.
 136                  * For example, if an exception was thrown in a function and when the function's
 137                  * local variable destruction results in a destructor being called.
 138                  */
 139                 old_exception = NULL;
 140                 if (EG(exception)) {
 141                         if (EG(exception) == object) {
 142                                 zend_error_noreturn(E_CORE_ERROR, "Attempt to destruct pending exception");
 143                         } else {
 144                                 old_exception = EG(exception);
 145                                 EG(exception) = NULL;
 146                         }
 147                 }
 148                 zend_call_method_with_0_params(&obj, object->ce, &destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
 149                 if (old_exception) {
 150                         if (EG(exception)) {
 151                                 zend_exception_set_previous(EG(exception), old_exception);
 152                         } else {
 153                                 EG(exception) = old_exception;
 154                         }
 155                 }
 156                 zval_ptr_dtor(&obj);
 157         }
 158 }
 159 
 160 ZEND_API zend_object *zend_objects_new(zend_class_entry *ce)
 161 {
 162         zend_object *object = emalloc(sizeof(zend_object) + zend_object_properties_size(ce));
 163 
 164         zend_object_std_init(object, ce);
 165         object->handlers = &std_object_handlers;
 166         return object;
 167 }
 168 
 169 ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
 170 {
 171         if (old_object->ce->default_properties_count) {
 172                 zval *src = old_object->properties_table;
 173                 zval *dst = new_object->properties_table;
 174                 zval *end = src + old_object->ce->default_properties_count;
 175 
 176                 do {
 177                         i_zval_ptr_dtor(dst ZEND_FILE_LINE_CC);
 178                         ZVAL_COPY_VALUE(dst, src);
 179                         zval_add_ref(dst);
 180                         src++;
 181                         dst++;
 182                 } while (src != end);
 183         } else if (old_object->properties && !old_object->ce->clone) {
 184                 /* fast copy */
 185                 if (EXPECTED(old_object->handlers == &std_object_handlers)) {
 186                         if (EXPECTED(!(GC_FLAGS(old_object->properties) & IS_ARRAY_IMMUTABLE))) {
 187                                 GC_REFCOUNT(old_object->properties)++;
 188                         }
 189                         new_object->properties = old_object->properties;
 190                         return;
 191                 }
 192         }
 193 
 194         if (old_object->properties &&
 195             EXPECTED(zend_hash_num_elements(old_object->properties))) {
 196                 zval *prop, new_prop;
 197                 zend_ulong num_key;
 198                 zend_string *key;
 199 
 200                 if (!new_object->properties) {
 201                         ALLOC_HASHTABLE(new_object->properties);
 202                         zend_hash_init(new_object->properties, zend_hash_num_elements(old_object->properties), NULL, ZVAL_PTR_DTOR, 0);
 203                         zend_hash_real_init(new_object->properties, 0);
 204                 } else {
 205                         zend_hash_extend(new_object->properties, new_object->properties->nNumUsed + zend_hash_num_elements(old_object->properties), 0);
 206                 }
 207 
 208                 new_object->properties->u.v.flags |=
 209                         old_object->properties->u.v.flags & HASH_FLAG_HAS_EMPTY_IND;
 210 
 211                 ZEND_HASH_FOREACH_KEY_VAL(old_object->properties, num_key, key, prop) {
 212                         if (Z_TYPE_P(prop) == IS_INDIRECT) {
 213                                 ZVAL_INDIRECT(&new_prop, new_object->properties_table + (Z_INDIRECT_P(prop) - old_object->properties_table));
 214                         } else {
 215                                 ZVAL_COPY_VALUE(&new_prop, prop);
 216                                 zval_add_ref(&new_prop);
 217                         }
 218                         if (EXPECTED(key)) {
 219                                 _zend_hash_append(new_object->properties, key, &new_prop);
 220                         } else {
 221                                 zend_hash_index_add_new(new_object->properties, num_key, &new_prop);
 222                         }
 223                 } ZEND_HASH_FOREACH_END();
 224         }
 225 
 226         if (old_object->ce->clone) {
 227                 zval new_obj;
 228 
 229                 ZVAL_OBJ(&new_obj, new_object);
 230                 zval_copy_ctor(&new_obj);
 231                 zend_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
 232                 zval_ptr_dtor(&new_obj);
 233         }
 234 }
 235 
 236 ZEND_API zend_object *zend_objects_clone_obj(zval *zobject)
 237 {
 238         zend_object *old_object;
 239         zend_object *new_object;
 240 
 241         /* assume that create isn't overwritten, so when clone depends on the
 242          * overwritten one then it must itself be overwritten */
 243         old_object = Z_OBJ_P(zobject);
 244         new_object = zend_objects_new(old_object->ce);
 245 
 246         zend_objects_clone_members(new_object, old_object);
 247 
 248         return new_object;
 249 }
 250 
 251 /*
 252  * Local variables:
 253  * tab-width: 4
 254  * c-basic-offset: 4
 255  * indent-tabs-mode: t
 256  * End:
 257  */

/* [<][>][^][v][top][bottom][index][help] */