1/* 2 +----------------------------------------------------------------------+ 3 | Zend Engine | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1998-2013 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_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 54ZEND_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 62ZEND_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 69static 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 94static 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 124static 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 140static 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 161static 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 180static 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 194ZEND_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 264ZEND_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 289static 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 } else if(property_info->name[0] == '\0'){ 300 const char *class_name = NULL, *prop_name = NULL; 301 zend_unmangle_property_name(property_info->name, property_info->name_length, &class_name, &prop_name); 302 if(class_name) { 303 /* use unmangled name for protected properties */ 304 info.name = prop_name; 305 info.name_length = strlen(prop_name); 306 info.h = zend_get_hash_value(info.name, info.name_length+1); 307 property_info = &info; 308 } 309 } 310 if (!zobj->guards) { 311 ALLOC_HASHTABLE(zobj->guards); 312 zend_hash_init(zobj->guards, 0, NULL, NULL, 0); 313 } else if (zend_hash_quick_find(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void **) pguard) == SUCCESS) { 314 return SUCCESS; 315 } 316 stub.in_get = 0; 317 stub.in_set = 0; 318 stub.in_unset = 0; 319 stub.in_isset = 0; 320 return zend_hash_quick_add(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard); 321} 322/* }}} */ 323 324zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ 325{ 326 zend_object *zobj; 327 zval *tmp_member = NULL; 328 zval **retval; 329 zval *rv = NULL; 330 zend_property_info *property_info; 331 int silent; 332 333 silent = (type == BP_VAR_IS); 334 zobj = Z_OBJ_P(object); 335 336 if (Z_TYPE_P(member) != IS_STRING) { 337 ALLOC_ZVAL(tmp_member); 338 *tmp_member = *member; 339 INIT_PZVAL(tmp_member); 340 zval_copy_ctor(tmp_member); 341 convert_to_string(tmp_member); 342 member = tmp_member; 343 } 344 345#if DEBUG_OBJECT_HANDLERS 346 fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member)); 347#endif 348 349 /* make zend_get_property_info silent if we have getter - we may want to use it */ 350 property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC); 351 352 if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { 353 zend_guard *guard = NULL; 354 355 if (zobj->ce->__get && 356 zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && 357 !guard->in_get) { 358 /* have getter - try with it! */ 359 Z_ADDREF_P(object); 360 if (PZVAL_IS_REF(object)) { 361 SEPARATE_ZVAL(&object); 362 } 363 guard->in_get = 1; /* prevent circular getting */ 364 rv = zend_std_call_getter(object, member TSRMLS_CC); 365 guard->in_get = 0; 366 367 if (rv) { 368 retval = &rv; 369 if (!Z_ISREF_P(rv) && 370 (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)) { 371 if (Z_REFCOUNT_P(rv) > 0) { 372 zval *tmp = rv; 373 374 ALLOC_ZVAL(rv); 375 *rv = *tmp; 376 zval_copy_ctor(rv); 377 Z_UNSET_ISREF_P(rv); 378 Z_SET_REFCOUNT_P(rv, 0); 379 } 380 if (Z_TYPE_P(rv) != IS_OBJECT) { 381 zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", zobj->ce->name, Z_STRVAL_P(member)); 382 } 383 } 384 } else { 385 retval = &EG(uninitialized_zval_ptr); 386 } 387 if (EXPECTED(*retval != object)) { 388 zval_ptr_dtor(&object); 389 } else { 390 Z_DELREF_P(object); 391 } 392 } else { 393 if (zobj->ce->__get && guard && guard->in_get == 1) { 394 if (Z_STRVAL_P(member)[0] == '\0') { 395 if (Z_STRLEN_P(member) == 0) { 396 zend_error(E_ERROR, "Cannot access empty property"); 397 } else { 398 zend_error(E_ERROR, "Cannot access property started with '\\0'"); 399 } 400 } 401 } 402 if (!silent) { 403 zend_error(E_NOTICE,"Undefined property: %s::$%s", zobj->ce->name, Z_STRVAL_P(member)); 404 } 405 retval = &EG(uninitialized_zval_ptr); 406 } 407 } 408 if (tmp_member) { 409 Z_ADDREF_PP(retval); 410 zval_ptr_dtor(&tmp_member); 411 Z_DELREF_PP(retval); 412 } 413 return *retval; 414} 415/* }}} */ 416 417static void zend_std_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */ 418{ 419 zend_object *zobj; 420 zval *tmp_member = NULL; 421 zval **variable_ptr; 422 zend_property_info *property_info; 423 424 zobj = Z_OBJ_P(object); 425 426 if (Z_TYPE_P(member) != IS_STRING) { 427 ALLOC_ZVAL(tmp_member); 428 *tmp_member = *member; 429 INIT_PZVAL(tmp_member); 430 zval_copy_ctor(tmp_member); 431 convert_to_string(tmp_member); 432 member = tmp_member; 433 } 434 435 property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__set != NULL) TSRMLS_CC); 436 437 if (property_info && zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) { 438 /* if we already have this value there, we don't actually need to do anything */ 439 if (*variable_ptr != value) { 440 /* if we are assigning reference, we shouldn't move it, but instead assign variable 441 to the same pointer */ 442 if (PZVAL_IS_REF(*variable_ptr)) { 443 zval garbage = **variable_ptr; /* old value should be destroyed */ 444 445 /* To check: can't *variable_ptr be some system variable like error_zval here? */ 446 Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value); 447 (*variable_ptr)->value = value->value; 448 if (Z_REFCOUNT_P(value) > 0) { 449 zval_copy_ctor(*variable_ptr); 450 } else { 451 efree(value); 452 } 453 zval_dtor(&garbage); 454 } else { 455 zval *garbage = *variable_ptr; 456 457 /* if we assign referenced variable, we should separate it */ 458 Z_ADDREF_P(value); 459 if (PZVAL_IS_REF(value)) { 460 SEPARATE_ZVAL(&value); 461 } 462 *variable_ptr = value; 463 zval_ptr_dtor(&garbage); 464 } 465 } 466 } else { 467 zend_guard *guard = NULL; 468 469 if (zobj->ce->__set && 470 zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && 471 !guard->in_set) { 472 Z_ADDREF_P(object); 473 if (PZVAL_IS_REF(object)) { 474 SEPARATE_ZVAL(&object); 475 } 476 guard->in_set = 1; /* prevent circular setting */ 477 if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) { 478 /* for now, just ignore it - __set should take care of warnings, etc. */ 479 } 480 guard->in_set = 0; 481 zval_ptr_dtor(&object); 482 } else if (property_info) { 483 zval **foo; 484 485 /* if we assign referenced variable, we should separate it */ 486 Z_ADDREF_P(value); 487 if (PZVAL_IS_REF(value)) { 488 SEPARATE_ZVAL(&value); 489 } 490 zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void **) &foo); 491 } else if (zobj->ce->__set && guard && guard->in_set == 1) { 492 if (Z_STRVAL_P(member)[0] == '\0') { 493 if (Z_STRLEN_P(member) == 0) { 494 zend_error(E_ERROR, "Cannot access empty property"); 495 } else { 496 zend_error(E_ERROR, "Cannot access property started with '\\0'"); 497 } 498 } 499 } 500 } 501 502 if (tmp_member) { 503 zval_ptr_dtor(&tmp_member); 504 } 505} 506/* }}} */ 507 508zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */ 509{ 510 zend_class_entry *ce = Z_OBJCE_P(object); 511 zval *retval; 512 513 if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) { 514 if(offset == NULL) { 515 /* [] construct */ 516 ALLOC_INIT_ZVAL(offset); 517 } else { 518 SEPARATE_ARG_IF_REF(offset); 519 } 520 zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset); 521 522 zval_ptr_dtor(&offset); 523 524 if (!retval) { 525 if (!EG(exception)) { 526 zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); 527 } 528 return 0; 529 } 530 531 /* Undo PZVAL_LOCK() */ 532 Z_DELREF_P(retval); 533 534 return retval; 535 } else { 536 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); 537 return 0; 538 } 539} 540/* }}} */ 541 542static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */ 543{ 544 zend_class_entry *ce = Z_OBJCE_P(object); 545 546 if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) { 547 if (!offset) { 548 ALLOC_INIT_ZVAL(offset); 549 } else { 550 SEPARATE_ARG_IF_REF(offset); 551 } 552 zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value); 553 zval_ptr_dtor(&offset); 554 } else { 555 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); 556 } 557} 558/* }}} */ 559 560static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */ 561{ 562 zend_class_entry *ce = Z_OBJCE_P(object); 563 zval *retval; 564 int result; 565 566 if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) { 567 SEPARATE_ARG_IF_REF(offset); 568 zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset); 569 if (retval) { 570 result = i_zend_is_true(retval); 571 zval_ptr_dtor(&retval); 572 if (check_empty && result && !EG(exception)) { 573 zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset); 574 if (retval) { 575 result = i_zend_is_true(retval); 576 zval_ptr_dtor(&retval); 577 } 578 } 579 } else { 580 result = 0; 581 } 582 zval_ptr_dtor(&offset); 583 } else { 584 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); 585 return 0; 586 } 587 return result; 588} 589/* }}} */ 590 591static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */ 592{ 593 zend_object *zobj; 594 zval tmp_member; 595 zval **retval; 596 zend_property_info *property_info; 597 598 zobj = Z_OBJ_P(object); 599 600 if (Z_TYPE_P(member) != IS_STRING) { 601 tmp_member = *member; 602 zval_copy_ctor(&tmp_member); 603 convert_to_string(&tmp_member); 604 member = &tmp_member; 605 } 606 607#if DEBUG_OBJECT_HANDLERS 608 fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member)); 609#endif 610 611 property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC); 612 613 if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { 614 zval *new_zval; 615 zend_guard *guard; 616 617 if (!zobj->ce->__get || 618 zend_get_property_guard(zobj, property_info, member, &guard) != SUCCESS || 619 (property_info && guard->in_get)) { 620 /* we don't have access controls - will just add it */ 621 new_zval = &EG(uninitialized_zval); 622 623/* zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */ 624 Z_ADDREF_P(new_zval); 625 zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval); 626 } else { 627 /* we do have getter - fail and let it try again with usual get/set */ 628 retval = NULL; 629 } 630 } 631 if (member == &tmp_member) { 632 zval_dtor(member); 633 } 634 return retval; 635} 636/* }}} */ 637 638static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */ 639{ 640 zend_object *zobj; 641 zval *tmp_member = NULL; 642 zend_property_info *property_info; 643 644 zobj = Z_OBJ_P(object); 645 646 if (Z_TYPE_P(member) != IS_STRING) { 647 ALLOC_ZVAL(tmp_member); 648 *tmp_member = *member; 649 INIT_PZVAL(tmp_member); 650 zval_copy_ctor(tmp_member); 651 convert_to_string(tmp_member); 652 member = tmp_member; 653 } 654 655 property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__unset != NULL) TSRMLS_CC); 656 657 if (!property_info || zend_hash_quick_del(zobj->properties, property_info->name, property_info->name_length+1, property_info->h) == FAILURE) { 658 zend_guard *guard = NULL; 659 660 if (zobj->ce->__unset && 661 zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && 662 !guard->in_unset) { 663 /* have unseter - try with it! */ 664 Z_ADDREF_P(object); 665 if (PZVAL_IS_REF(object)) { 666 SEPARATE_ZVAL(&object); 667 } 668 guard->in_unset = 1; /* prevent circular unsetting */ 669 zend_std_call_unsetter(object, member TSRMLS_CC); 670 guard->in_unset = 0; 671 zval_ptr_dtor(&object); 672 } else if (zobj->ce->__unset && guard && guard->in_unset == 1) { 673 if (Z_STRVAL_P(member)[0] == '\0') { 674 if (Z_STRLEN_P(member) == 0) { 675 zend_error(E_ERROR, "Cannot access empty property"); 676 } else { 677 zend_error(E_ERROR, "Cannot access property started with '\\0'"); 678 } 679 } 680 } 681 } 682 683 if (tmp_member) { 684 zval_ptr_dtor(&tmp_member); 685 } 686} 687/* }}} */ 688 689static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */ 690{ 691 zend_class_entry *ce = Z_OBJCE_P(object); 692 693 if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) { 694 SEPARATE_ARG_IF_REF(offset); 695 zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", NULL, offset); 696 zval_ptr_dtor(&offset); 697 } else { 698 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); 699 } 700} 701/* }}} */ 702 703ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ 704{ 705 zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function; 706 zval *method_name_ptr, *method_args_ptr; 707 zval *method_result_ptr = NULL; 708 zend_class_entry *ce = Z_OBJCE_P(this_ptr); 709 710 ALLOC_ZVAL(method_args_ptr); 711 INIT_PZVAL(method_args_ptr); 712 array_init_size(method_args_ptr, ZEND_NUM_ARGS()); 713 714 if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) { 715 zval_dtor(method_args_ptr); 716 zend_error(E_ERROR, "Cannot get arguments for __call"); 717 RETURN_FALSE; 718 } 719 720 ALLOC_ZVAL(method_name_ptr); 721 INIT_PZVAL(method_name_ptr); 722 ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */ 723 724 /* __call handler is called with two arguments: 725 method name 726 array of method parameters 727 728 */ 729 zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr); 730 731 if (method_result_ptr) { 732 if (Z_ISREF_P(method_result_ptr) || Z_REFCOUNT_P(method_result_ptr) > 1) { 733 RETVAL_ZVAL(method_result_ptr, 1, 1); 734 } else { 735 RETVAL_ZVAL(method_result_ptr, 0, 1); 736 } 737 } 738 739 /* now destruct all auxiliaries */ 740 zval_ptr_dtor(&method_args_ptr); 741 zval_ptr_dtor(&method_name_ptr); 742 743 /* destruct the function also, then - we have allocated it in get_method */ 744 efree(func); 745} 746/* }}} */ 747 748/* Ensures that we're allowed to call a private method. 749 * Returns the function address that should be called, or NULL 750 * if no such function exists. 751 */ 752static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */ 753{ 754 if (!ce) { 755 return 0; 756 } 757 758 /* We may call a private function if: 759 * 1. The class of our object is the same as the scope, and the private 760 * function (EX(fbc)) has the same scope. 761 * 2. One of our parent classes are the same as the scope, and it contains 762 * a private function with the same name that has the same scope. 763 */ 764 if (fbc->common.scope == ce && EG(scope) == ce) { 765 /* rule #1 checks out ok, allow the function call */ 766 return fbc; 767 } 768 769 770 /* Check rule #2 */ 771 ce = ce->parent; 772 while (ce) { 773 if (ce == EG(scope)) { 774 if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==SUCCESS 775 && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE 776 && fbc->common.scope == EG(scope)) { 777 return fbc; 778 } 779 break; 780 } 781 ce = ce->parent; 782 } 783 return NULL; 784} 785/* }}} */ 786 787ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */ 788{ 789 return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen TSRMLS_CC) != NULL; 790} 791/* }}} */ 792 793/* Ensures that we're allowed to call a protected method. 794 */ 795ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) /* {{{ */ 796{ 797 zend_class_entry *fbc_scope = ce; 798 799 /* Is the context that's calling the function, the same as one of 800 * the function's parents? 801 */ 802 while (fbc_scope) { 803 if (fbc_scope==scope) { 804 return 1; 805 } 806 fbc_scope = fbc_scope->parent; 807 } 808 809 /* Is the function's scope the same as our current object context, 810 * or any of the parents of our context? 811 */ 812 while (scope) { 813 if (scope==ce) { 814 return 1; 815 } 816 scope = scope->parent; 817 } 818 return 0; 819} 820/* }}} */ 821 822static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc) /* {{{ */ 823{ 824 return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope; 825} 826/* }}} */ 827 828static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */ 829{ 830 zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function)); 831 call_user_call->type = ZEND_INTERNAL_FUNCTION; 832 call_user_call->module = ce->module; 833 call_user_call->handler = zend_std_call_user_call; 834 call_user_call->arg_info = NULL; 835 call_user_call->num_args = 0; 836 call_user_call->scope = ce; 837 call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; 838 call_user_call->function_name = estrndup(method_name, method_len); 839 call_user_call->pass_rest_by_reference = 0; 840 call_user_call->return_reference = ZEND_RETURN_VALUE; 841 842 return (union _zend_function *)call_user_call; 843} 844/* }}} */ 845 846static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */ 847{ 848 zend_object *zobj; 849 zend_function *fbc; 850 char *lc_method_name; 851 zval *object = *object_ptr; 852 ALLOCA_FLAG(use_heap) 853 854 lc_method_name = do_alloca(method_len+1, use_heap); 855 /* Create a zend_copy_str_tolower(dest, src, src_length); */ 856 zend_str_tolower_copy(lc_method_name, method_name, method_len); 857 858 zobj = Z_OBJ_P(object); 859 if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) { 860 free_alloca(lc_method_name, use_heap); 861 if (zobj->ce->__call) { 862 return zend_get_user_call_function(zobj->ce, method_name, method_len); 863 } else { 864 return NULL; 865 } 866 } 867 868 /* Check access level */ 869 if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) { 870 zend_function *updated_fbc; 871 872 /* Ensure that if we're calling a private function, we're allowed to do so. 873 * If we're not and __call() handler exists, invoke it, otherwise error out. 874 */ 875 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); 876 if (updated_fbc) { 877 fbc = updated_fbc; 878 } else { 879 if (zobj->ce->__call) { 880 fbc = zend_get_user_call_function(zobj->ce, method_name, method_len); 881 } else { 882 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 : ""); 883 } 884 } 885 } else { 886 /* Ensure that we haven't overridden a private function and end up calling 887 * the overriding public function... 888 */ 889 if (EG(scope) && 890 is_derived_class(fbc->common.scope, EG(scope)) && 891 fbc->op_array.fn_flags & ZEND_ACC_CHANGED) { 892 zend_function *priv_fbc; 893 894 if (zend_hash_find(&EG(scope)->function_table, lc_method_name, method_len+1, (void **) &priv_fbc)==SUCCESS 895 && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE 896 && priv_fbc->common.scope == EG(scope)) { 897 fbc = priv_fbc; 898 } 899 } 900 if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) { 901 /* Ensure that if we're calling a protected function, we're allowed to do so. 902 * If we're not and __call() handler exists, invoke it, otherwise error out. 903 */ 904 if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) { 905 if (zobj->ce->__call) { 906 fbc = zend_get_user_call_function(zobj->ce, method_name, method_len); 907 } else { 908 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 : ""); 909 } 910 } 911 } 912 } 913 914 free_alloca(lc_method_name, use_heap); 915 return fbc; 916} 917/* }}} */ 918 919ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ 920{ 921 zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function; 922 zval *method_name_ptr, *method_args_ptr; 923 zval *method_result_ptr = NULL; 924 zend_class_entry *ce = EG(scope); 925 926 ALLOC_ZVAL(method_args_ptr); 927 INIT_PZVAL(method_args_ptr); 928 array_init_size(method_args_ptr, ZEND_NUM_ARGS()); 929 930 if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) { 931 zval_dtor(method_args_ptr); 932 zend_error(E_ERROR, "Cannot get arguments for " ZEND_CALLSTATIC_FUNC_NAME); 933 RETURN_FALSE; 934 } 935 936 ALLOC_ZVAL(method_name_ptr); 937 INIT_PZVAL(method_name_ptr); 938 ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */ 939 940 /* __callStatic handler is called with two arguments: 941 method name 942 array of method parameters 943 */ 944 zend_call_method_with_2_params(NULL, ce, &ce->__callstatic, ZEND_CALLSTATIC_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr); 945 946 if (method_result_ptr) { 947 if (Z_ISREF_P(method_result_ptr) || Z_REFCOUNT_P(method_result_ptr) > 1) { 948 RETVAL_ZVAL(method_result_ptr, 1, 1); 949 } else { 950 RETVAL_ZVAL(method_result_ptr, 0, 1); 951 } 952 } 953 954 /* now destruct all auxiliaries */ 955 zval_ptr_dtor(&method_args_ptr); 956 zval_ptr_dtor(&method_name_ptr); 957 958 /* destruct the function also, then - we have allocated it in get_method */ 959 efree(func); 960} 961/* }}} */ 962 963static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */ 964{ 965 zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function)); 966 callstatic_user_call->type = ZEND_INTERNAL_FUNCTION; 967 callstatic_user_call->module = ce->module; 968 callstatic_user_call->handler = zend_std_callstatic_user_call; 969 callstatic_user_call->arg_info = NULL; 970 callstatic_user_call->num_args = 0; 971 callstatic_user_call->scope = ce; 972 callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER; 973 callstatic_user_call->function_name = estrndup(method_name, method_len); 974 callstatic_user_call->pass_rest_by_reference = 0; 975 callstatic_user_call->return_reference = ZEND_RETURN_VALUE; 976 977 return (zend_function *)callstatic_user_call; 978} 979/* }}} */ 980 981/* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */ 982 983ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */ 984{ 985 zend_function *fbc = NULL; 986 char *lc_class_name, *lc_function_name = NULL; 987 988 lc_function_name = zend_str_tolower_dup(function_name_strval, function_name_strlen); 989 990 if (function_name_strlen == ce->name_length && ce->constructor) { 991 lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length); 992 /* Only change the method to the constructor if the constructor isn't called __construct 993 * we check for __ so we can be binary safe for lowering, we should use ZEND_CONSTRUCTOR_FUNC_NAME 994 */ 995 if (!memcmp(lc_class_name, lc_function_name, function_name_strlen) && memcmp(ce->constructor->common.function_name, "__", sizeof("__") - 1)) { 996 fbc = ce->constructor; 997 } 998 efree(lc_class_name); 999 } 1000 if (!fbc && zend_hash_find(&ce->function_table, lc_function_name, function_name_strlen+1, (void **) &fbc)==FAILURE) { 1001 efree(lc_function_name); 1002 1003 if (ce->__call && 1004 EG(This) && 1005 Z_OBJ_HT_P(EG(This))->get_class_entry && 1006 instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { 1007 return zend_get_user_call_function(ce, function_name_strval, function_name_strlen); 1008 } else if (ce->__callstatic) { 1009 return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); 1010 } else { 1011 return NULL; 1012 } 1013 } 1014 efree(lc_function_name); 1015 1016#if MBO_0 1017 /* right now this function is used for non static method lookup too */ 1018 /* Is the function static */ 1019 if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { 1020 zend_error(E_ERROR, "Cannot call non static method %s::%s() without object", ZEND_FN_SCOPE_NAME(fbc), fbc->common.function_name); 1021 } 1022#endif 1023 if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) { 1024 /* No further checks necessary, most common case */ 1025 } else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) { 1026 zend_function *updated_fbc; 1027 1028 /* Ensure that if we're calling a private function, we're allowed to do so. 1029 */ 1030 updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC); 1031 if (updated_fbc) { 1032 fbc = updated_fbc; 1033 } else { 1034 if (ce->__callstatic) { 1035 return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); 1036 } 1037 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 : ""); 1038 } 1039 } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) { 1040 /* Ensure that if we're calling a protected function, we're allowed to do so. 1041 */ 1042 if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) { 1043 if (ce->__callstatic) { 1044 return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); 1045 } 1046 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 : ""); 1047 } 1048 } 1049 1050 return fbc; 1051} 1052/* }}} */ 1053 1054ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC) /* {{{ */ 1055{ 1056 zval **retval = NULL; 1057 zend_class_entry *tmp_ce = ce; 1058 zend_property_info *property_info; 1059 zend_property_info std_property_info; 1060 1061 if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE) { 1062 std_property_info.flags = ZEND_ACC_PUBLIC; 1063 std_property_info.name = property_name; 1064 std_property_info.name_length = property_name_len; 1065 std_property_info.h = zend_get_hash_value(std_property_info.name, std_property_info.name_length+1); 1066 std_property_info.ce = ce; 1067 property_info = &std_property_info; 1068 } 1069 1070#if DEBUG_OBJECT_HANDLERS 1071 zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags)); 1072#endif 1073 1074 if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) { 1075 if (!silent) { 1076 zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name); 1077 } 1078 return NULL; 1079 } 1080 1081 zend_update_class_constants(tmp_ce TSRMLS_CC); 1082 1083 zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval); 1084 1085 if (!retval) { 1086 if (silent) { 1087 return NULL; 1088 } else { 1089 zend_error(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); 1090 } 1091 } 1092 1093 return retval; 1094} 1095/* }}} */ 1096 1097ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC) /* {{{ */ 1098{ 1099 zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name); 1100 return 0; 1101} 1102/* }}} */ 1103 1104ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC) /* {{{ */ 1105{ 1106 zend_object *zobj = Z_OBJ_P(object); 1107 zend_function *constructor = zobj->ce->constructor; 1108 1109 if (constructor) { 1110 if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) { 1111 /* No further checks necessary */ 1112 } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) { 1113 /* Ensure that if we're calling a private function, we're allowed to do so. 1114 */ 1115 if (constructor->common.scope != EG(scope)) { 1116 if (EG(scope)) { 1117 zend_error(E_ERROR, "Call to private %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 private %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name); 1120 } 1121 } 1122 } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) { 1123 /* Ensure that if we're calling a protected function, we're allowed to do so. 1124 * Constructors only have prototype if they are defined by an interface but 1125 * it is the compilers responsibility to take care of the prototype. 1126 */ 1127 if (!zend_check_protected(zend_get_function_root_class(constructor), EG(scope))) { 1128 if (EG(scope)) { 1129 zend_error(E_ERROR, "Call to protected %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name); 1130 } else { 1131 zend_error(E_ERROR, "Call to protected %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name); 1132 } 1133 } 1134 } 1135 } 1136 1137 return constructor; 1138} 1139/* }}} */ 1140 1141int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC); 1142 1143static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */ 1144{ 1145 zend_object *zobj1, *zobj2; 1146 1147 zobj1 = Z_OBJ_P(o1); 1148 zobj2 = Z_OBJ_P(o2); 1149 1150 if (zobj1->ce != zobj2->ce) { 1151 return 1; /* different classes */ 1152 } 1153 return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC); 1154} 1155/* }}} */ 1156 1157static int zend_std_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */ 1158{ 1159 zend_object *zobj; 1160 int result; 1161 zval **value; 1162 zval *tmp_member = NULL; 1163 zend_property_info *property_info; 1164 1165 zobj = Z_OBJ_P(object); 1166 1167 if (Z_TYPE_P(member) != IS_STRING) { 1168 ALLOC_ZVAL(tmp_member); 1169 *tmp_member = *member; 1170 INIT_PZVAL(tmp_member); 1171 zval_copy_ctor(tmp_member); 1172 convert_to_string(tmp_member); 1173 member = tmp_member; 1174 } 1175 1176#if DEBUG_OBJECT_HANDLERS 1177 fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member)); 1178#endif 1179 1180 property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC); 1181 1182 if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) { 1183 zend_guard *guard; 1184 1185 result = 0; 1186 if ((has_set_exists != 2) && 1187 zobj->ce->__isset && 1188 zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && 1189 !guard->in_isset) { 1190 zval *rv; 1191 1192 /* have issetter - try with it! */ 1193 Z_ADDREF_P(object); 1194 if (PZVAL_IS_REF(object)) { 1195 SEPARATE_ZVAL(&object); 1196 } 1197 guard->in_isset = 1; /* prevent circular getting */ 1198 rv = zend_std_call_issetter(object, member TSRMLS_CC); 1199 if (rv) { 1200 result = zend_is_true(rv); 1201 zval_ptr_dtor(&rv); 1202 if (has_set_exists && result) { 1203 if (!EG(exception) && zobj->ce->__get && !guard->in_get) { 1204 guard->in_get = 1; 1205 rv = zend_std_call_getter(object, member TSRMLS_CC); 1206 guard->in_get = 0; 1207 if (rv) { 1208 Z_ADDREF_P(rv); 1209 result = i_zend_is_true(rv); 1210 zval_ptr_dtor(&rv); 1211 } else { 1212 result = 0; 1213 } 1214 } else { 1215 result = 0; 1216 } 1217 } 1218 } 1219 guard->in_isset = 0; 1220 zval_ptr_dtor(&object); 1221 } 1222 } else { 1223 switch (has_set_exists) { 1224 case 0: 1225 result = (Z_TYPE_PP(value) != IS_NULL); 1226 break; 1227 default: 1228 result = zend_is_true(*value); 1229 break; 1230 case 2: 1231 result = 1; 1232 break; 1233 } 1234 } 1235 1236 if (tmp_member) { 1237 zval_ptr_dtor(&tmp_member); 1238 } 1239 return result; 1240} 1241/* }}} */ 1242 1243zend_class_entry *zend_std_object_get_class(const zval *object TSRMLS_DC) /* {{{ */ 1244{ 1245 zend_object *zobj; 1246 zobj = Z_OBJ_P(object); 1247 1248 return zobj->ce; 1249} 1250/* }}} */ 1251 1252int zend_std_object_get_class_name(const zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) /* {{{ */ 1253{ 1254 zend_object *zobj; 1255 zend_class_entry *ce; 1256 zobj = Z_OBJ_P(object); 1257 1258 if (parent) { 1259 if (!zobj->ce->parent) { 1260 return FAILURE; 1261 } 1262 ce = zobj->ce->parent; 1263 } else { 1264 ce = zobj->ce; 1265 } 1266 1267 *class_name_len = ce->name_length; 1268 *class_name = estrndup(ce->name, ce->name_length); 1269 return SUCCESS; 1270} 1271/* }}} */ 1272 1273ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */ 1274{ 1275 zval *retval; 1276 zend_class_entry *ce; 1277 1278 switch (type) { 1279 case IS_STRING: 1280 ce = Z_OBJCE_P(readobj); 1281 if (ce->__tostring && 1282 (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) { 1283 if (EG(exception)) { 1284 if (retval) { 1285 zval_ptr_dtor(&retval); 1286 } 1287 EG(exception) = NULL; 1288 zend_error(E_ERROR, "Method %s::__toString() must not throw an exception", ce->name); 1289 return FAILURE; 1290 } 1291 if (Z_TYPE_P(retval) == IS_STRING) { 1292 INIT_PZVAL(writeobj); 1293 if (readobj == writeobj) { 1294 zval_dtor(readobj); 1295 } 1296 ZVAL_ZVAL(writeobj, retval, 1, 1); 1297 if (Z_TYPE_P(writeobj) != type) { 1298 convert_to_explicit_type(writeobj, type); 1299 } 1300 return SUCCESS; 1301 } else { 1302 zval_ptr_dtor(&retval); 1303 INIT_PZVAL(writeobj); 1304 if (readobj == writeobj) { 1305 zval_dtor(readobj); 1306 } 1307 ZVAL_EMPTY_STRING(writeobj); 1308 zend_error(E_RECOVERABLE_ERROR, "Method %s::__toString() must return a string value", ce->name); 1309 return SUCCESS; 1310 } 1311 } 1312 return FAILURE; 1313 case IS_BOOL: 1314 INIT_PZVAL(writeobj); 1315 ZVAL_BOOL(writeobj, 1); 1316 return SUCCESS; 1317 case IS_LONG: 1318 ce = Z_OBJCE_P(readobj); 1319 zend_error(E_NOTICE, "Object of class %s could not be converted to int", ce->name); 1320 INIT_PZVAL(writeobj); 1321 if (readobj == writeobj) { 1322 zval_dtor(readobj); 1323 } 1324 ZVAL_LONG(writeobj, 1); 1325 return SUCCESS; 1326 case IS_DOUBLE: 1327 ce = Z_OBJCE_P(readobj); 1328 zend_error(E_NOTICE, "Object of class %s could not be converted to double", ce->name); 1329 INIT_PZVAL(writeobj); 1330 if (readobj == writeobj) { 1331 zval_dtor(readobj); 1332 } 1333 ZVAL_DOUBLE(writeobj, 1); 1334 return SUCCESS; 1335 default: 1336 INIT_PZVAL(writeobj); 1337 Z_TYPE_P(writeobj) = IS_NULL; 1338 break; 1339 } 1340 return FAILURE; 1341} 1342/* }}} */ 1343 1344int zend_std_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */ 1345{ 1346 zend_class_entry *ce; 1347 if (Z_TYPE_P(obj) != IS_OBJECT) { 1348 return FAILURE; 1349 } 1350 1351 ce = Z_OBJCE_P(obj); 1352 1353 if (zend_hash_find(&ce->function_table, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME), (void**)fptr_ptr) == FAILURE) { 1354 return FAILURE; 1355 } 1356 1357 *ce_ptr = ce; 1358 if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) { 1359 if (zobj_ptr) { 1360 *zobj_ptr = NULL; 1361 } 1362 } else { 1363 if (zobj_ptr) { 1364 *zobj_ptr = obj; 1365 } 1366 } 1367 return SUCCESS; 1368} 1369/* }}} */ 1370 1371ZEND_API zend_object_handlers std_object_handlers = { 1372 zend_objects_store_add_ref, /* add_ref */ 1373 zend_objects_store_del_ref, /* del_ref */ 1374 zend_objects_clone_obj, /* clone_obj */ 1375 1376 zend_std_read_property, /* read_property */ 1377 zend_std_write_property, /* write_property */ 1378 zend_std_read_dimension, /* read_dimension */ 1379 zend_std_write_dimension, /* write_dimension */ 1380 zend_std_get_property_ptr_ptr, /* get_property_ptr_ptr */ 1381 NULL, /* get */ 1382 NULL, /* set */ 1383 zend_std_has_property, /* has_property */ 1384 zend_std_unset_property, /* unset_property */ 1385 zend_std_has_dimension, /* has_dimension */ 1386 zend_std_unset_dimension, /* unset_dimension */ 1387 zend_std_get_properties, /* get_properties */ 1388 zend_std_get_method, /* get_method */ 1389 NULL, /* call_method */ 1390 zend_std_get_constructor, /* get_constructor */ 1391 zend_std_object_get_class, /* get_class_entry */ 1392 zend_std_object_get_class_name, /* get_class_name */ 1393 zend_std_compare_objects, /* compare_objects */ 1394 zend_std_cast_object_tostring, /* cast_object */ 1395 NULL, /* count_elements */ 1396 NULL, /* get_debug_info */ 1397 zend_std_get_closure, /* get_closure */ 1398}; 1399 1400/* 1401 * Local variables: 1402 * tab-width: 4 1403 * c-basic-offset: 4 1404 * indent-tabs-mode: t 1405 * End: 1406 */ 1407