2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
23 #include "zend_globals.h"
24 #include "zend_variables.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"
33 #define DEBUG_OBJECT_HANDLERS 0
35 #define Z_OBJ_P(zval_p) \
36 ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].bucket.obj.object))
38 #define Z_OBJ_PROTECT_RECURSION(zval_p) \
40 if (EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].apply_count++ >= 3) { \
41 zend_error(E_ERROR, "Nesting level too deep - recursive dependency?"); \
46 #define Z_OBJ_UNPROTECT_RECURSION(zval_p) \
47 EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].apply_count--
50 __X accessors explanation:
52 if we have __get and property that is not part of the properties array is
53 requested, we call __get handler. If it fails, we return uninitialized.
55 if we have __set and property that is not part of the properties array is
56 set, we call __set handler. If it fails, we do not change the array.
58 for both handlers above, when we are inside __get/__set, no further calls for
59 __get/__set for this property of this object will be made, to prevent endless
60 recursion and enable accessors to change properties array.
62 if we have __call and method which is not part of the class function table is
63 called, we cal __call handler.
66 ZEND_API
void rebuild_object_properties(zend_object
*zobj
) /* {{{ */
68 if (!zobj
->properties
) {
70 zend_property_info
*prop_info
;
71 zend_class_entry
*ce
= zobj
->ce
;
73 ALLOC_HASHTABLE(zobj
->properties
);
74 zend_hash_init(zobj
->properties
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
75 if (ce
->default_properties_count
) {
76 for (zend_hash_internal_pointer_reset_ex(&ce
->properties_info
, &pos
);
77 zend_hash_get_current_data_ex(&ce
->properties_info
, (void**)&prop_info
, &pos
) == SUCCESS
;
78 zend_hash_move_forward_ex(&ce
->properties_info
, &pos
)) {
79 if (/*prop_info->ce == ce &&*/
80 (prop_info
->flags
& ZEND_ACC_STATIC
) == 0 &&
81 prop_info
->offset
>= 0 &&
82 zobj
->properties_table
[prop_info
->offset
]) {
83 zend_hash_quick_add(zobj
->properties
, prop_info
->name
, prop_info
->name_length
+1, prop_info
->h
, (void**)&zobj
->properties_table
[prop_info
->offset
], sizeof(zval
*), (void**)&zobj
->properties_table
[prop_info
->offset
]);
86 while (ce
->parent
&& ce
->parent
->default_properties_count
) {
88 for (zend_hash_internal_pointer_reset_ex(&ce
->properties_info
, &pos
);
89 zend_hash_get_current_data_ex(&ce
->properties_info
, (void**)&prop_info
, &pos
) == SUCCESS
;
90 zend_hash_move_forward_ex(&ce
->properties_info
, &pos
)) {
91 if (prop_info
->ce
== ce
&&
92 (prop_info
->flags
& ZEND_ACC_STATIC
) == 0 &&
93 (prop_info
->flags
& ZEND_ACC_PRIVATE
) != 0 &&
94 prop_info
->offset
>= 0 &&
95 zobj
->properties_table
[prop_info
->offset
]) {
96 zend_hash_quick_add(zobj
->properties
, prop_info
->name
, prop_info
->name_length
+1, prop_info
->h
, (void**)&zobj
->properties_table
[prop_info
->offset
], sizeof(zval
*), (void**)&zobj
->properties_table
[prop_info
->offset
]);
105 ZEND_API HashTable
*zend_std_get_properties(zval
*object TSRMLS_DC
) /* {{{ */
108 zobj
= Z_OBJ_P(object
);
109 if (!zobj
->properties
) {
110 rebuild_object_properties(zobj
);
112 return zobj
->properties
;
116 ZEND_API HashTable
*zend_std_get_gc(zval
*object
, zval
***table
, int *n TSRMLS_DC
) /* {{{ */
118 if (Z_OBJ_HANDLER_P(object
, get_properties
) != zend_std_get_properties
) {
121 return Z_OBJ_HANDLER_P(object
, get_properties
)(object TSRMLS_CC
);
123 zend_object
*zobj
= Z_OBJ_P(object
);
125 if (zobj
->properties
) {
128 return zobj
->properties
;
130 *table
= zobj
->properties_table
;
131 *n
= zobj
->ce
->default_properties_count
;
138 ZEND_API HashTable
*zend_std_get_debug_info(zval
*object
, int *is_temp TSRMLS_DC
) /* {{{ */
141 return zend_std_get_properties(object TSRMLS_CC
);
145 static zval
*zend_std_call_getter(zval
*object
, zval
*member TSRMLS_DC
) /* {{{ */
148 zend_class_entry
*ce
= Z_OBJCE_P(object
);
150 /* __get handler is called with one argument:
153 it should return whether the call was successfull or not
156 SEPARATE_ARG_IF_REF(member
);
158 zend_call_method_with_1_params(&object
, ce
, &ce
->__get
, ZEND_GET_FUNC_NAME
, &retval
, member
);
160 zval_ptr_dtor(&member
);
170 static int zend_std_call_setter(zval
*object
, zval
*member
, zval
*value TSRMLS_DC
) /* {{{ */
174 zend_class_entry
*ce
= Z_OBJCE_P(object
);
176 SEPARATE_ARG_IF_REF(member
);
179 /* __set handler is called with two arguments:
183 it should return whether the call was successfull or not
185 zend_call_method_with_2_params(&object
, ce
, &ce
->__set
, ZEND_SET_FUNC_NAME
, &retval
, member
, value
);
187 zval_ptr_dtor(&member
);
188 zval_ptr_dtor(&value
);
191 result
= i_zend_is_true(retval
) ? SUCCESS
: FAILURE
;
192 zval_ptr_dtor(&retval
);
200 static void zend_std_call_unsetter(zval
*object
, zval
*member TSRMLS_DC
) /* {{{ */
202 zend_class_entry
*ce
= Z_OBJCE_P(object
);
204 /* __unset handler is called with one argument:
208 SEPARATE_ARG_IF_REF(member
);
210 zend_call_method_with_1_params(&object
, ce
, &ce
->__unset
, ZEND_UNSET_FUNC_NAME
, NULL
, member
);
212 zval_ptr_dtor(&member
);
216 static zval
*zend_std_call_issetter(zval
*object
, zval
*member TSRMLS_DC
) /* {{{ */
219 zend_class_entry
*ce
= Z_OBJCE_P(object
);
221 /* __isset handler is called with one argument:
224 it should return whether the property is set or not
227 SEPARATE_ARG_IF_REF(member
);
229 zend_call_method_with_1_params(&object
, ce
, &ce
->__isset
, ZEND_ISSET_FUNC_NAME
, &retval
, member
);
231 zval_ptr_dtor(&member
);
237 static zend_always_inline
int zend_verify_property_access(zend_property_info
*property_info
, zend_class_entry
*ce TSRMLS_DC
) /* {{{ */
239 switch (property_info
->flags
& ZEND_ACC_PPP_MASK
) {
240 case ZEND_ACC_PUBLIC
:
242 case ZEND_ACC_PROTECTED
:
243 return zend_check_protected(property_info
->ce
, EG(scope
));
244 case ZEND_ACC_PRIVATE
:
245 if ((ce
==EG(scope
) || property_info
->ce
== EG(scope
)) && EG(scope
)) {
256 static zend_always_inline zend_bool
is_derived_class(zend_class_entry
*child_class
, zend_class_entry
*parent_class
) /* {{{ */
258 child_class
= child_class
->parent
;
259 while (child_class
) {
260 if (child_class
== parent_class
) {
263 child_class
= child_class
->parent
;
270 static zend_always_inline
struct _zend_property_info
*zend_get_property_info_quick(zend_class_entry
*ce
, zval
*member
, int silent
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
272 zend_property_info
*property_info
;
273 zend_property_info
*scope_property_info
;
274 zend_bool denied_access
= 0;
277 if (key
&& (property_info
= CACHED_POLYMORPHIC_PTR(key
->cache_slot
, ce
)) != NULL
) {
278 return property_info
;
281 if (UNEXPECTED(Z_STRVAL_P(member
)[0] == '\0')) {
283 if (Z_STRLEN_P(member
) == 0) {
284 zend_error_noreturn(E_ERROR
, "Cannot access empty property");
286 zend_error_noreturn(E_ERROR
, "Cannot access property started with '\\0'");
291 property_info
= NULL
;
292 h
= key
? key
->hash_value
: zend_get_hash_value(Z_STRVAL_P(member
), Z_STRLEN_P(member
) + 1);
293 if (zend_hash_quick_find(&ce
->properties_info
, Z_STRVAL_P(member
), Z_STRLEN_P(member
)+1, h
, (void **) &property_info
)==SUCCESS
) {
294 if (UNEXPECTED((property_info
->flags
& ZEND_ACC_SHADOW
) != 0)) {
295 /* if it's a shadow - go to access it's private */
296 property_info
= NULL
;
298 if (EXPECTED(zend_verify_property_access(property_info
, ce TSRMLS_CC
) != 0)) {
299 if (EXPECTED((property_info
->flags
& ZEND_ACC_CHANGED
) != 0)
300 && EXPECTED(!(property_info
->flags
& ZEND_ACC_PRIVATE
))) {
301 /* We still need to make sure that we're not in a context
302 * where the right property is a different 'statically linked' private
303 * continue checking below...
306 if (UNEXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) != 0) && !silent
) {
307 zend_error(E_STRICT
, "Accessing static property %s::$%s as non static", ce
->name
, Z_STRVAL_P(member
));
310 CACHE_POLYMORPHIC_PTR(key
->cache_slot
, ce
, property_info
);
312 return property_info
;
315 /* Try to look in the scope instead */
322 && is_derived_class(ce
, EG(scope
))
323 && zend_hash_quick_find(&EG(scope
)->properties_info
, Z_STRVAL_P(member
), Z_STRLEN_P(member
)+1, h
, (void **) &scope_property_info
)==SUCCESS
324 && scope_property_info
->flags
& ZEND_ACC_PRIVATE
) {
326 CACHE_POLYMORPHIC_PTR(key
->cache_slot
, ce
, scope_property_info
);
328 return scope_property_info
;
329 } else if (property_info
) {
330 if (UNEXPECTED(denied_access
!= 0)) {
331 /* Information was available, but we were denied access. Error out. */
333 zend_error_noreturn(E_ERROR
, "Cannot access %s property %s::$%s", zend_visibility_string(property_info
->flags
), ce
->name
, Z_STRVAL_P(member
));
337 /* fall through, return property_info... */
339 CACHE_POLYMORPHIC_PTR(key
->cache_slot
, ce
, property_info
);
343 EG(std_property_info
).flags
= ZEND_ACC_PUBLIC
;
344 EG(std_property_info
).name
= Z_STRVAL_P(member
);
345 EG(std_property_info
).name_length
= Z_STRLEN_P(member
);
346 EG(std_property_info
).h
= h
;
347 EG(std_property_info
).ce
= ce
;
348 EG(std_property_info
).offset
= -1;
349 property_info
= &EG(std_property_info
);
351 return property_info
;
355 ZEND_API
struct _zend_property_info
*zend_get_property_info(zend_class_entry
*ce
, zval
*member
, int silent TSRMLS_DC
) /* {{{ */
357 return zend_get_property_info_quick(ce
, member
, silent
, NULL TSRMLS_CC
);
361 ZEND_API
int zend_check_property_access(zend_object
*zobj
, const char *prop_info_name
, int prop_info_name_len TSRMLS_DC
) /* {{{ */
363 zend_property_info
*property_info
;
364 const char *class_name
, *prop_name
;
367 zend_unmangle_property_name(prop_info_name
, prop_info_name_len
, &class_name
, &prop_name
);
368 ZVAL_STRING(&member
, prop_name
, 0);
369 property_info
= zend_get_property_info_quick(zobj
->ce
, &member
, 1, NULL TSRMLS_CC
);
370 if (!property_info
) {
373 if (class_name
&& class_name
[0] != '*') {
374 if (!(property_info
->flags
& ZEND_ACC_PRIVATE
)) {
375 /* we we're looking for a private prop but found a non private one of the same name */
377 } else if (strcmp(prop_info_name
+1, property_info
->name
+1)) {
378 /* we we're looking for a private prop but found a private one of the same name but another class */
382 return zend_verify_property_access(property_info
, zobj
->ce TSRMLS_CC
) ? SUCCESS
: FAILURE
;
386 static int zend_get_property_guard(zend_object
*zobj
, zend_property_info
*property_info
, zval
*member
, zend_guard
**pguard
) /* {{{ */
388 zend_property_info info
;
391 if (!property_info
) {
392 property_info
= &info
;
393 info
.name
= Z_STRVAL_P(member
);
394 info
.name_length
= Z_STRLEN_P(member
);
395 info
.h
= zend_get_hash_value(Z_STRVAL_P(member
), Z_STRLEN_P(member
) + 1);
396 } else if(property_info
->name
[0] == '\0'){
397 const char *class_name
= NULL
, *prop_name
= NULL
;
398 zend_unmangle_property_name(property_info
->name
, property_info
->name_length
, &class_name
, &prop_name
);
400 /* use unmangled name for protected properties */
401 info
.name
= prop_name
;
402 info
.name_length
= strlen(prop_name
);
403 info
.h
= zend_get_hash_value(info
.name
, info
.name_length
+1);
404 property_info
= &info
;
408 ALLOC_HASHTABLE(zobj
->guards
);
409 zend_hash_init(zobj
->guards
, 0, NULL
, NULL
, 0);
410 } else if (zend_hash_quick_find(zobj
->guards
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, (void **) pguard
) == SUCCESS
) {
417 return zend_hash_quick_add(zobj
->guards
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, (void**)&stub
, sizeof(stub
), (void**) pguard
);
421 zval
*zend_std_read_property(zval
*object
, zval
*member
, int type
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
424 zval
*tmp_member
= NULL
;
427 zend_property_info
*property_info
;
430 silent
= (type
== BP_VAR_IS
);
431 zobj
= Z_OBJ_P(object
);
433 if (UNEXPECTED(Z_TYPE_P(member
) != IS_STRING
)) {
434 ALLOC_ZVAL(tmp_member
);
435 *tmp_member
= *member
;
436 INIT_PZVAL(tmp_member
);
437 zval_copy_ctor(tmp_member
);
438 convert_to_string(tmp_member
);
443 #if DEBUG_OBJECT_HANDLERS
444 fprintf(stderr
, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object
), Z_STRVAL_P(member
));
447 /* make zend_get_property_info silent if we have getter - we may want to use it */
448 property_info
= zend_get_property_info_quick(zobj
->ce
, member
, silent
|| (zobj
->ce
->__get
!= NULL
), key TSRMLS_CC
);
450 if (UNEXPECTED(!property_info
) ||
451 ((EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
452 property_info
->offset
>= 0) ?
454 ((retval
= (zval
**)zobj
->properties_table
[property_info
->offset
]) == NULL
) :
455 (*(retval
= &zobj
->properties_table
[property_info
->offset
]) == NULL
)) :
456 (UNEXPECTED(!zobj
->properties
) ||
457 UNEXPECTED(zend_hash_quick_find(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, (void **) &retval
) == FAILURE
)))) {
458 zend_guard
*guard
= NULL
;
460 if (zobj
->ce
->__get
&&
461 zend_get_property_guard(zobj
, property_info
, member
, &guard
) == SUCCESS
&&
463 /* have getter - try with it! */
465 if (PZVAL_IS_REF(object
)) {
466 SEPARATE_ZVAL(&object
);
468 guard
->in_get
= 1; /* prevent circular getting */
469 rv
= zend_std_call_getter(object
, member TSRMLS_CC
);
474 if (!Z_ISREF_P(rv
) &&
475 (type
== BP_VAR_W
|| type
== BP_VAR_RW
|| type
== BP_VAR_UNSET
)) {
476 if (Z_REFCOUNT_P(rv
) > 0) {
483 Z_SET_REFCOUNT_P(rv
, 0);
485 if (UNEXPECTED(Z_TYPE_P(rv
) != IS_OBJECT
)) {
486 zend_error(E_NOTICE
, "Indirect modification of overloaded property %s::$%s has no effect", zobj
->ce
->name
, Z_STRVAL_P(member
));
490 retval
= &EG(uninitialized_zval_ptr
);
492 if (EXPECTED(*retval
!= object
)) {
493 zval_ptr_dtor(&object
);
498 if (zobj
->ce
->__get
&& guard
&& guard
->in_get
== 1) {
499 if (Z_STRVAL_P(member
)[0] == '\0') {
500 if (Z_STRLEN_P(member
) == 0) {
501 zend_error(E_ERROR
, "Cannot access empty property");
503 zend_error(E_ERROR
, "Cannot access property started with '\\0'");
508 zend_error(E_NOTICE
,"Undefined property: %s::$%s", zobj
->ce
->name
, Z_STRVAL_P(member
));
510 retval
= &EG(uninitialized_zval_ptr
);
513 if (UNEXPECTED(tmp_member
!= NULL
)) {
515 zval_ptr_dtor(&tmp_member
);
522 ZEND_API
void zend_std_write_property(zval
*object
, zval
*member
, zval
*value
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
525 zval
*tmp_member
= NULL
;
527 zend_property_info
*property_info
;
529 zobj
= Z_OBJ_P(object
);
531 if (UNEXPECTED(Z_TYPE_P(member
) != IS_STRING
)) {
532 ALLOC_ZVAL(tmp_member
);
533 *tmp_member
= *member
;
534 INIT_PZVAL(tmp_member
);
535 zval_copy_ctor(tmp_member
);
536 convert_to_string(tmp_member
);
541 property_info
= zend_get_property_info_quick(zobj
->ce
, member
, (zobj
->ce
->__set
!= NULL
), key TSRMLS_CC
);
543 if (EXPECTED(property_info
!= NULL
) &&
544 ((EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
545 property_info
->offset
>= 0) ?
547 ((variable_ptr
= (zval
**)zobj
->properties_table
[property_info
->offset
]) != NULL
) :
548 (*(variable_ptr
= &zobj
->properties_table
[property_info
->offset
]) != NULL
)) :
549 (EXPECTED(zobj
->properties
!= NULL
) &&
550 EXPECTED(zend_hash_quick_find(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, (void **) &variable_ptr
) == SUCCESS
)))) {
551 /* if we already have this value there, we don't actually need to do anything */
552 if (EXPECTED(*variable_ptr
!= value
)) {
553 /* if we are assigning reference, we shouldn't move it, but instead assign variable
554 to the same pointer */
555 if (PZVAL_IS_REF(*variable_ptr
)) {
556 zval garbage
= **variable_ptr
; /* old value should be destroyed */
558 /* To check: can't *variable_ptr be some system variable like error_zval here? */
559 Z_TYPE_PP(variable_ptr
) = Z_TYPE_P(value
);
560 (*variable_ptr
)->value
= value
->value
;
561 if (Z_REFCOUNT_P(value
) > 0) {
562 zval_copy_ctor(*variable_ptr
);
568 zval
*garbage
= *variable_ptr
;
570 /* if we assign referenced variable, we should separate it */
572 if (PZVAL_IS_REF(value
)) {
573 SEPARATE_ZVAL(&value
);
575 *variable_ptr
= value
;
576 zval_ptr_dtor(&garbage
);
580 zend_guard
*guard
= NULL
;
582 if (zobj
->ce
->__set
&&
583 zend_get_property_guard(zobj
, property_info
, member
, &guard
) == SUCCESS
&&
586 if (PZVAL_IS_REF(object
)) {
587 SEPARATE_ZVAL(&object
);
589 guard
->in_set
= 1; /* prevent circular setting */
590 if (zend_std_call_setter(object
, member
, value TSRMLS_CC
) != SUCCESS
) {
591 /* for now, just ignore it - __set should take care of warnings, etc. */
594 zval_ptr_dtor(&object
);
595 } else if (EXPECTED(property_info
!= NULL
)) {
596 /* if we assign referenced variable, we should separate it */
598 if (PZVAL_IS_REF(value
)) {
599 SEPARATE_ZVAL(&value
);
601 if (EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
602 property_info
->offset
>= 0) {
603 if (!zobj
->properties
) {
604 zobj
->properties_table
[property_info
->offset
] = value
;
605 } else if (zobj
->properties_table
[property_info
->offset
]) {
606 *(zval
**)zobj
->properties_table
[property_info
->offset
] = value
;
608 zend_hash_quick_update(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, &value
, sizeof(zval
*), (void**)&zobj
->properties_table
[property_info
->offset
]);
611 if (!zobj
->properties
) {
612 rebuild_object_properties(zobj
);
614 zend_hash_quick_update(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, &value
, sizeof(zval
*), NULL
);
616 } else if (zobj
->ce
->__set
&& guard
&& guard
->in_set
== 1) {
617 if (Z_STRVAL_P(member
)[0] == '\0') {
618 if (Z_STRLEN_P(member
) == 0) {
619 zend_error(E_ERROR
, "Cannot access empty property");
621 zend_error(E_ERROR
, "Cannot access property started with '\\0'");
627 if (UNEXPECTED(tmp_member
!= NULL
)) {
628 zval_ptr_dtor(&tmp_member
);
633 zval
*zend_std_read_dimension(zval
*object
, zval
*offset
, int type TSRMLS_DC
) /* {{{ */
635 zend_class_entry
*ce
= Z_OBJCE_P(object
);
638 if (EXPECTED(instanceof_function_ex(ce
, zend_ce_arrayaccess
, 1 TSRMLS_CC
) != 0)) {
641 ALLOC_INIT_ZVAL(offset
);
643 SEPARATE_ARG_IF_REF(offset
);
645 zend_call_method_with_1_params(&object
, ce
, NULL
, "offsetget", &retval
, offset
);
647 zval_ptr_dtor(&offset
);
649 if (UNEXPECTED(!retval
)) {
650 if (UNEXPECTED(!EG(exception
))) {
651 zend_error_noreturn(E_ERROR
, "Undefined offset for object of type %s used as array", ce
->name
);
656 /* Undo PZVAL_LOCK() */
661 zend_error_noreturn(E_ERROR
, "Cannot use object of type %s as array", ce
->name
);
667 static void zend_std_write_dimension(zval
*object
, zval
*offset
, zval
*value TSRMLS_DC
) /* {{{ */
669 zend_class_entry
*ce
= Z_OBJCE_P(object
);
671 if (EXPECTED(instanceof_function_ex(ce
, zend_ce_arrayaccess
, 1 TSRMLS_CC
) != 0)) {
673 ALLOC_INIT_ZVAL(offset
);
675 SEPARATE_ARG_IF_REF(offset
);
677 zend_call_method_with_2_params(&object
, ce
, NULL
, "offsetset", NULL
, offset
, value
);
678 zval_ptr_dtor(&offset
);
680 zend_error_noreturn(E_ERROR
, "Cannot use object of type %s as array", ce
->name
);
685 static int zend_std_has_dimension(zval
*object
, zval
*offset
, int check_empty TSRMLS_DC
) /* {{{ */
687 zend_class_entry
*ce
= Z_OBJCE_P(object
);
691 if (EXPECTED(instanceof_function_ex(ce
, zend_ce_arrayaccess
, 1 TSRMLS_CC
) != 0)) {
692 SEPARATE_ARG_IF_REF(offset
);
693 zend_call_method_with_1_params(&object
, ce
, NULL
, "offsetexists", &retval
, offset
);
694 if (EXPECTED(retval
!= NULL
)) {
695 result
= i_zend_is_true(retval
);
696 zval_ptr_dtor(&retval
);
697 if (check_empty
&& result
&& EXPECTED(!EG(exception
))) {
698 zend_call_method_with_1_params(&object
, ce
, NULL
, "offsetget", &retval
, offset
);
700 result
= i_zend_is_true(retval
);
701 zval_ptr_dtor(&retval
);
707 zval_ptr_dtor(&offset
);
709 zend_error_noreturn(E_ERROR
, "Cannot use object of type %s as array", ce
->name
);
716 static zval
**zend_std_get_property_ptr_ptr(zval
*object
, zval
*member
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
721 zend_property_info
*property_info
;
723 zobj
= Z_OBJ_P(object
);
725 if (UNEXPECTED(Z_TYPE_P(member
) != IS_STRING
)) {
726 tmp_member
= *member
;
727 zval_copy_ctor(&tmp_member
);
728 convert_to_string(&tmp_member
);
729 member
= &tmp_member
;
733 #if DEBUG_OBJECT_HANDLERS
734 fprintf(stderr
, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object
), Z_STRVAL_P(member
));
737 property_info
= zend_get_property_info_quick(zobj
->ce
, member
, (zobj
->ce
->__get
!= NULL
), key TSRMLS_CC
);
739 if (UNEXPECTED(!property_info
) ||
740 ((EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
741 property_info
->offset
>= 0) ?
743 ((retval
= (zval
**)zobj
->properties_table
[property_info
->offset
]) == NULL
) :
744 (*(retval
= &zobj
->properties_table
[property_info
->offset
]) == NULL
)) :
745 (UNEXPECTED(!zobj
->properties
) ||
746 UNEXPECTED(zend_hash_quick_find(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, (void **) &retval
) == FAILURE
)))) {
750 if (!zobj
->ce
->__get
||
751 zend_get_property_guard(zobj
, property_info
, member
, &guard
) != SUCCESS
||
752 (property_info
&& guard
->in_get
)) {
753 /* we don't have access controls - will just add it */
754 new_zval
= &EG(uninitialized_zval
);
756 /* zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */
757 Z_ADDREF_P(new_zval
);
758 if (EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
759 property_info
->offset
>= 0) {
760 if (!zobj
->properties
) {
761 zobj
->properties_table
[property_info
->offset
] = new_zval
;
762 retval
= &zobj
->properties_table
[property_info
->offset
];
763 } else if (zobj
->properties_table
[property_info
->offset
]) {
764 *(zval
**)zobj
->properties_table
[property_info
->offset
] = new_zval
;
765 retval
= (zval
**)zobj
->properties_table
[property_info
->offset
];
767 zend_hash_quick_update(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, &new_zval
, sizeof(zval
*), (void**)&zobj
->properties_table
[property_info
->offset
]);
768 retval
= (zval
**)zobj
->properties_table
[property_info
->offset
];
771 if (!zobj
->properties
) {
772 rebuild_object_properties(zobj
);
774 zend_hash_quick_update(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, &new_zval
, sizeof(zval
*), (void **) &retval
);
777 /* we do have getter - fail and let it try again with usual get/set */
781 if (UNEXPECTED(member
== &tmp_member
)) {
788 static void zend_std_unset_property(zval
*object
, zval
*member
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
791 zval
*tmp_member
= NULL
;
792 zend_property_info
*property_info
;
794 zobj
= Z_OBJ_P(object
);
796 if (UNEXPECTED(Z_TYPE_P(member
) != IS_STRING
)) {
797 ALLOC_ZVAL(tmp_member
);
798 *tmp_member
= *member
;
799 INIT_PZVAL(tmp_member
);
800 zval_copy_ctor(tmp_member
);
801 convert_to_string(tmp_member
);
806 property_info
= zend_get_property_info_quick(zobj
->ce
, member
, (zobj
->ce
->__unset
!= NULL
), key TSRMLS_CC
);
808 if (EXPECTED(property_info
!= NULL
) &&
809 EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
811 property_info
->offset
>= 0 &&
812 EXPECTED(zobj
->properties_table
[property_info
->offset
] != NULL
)) {
813 zval_ptr_dtor(&zobj
->properties_table
[property_info
->offset
]);
814 zobj
->properties_table
[property_info
->offset
] = NULL
;
815 } else if (UNEXPECTED(!property_info
) ||
817 UNEXPECTED(zend_hash_quick_del(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
) == FAILURE
)) {
818 zend_guard
*guard
= NULL
;
820 if (zobj
->ce
->__unset
&&
821 zend_get_property_guard(zobj
, property_info
, member
, &guard
) == SUCCESS
&&
823 /* have unseter - try with it! */
825 if (PZVAL_IS_REF(object
)) {
826 SEPARATE_ZVAL(&object
);
828 guard
->in_unset
= 1; /* prevent circular unsetting */
829 zend_std_call_unsetter(object
, member TSRMLS_CC
);
831 zval_ptr_dtor(&object
);
832 } else if (zobj
->ce
->__unset
&& guard
&& guard
->in_unset
== 1) {
833 if (Z_STRVAL_P(member
)[0] == '\0') {
834 if (Z_STRLEN_P(member
) == 0) {
835 zend_error(E_ERROR
, "Cannot access empty property");
837 zend_error(E_ERROR
, "Cannot access property started with '\\0'");
841 } else if (EXPECTED(property_info
!= NULL
) &&
842 EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
843 property_info
->offset
>= 0) {
844 zobj
->properties_table
[property_info
->offset
] = NULL
;
847 if (UNEXPECTED(tmp_member
!= NULL
)) {
848 zval_ptr_dtor(&tmp_member
);
853 static void zend_std_unset_dimension(zval
*object
, zval
*offset TSRMLS_DC
) /* {{{ */
855 zend_class_entry
*ce
= Z_OBJCE_P(object
);
857 if (instanceof_function_ex(ce
, zend_ce_arrayaccess
, 1 TSRMLS_CC
)) {
858 SEPARATE_ARG_IF_REF(offset
);
859 zend_call_method_with_1_params(&object
, ce
, NULL
, "offsetunset", NULL
, offset
);
860 zval_ptr_dtor(&offset
);
862 zend_error_noreturn(E_ERROR
, "Cannot use object of type %s as array", ce
->name
);
867 ZEND_API
void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS
) /* {{{ */
869 zend_internal_function
*func
= (zend_internal_function
*)EG(current_execute_data
)->function_state
.function
;
870 zval
*method_name_ptr
, *method_args_ptr
;
871 zval
*method_result_ptr
= NULL
;
872 zend_class_entry
*ce
= Z_OBJCE_P(this_ptr
);
874 ALLOC_ZVAL(method_args_ptr
);
875 INIT_PZVAL(method_args_ptr
);
876 array_init_size(method_args_ptr
, ZEND_NUM_ARGS());
878 if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC
) == FAILURE
)) {
879 zval_dtor(method_args_ptr
);
880 zend_error_noreturn(E_ERROR
, "Cannot get arguments for __call");
884 ALLOC_ZVAL(method_name_ptr
);
885 INIT_PZVAL(method_name_ptr
);
886 ZVAL_STRING(method_name_ptr
, func
->function_name
, 0); /* no dup - it's a copy */
888 /* __call handler is called with two arguments:
890 array of method parameters
893 zend_call_method_with_2_params(&this_ptr
, ce
, &ce
->__call
, ZEND_CALL_FUNC_NAME
, &method_result_ptr
, method_name_ptr
, method_args_ptr
);
895 if (method_result_ptr
) {
896 if (Z_ISREF_P(method_result_ptr
) || Z_REFCOUNT_P(method_result_ptr
) > 1) {
897 RETVAL_ZVAL(method_result_ptr
, 1, 1);
899 RETVAL_ZVAL(method_result_ptr
, 0, 1);
903 /* now destruct all auxiliaries */
904 zval_ptr_dtor(&method_args_ptr
);
905 zval_ptr_dtor(&method_name_ptr
);
907 /* destruct the function also, then - we have allocated it in get_method */
912 /* Ensures that we're allowed to call a private method.
913 * Returns the function address that should be called, or NULL
914 * if no such function exists.
916 static inline zend_function
*zend_check_private_int(zend_function
*fbc
, zend_class_entry
*ce
, char *function_name_strval
, int function_name_strlen
, ulong hash_value TSRMLS_DC
) /* {{{ */
922 /* We may call a private function if:
923 * 1. The class of our object is the same as the scope, and the private
924 * function (EX(fbc)) has the same scope.
925 * 2. One of our parent classes are the same as the scope, and it contains
926 * a private function with the same name that has the same scope.
928 if (fbc
->common
.scope
== ce
&& EG(scope
) == ce
) {
929 /* rule #1 checks out ok, allow the function call */
937 if (ce
== EG(scope
)) {
938 if (zend_hash_quick_find(&ce
->function_table
, function_name_strval
, function_name_strlen
+1, hash_value
, (void **) &fbc
)==SUCCESS
939 && fbc
->op_array
.fn_flags
& ZEND_ACC_PRIVATE
940 && fbc
->common
.scope
== EG(scope
)) {
951 ZEND_API
int zend_check_private(zend_function
*fbc
, zend_class_entry
*ce
, char *function_name_strval
, int function_name_strlen TSRMLS_DC
) /* {{{ */
953 return zend_check_private_int(fbc
, ce
, function_name_strval
, function_name_strlen
, zend_hash_func(function_name_strval
, function_name_strlen
+1) TSRMLS_CC
) != NULL
;
957 /* Ensures that we're allowed to call a protected method.
959 ZEND_API
int zend_check_protected(zend_class_entry
*ce
, zend_class_entry
*scope
) /* {{{ */
961 zend_class_entry
*fbc_scope
= ce
;
963 /* Is the context that's calling the function, the same as one of
964 * the function's parents?
967 if (fbc_scope
==scope
) {
970 fbc_scope
= fbc_scope
->parent
;
973 /* Is the function's scope the same as our current object context,
974 * or any of the parents of our context?
980 scope
= scope
->parent
;
986 static inline union _zend_function
*zend_get_user_call_function(zend_class_entry
*ce
, const char *method_name
, int method_len
) /* {{{ */
988 zend_internal_function
*call_user_call
= emalloc(sizeof(zend_internal_function
));
989 call_user_call
->type
= ZEND_INTERNAL_FUNCTION
;
990 call_user_call
->module
= (ce
->type
== ZEND_INTERNAL_CLASS
) ? ce
->info
.internal
.module
: NULL
;
991 call_user_call
->handler
= zend_std_call_user_call
;
992 call_user_call
->arg_info
= NULL
;
993 call_user_call
->num_args
= 0;
994 call_user_call
->scope
= ce
;
995 call_user_call
->fn_flags
= ZEND_ACC_CALL_VIA_HANDLER
;
996 call_user_call
->function_name
= estrndup(method_name
, method_len
);
998 return (union _zend_function
*)call_user_call
;
1002 static union _zend_function
*zend_std_get_method(zval
**object_ptr
, char *method_name
, int method_len
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
1005 zval
*object
= *object_ptr
;
1006 zend_object
*zobj
= Z_OBJ_P(object
);
1008 char *lc_method_name
;
1009 ALLOCA_FLAG(use_heap
)
1011 if (EXPECTED(key
!= NULL
)) {
1012 lc_method_name
= Z_STRVAL(key
->constant
);
1013 hash_value
= key
->hash_value
;
1015 lc_method_name
= do_alloca(method_len
+1, use_heap
);
1016 /* Create a zend_copy_str_tolower(dest, src, src_length); */
1017 zend_str_tolower_copy(lc_method_name
, method_name
, method_len
);
1018 hash_value
= zend_hash_func(lc_method_name
, method_len
+1);
1021 if (UNEXPECTED(zend_hash_quick_find(&zobj
->ce
->function_table
, lc_method_name
, method_len
+1, hash_value
, (void **)&fbc
) == FAILURE
)) {
1022 if (UNEXPECTED(!key
)) {
1023 free_alloca(lc_method_name
, use_heap
);
1025 if (zobj
->ce
->__call
) {
1026 return zend_get_user_call_function(zobj
->ce
, method_name
, method_len
);
1032 /* Check access level */
1033 if (fbc
->op_array
.fn_flags
& ZEND_ACC_PRIVATE
) {
1034 zend_function
*updated_fbc
;
1036 /* Ensure that if we're calling a private function, we're allowed to do so.
1037 * If we're not and __call() handler exists, invoke it, otherwise error out.
1039 updated_fbc
= zend_check_private_int(fbc
, Z_OBJ_HANDLER_P(object
, get_class_entry
)(object TSRMLS_CC
), lc_method_name
, method_len
, hash_value TSRMLS_CC
);
1040 if (EXPECTED(updated_fbc
!= NULL
)) {
1043 if (zobj
->ce
->__call
) {
1044 fbc
= zend_get_user_call_function(zobj
->ce
, method_name
, method_len
);
1046 zend_error_noreturn(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
: "");
1050 /* Ensure that we haven't overridden a private function and end up calling
1051 * the overriding public function...
1054 is_derived_class(fbc
->common
.scope
, EG(scope
)) &&
1055 fbc
->op_array
.fn_flags
& ZEND_ACC_CHANGED
) {
1056 zend_function
*priv_fbc
;
1058 if (zend_hash_quick_find(&EG(scope
)->function_table
, lc_method_name
, method_len
+1, hash_value
, (void **) &priv_fbc
)==SUCCESS
1059 && priv_fbc
->common
.fn_flags
& ZEND_ACC_PRIVATE
1060 && priv_fbc
->common
.scope
== EG(scope
)) {
1064 if ((fbc
->common
.fn_flags
& ZEND_ACC_PROTECTED
)) {
1065 /* Ensure that if we're calling a protected function, we're allowed to do so.
1066 * If we're not and __call() handler exists, invoke it, otherwise error out.
1068 if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc
), EG(scope
)))) {
1069 if (zobj
->ce
->__call
) {
1070 fbc
= zend_get_user_call_function(zobj
->ce
, method_name
, method_len
);
1072 zend_error_noreturn(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
: "");
1078 if (UNEXPECTED(!key
)) {
1079 free_alloca(lc_method_name
, use_heap
);
1085 ZEND_API
void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS
) /* {{{ */
1087 zend_internal_function
*func
= (zend_internal_function
*)EG(current_execute_data
)->function_state
.function
;
1088 zval
*method_name_ptr
, *method_args_ptr
;
1089 zval
*method_result_ptr
= NULL
;
1090 zend_class_entry
*ce
= EG(scope
);
1092 ALLOC_ZVAL(method_args_ptr
);
1093 INIT_PZVAL(method_args_ptr
);
1094 array_init_size(method_args_ptr
, ZEND_NUM_ARGS());
1096 if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC
) == FAILURE
)) {
1097 zval_dtor(method_args_ptr
);
1098 zend_error_noreturn(E_ERROR
, "Cannot get arguments for " ZEND_CALLSTATIC_FUNC_NAME
);
1102 ALLOC_ZVAL(method_name_ptr
);
1103 INIT_PZVAL(method_name_ptr
);
1104 ZVAL_STRING(method_name_ptr
, func
->function_name
, 0); /* no dup - it's a copy */
1106 /* __callStatic handler is called with two arguments:
1108 array of method parameters
1110 zend_call_method_with_2_params(NULL
, ce
, &ce
->__callstatic
, ZEND_CALLSTATIC_FUNC_NAME
, &method_result_ptr
, method_name_ptr
, method_args_ptr
);
1112 if (method_result_ptr
) {
1113 if (Z_ISREF_P(method_result_ptr
) || Z_REFCOUNT_P(method_result_ptr
) > 1) {
1114 RETVAL_ZVAL(method_result_ptr
, 1, 1);
1116 RETVAL_ZVAL(method_result_ptr
, 0, 1);
1120 /* now destruct all auxiliaries */
1121 zval_ptr_dtor(&method_args_ptr
);
1122 zval_ptr_dtor(&method_name_ptr
);
1124 /* destruct the function also, then - we have allocated it in get_method */
1129 static inline union _zend_function
*zend_get_user_callstatic_function(zend_class_entry
*ce
, const char *method_name
, int method_len
) /* {{{ */
1131 zend_internal_function
*callstatic_user_call
= emalloc(sizeof(zend_internal_function
));
1132 callstatic_user_call
->type
= ZEND_INTERNAL_FUNCTION
;
1133 callstatic_user_call
->module
= (ce
->type
== ZEND_INTERNAL_CLASS
) ? ce
->info
.internal
.module
: NULL
;
1134 callstatic_user_call
->handler
= zend_std_callstatic_user_call
;
1135 callstatic_user_call
->arg_info
= NULL
;
1136 callstatic_user_call
->num_args
= 0;
1137 callstatic_user_call
->scope
= ce
;
1138 callstatic_user_call
->fn_flags
= ZEND_ACC_STATIC
| ZEND_ACC_PUBLIC
| ZEND_ACC_CALL_VIA_HANDLER
;
1139 callstatic_user_call
->function_name
= estrndup(method_name
, method_len
);
1141 return (zend_function
*)callstatic_user_call
;
1145 /* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
1147 ZEND_API zend_function
*zend_std_get_static_method(zend_class_entry
*ce
, const char *function_name_strval
, int function_name_strlen
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
1149 zend_function
*fbc
= NULL
;
1150 char *lc_class_name
, *lc_function_name
= NULL
;
1152 ALLOCA_FLAG(use_heap
)
1154 if (EXPECTED(key
!= NULL
)) {
1155 lc_function_name
= Z_STRVAL(key
->constant
);
1156 hash_value
= key
->hash_value
;
1158 lc_function_name
= do_alloca(function_name_strlen
+1, use_heap
);
1159 /* Create a zend_copy_str_tolower(dest, src, src_length); */
1160 zend_str_tolower_copy(lc_function_name
, function_name_strval
, function_name_strlen
);
1161 hash_value
= zend_hash_func(lc_function_name
, function_name_strlen
+1);
1164 if (function_name_strlen
== ce
->name_length
&& ce
->constructor
) {
1165 lc_class_name
= zend_str_tolower_dup(ce
->name
, ce
->name_length
);
1166 /* Only change the method to the constructor if the constructor isn't called __construct
1167 * we check for __ so we can be binary safe for lowering, we should use ZEND_CONSTRUCTOR_FUNC_NAME
1169 if (!memcmp(lc_class_name
, lc_function_name
, function_name_strlen
) && memcmp(ce
->constructor
->common
.function_name
, "__", sizeof("__") - 1)) {
1170 fbc
= ce
->constructor
;
1172 efree(lc_class_name
);
1174 if (EXPECTED(!fbc
) &&
1175 UNEXPECTED(zend_hash_quick_find(&ce
->function_table
, lc_function_name
, function_name_strlen
+1, hash_value
, (void **) &fbc
)==FAILURE
)) {
1176 if (UNEXPECTED(!key
)) {
1177 free_alloca(lc_function_name
, use_heap
);
1182 Z_OBJ_HT_P(EG(This
))->get_class_entry
&&
1183 instanceof_function(Z_OBJCE_P(EG(This
)), ce TSRMLS_CC
)) {
1184 return zend_get_user_call_function(ce
, function_name_strval
, function_name_strlen
);
1185 } else if (ce
->__callstatic
) {
1186 return zend_get_user_callstatic_function(ce
, function_name_strval
, function_name_strlen
);
1193 /* right now this function is used for non static method lookup too */
1194 /* Is the function static */
1195 if (UNEXPECTED(!(fbc
->common
.fn_flags
& ZEND_ACC_STATIC
))) {
1196 zend_error_noreturn(E_ERROR
, "Cannot call non static method %s::%s() without object", ZEND_FN_SCOPE_NAME(fbc
), fbc
->common
.function_name
);
1199 if (fbc
->op_array
.fn_flags
& ZEND_ACC_PUBLIC
) {
1200 /* No further checks necessary, most common case */
1201 } else if (fbc
->op_array
.fn_flags
& ZEND_ACC_PRIVATE
) {
1202 zend_function
*updated_fbc
;
1204 /* Ensure that if we're calling a private function, we're allowed to do so.
1206 updated_fbc
= zend_check_private_int(fbc
, EG(scope
), lc_function_name
, function_name_strlen
, hash_value TSRMLS_CC
);
1207 if (EXPECTED(updated_fbc
!= NULL
)) {
1210 if (ce
->__callstatic
) {
1211 fbc
= zend_get_user_callstatic_function(ce
, function_name_strval
, function_name_strlen
);
1213 zend_error_noreturn(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
: "");
1216 } else if ((fbc
->common
.fn_flags
& ZEND_ACC_PROTECTED
)) {
1217 /* Ensure that if we're calling a protected function, we're allowed to do so.
1219 if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc
), EG(scope
)))) {
1220 if (ce
->__callstatic
) {
1221 fbc
= zend_get_user_callstatic_function(ce
, function_name_strval
, function_name_strlen
);
1223 zend_error_noreturn(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
: "");
1228 if (UNEXPECTED(!key
)) {
1229 free_alloca(lc_function_name
, use_heap
);
1236 ZEND_API zval
**zend_std_get_static_property(zend_class_entry
*ce
, const char *property_name
, int property_name_len
, zend_bool silent
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
1238 zend_property_info
*property_info
;
1241 if (UNEXPECTED(!key
) ||
1242 (property_info
= CACHED_POLYMORPHIC_PTR(key
->cache_slot
, ce
)) == NULL
) {
1243 if (EXPECTED(key
!= NULL
)) {
1244 hash_value
= key
->hash_value
;
1246 hash_value
= zend_hash_func(property_name
, property_name_len
+1);
1249 if (UNEXPECTED(zend_hash_quick_find(&ce
->properties_info
, property_name
, property_name_len
+1, hash_value
, (void **) &property_info
)==FAILURE
)) {
1251 zend_error_noreturn(E_ERROR
, "Access to undeclared static property: %s::$%s", ce
->name
, property_name
);
1256 #if DEBUG_OBJECT_HANDLERS
1257 zend_printf("Access type for %s::%s is %s\n", ce
->name
, property_name
, zend_visibility_string(property_info
->flags
));
1260 if (UNEXPECTED(!zend_verify_property_access(property_info
, ce TSRMLS_CC
))) {
1262 zend_error_noreturn(E_ERROR
, "Cannot access %s property %s::$%s", zend_visibility_string(property_info
->flags
), ce
->name
, property_name
);
1267 if (UNEXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0)) {
1269 zend_error_noreturn(E_ERROR
, "Access to undeclared static property: %s::$%s", ce
->name
, property_name
);
1274 zend_update_class_constants(ce TSRMLS_CC
);
1276 if (EXPECTED(key
!= NULL
)) {
1277 CACHE_POLYMORPHIC_PTR(key
->cache_slot
, ce
, property_info
);
1281 return &CE_STATIC_MEMBERS(ce
)[property_info
->offset
];
1285 ZEND_API zend_bool
zend_std_unset_static_property(zend_class_entry
*ce
, const char *property_name
, int property_name_len
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
1287 zend_error_noreturn(E_ERROR
, "Attempt to unset static property %s::$%s", ce
->name
, property_name
);
1292 ZEND_API
union _zend_function
*zend_std_get_constructor(zval
*object TSRMLS_DC
) /* {{{ */
1294 zend_object
*zobj
= Z_OBJ_P(object
);
1295 zend_function
*constructor
= zobj
->ce
->constructor
;
1298 if (constructor
->op_array
.fn_flags
& ZEND_ACC_PUBLIC
) {
1299 /* No further checks necessary */
1300 } else if (constructor
->op_array
.fn_flags
& ZEND_ACC_PRIVATE
) {
1301 /* Ensure that if we're calling a private function, we're allowed to do so.
1303 if (UNEXPECTED(constructor
->common
.scope
!= EG(scope
))) {
1305 zend_error_noreturn(E_ERROR
, "Call to private %s::%s() from context '%s'", constructor
->common
.scope
->name
, constructor
->common
.function_name
, EG(scope
)->name
);
1307 zend_error_noreturn(E_ERROR
, "Call to private %s::%s() from invalid context", constructor
->common
.scope
->name
, constructor
->common
.function_name
);
1310 } else if ((constructor
->common
.fn_flags
& ZEND_ACC_PROTECTED
)) {
1311 /* Ensure that if we're calling a protected function, we're allowed to do so.
1312 * Constructors only have prototype if they are defined by an interface but
1313 * it is the compilers responsibility to take care of the prototype.
1315 if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(constructor
), EG(scope
)))) {
1317 zend_error_noreturn(E_ERROR
, "Call to protected %s::%s() from context '%s'", constructor
->common
.scope
->name
, constructor
->common
.function_name
, EG(scope
)->name
);
1319 zend_error_noreturn(E_ERROR
, "Call to protected %s::%s() from invalid context", constructor
->common
.scope
->name
, constructor
->common
.function_name
);
1329 int zend_compare_symbol_tables_i(HashTable
*ht1
, HashTable
*ht2 TSRMLS_DC
);
1331 static int zend_std_compare_objects(zval
*o1
, zval
*o2 TSRMLS_DC
) /* {{{ */
1333 zend_object
*zobj1
, *zobj2
;
1335 zobj1
= Z_OBJ_P(o1
);
1336 zobj2
= Z_OBJ_P(o2
);
1338 if (zobj1
->ce
!= zobj2
->ce
) {
1339 return 1; /* different classes */
1341 if (!zobj1
->properties
&& !zobj2
->properties
) {
1344 Z_OBJ_PROTECT_RECURSION(o1
);
1345 Z_OBJ_PROTECT_RECURSION(o2
);
1346 for (i
= 0; i
< zobj1
->ce
->default_properties_count
; i
++) {
1347 if (zobj1
->properties_table
[i
]) {
1348 if (zobj2
->properties_table
[i
]) {
1351 if (compare_function(&result
, zobj1
->properties_table
[i
], zobj2
->properties_table
[i
] TSRMLS_CC
)==FAILURE
) {
1352 Z_OBJ_UNPROTECT_RECURSION(o1
);
1353 Z_OBJ_UNPROTECT_RECURSION(o2
);
1356 if (Z_LVAL(result
) != 0) {
1357 Z_OBJ_UNPROTECT_RECURSION(o1
);
1358 Z_OBJ_UNPROTECT_RECURSION(o2
);
1359 return Z_LVAL(result
);
1362 Z_OBJ_UNPROTECT_RECURSION(o1
);
1363 Z_OBJ_UNPROTECT_RECURSION(o2
);
1367 if (zobj2
->properties_table
[i
]) {
1368 Z_OBJ_UNPROTECT_RECURSION(o1
);
1369 Z_OBJ_UNPROTECT_RECURSION(o2
);
1372 Z_OBJ_UNPROTECT_RECURSION(o1
);
1373 Z_OBJ_UNPROTECT_RECURSION(o2
);
1378 Z_OBJ_UNPROTECT_RECURSION(o1
);
1379 Z_OBJ_UNPROTECT_RECURSION(o2
);
1382 if (!zobj1
->properties
) {
1383 rebuild_object_properties(zobj1
);
1385 if (!zobj2
->properties
) {
1386 rebuild_object_properties(zobj2
);
1388 return zend_compare_symbol_tables_i(zobj1
->properties
, zobj2
->properties TSRMLS_CC
);
1393 static int zend_std_has_property(zval
*object
, zval
*member
, int has_set_exists
, const zend_literal
*key TSRMLS_DC
) /* {{{ */
1397 zval
**value
= NULL
;
1398 zval
*tmp_member
= NULL
;
1399 zend_property_info
*property_info
;
1401 zobj
= Z_OBJ_P(object
);
1403 if (UNEXPECTED(Z_TYPE_P(member
) != IS_STRING
)) {
1404 ALLOC_ZVAL(tmp_member
);
1405 *tmp_member
= *member
;
1406 INIT_PZVAL(tmp_member
);
1407 zval_copy_ctor(tmp_member
);
1408 convert_to_string(tmp_member
);
1409 member
= tmp_member
;
1413 #if DEBUG_OBJECT_HANDLERS
1414 fprintf(stderr
, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object
), Z_STRVAL_P(member
));
1417 property_info
= zend_get_property_info_quick(zobj
->ce
, member
, 1, key TSRMLS_CC
);
1419 if (UNEXPECTED(!property_info
) ||
1420 ((EXPECTED((property_info
->flags
& ZEND_ACC_STATIC
) == 0) &&
1421 property_info
->offset
>= 0) ?
1423 ((value
= (zval
**)zobj
->properties_table
[property_info
->offset
]) == NULL
) :
1424 (*(value
= &zobj
->properties_table
[property_info
->offset
]) == NULL
)) :
1425 (UNEXPECTED(!zobj
->properties
) ||
1426 UNEXPECTED(zend_hash_quick_find(zobj
->properties
, property_info
->name
, property_info
->name_length
+1, property_info
->h
, (void **) &value
) == FAILURE
)))) {
1430 if ((has_set_exists
!= 2) &&
1431 zobj
->ce
->__isset
&&
1432 zend_get_property_guard(zobj
, property_info
, member
, &guard
) == SUCCESS
&&
1436 /* have issetter - try with it! */
1438 if (PZVAL_IS_REF(object
)) {
1439 SEPARATE_ZVAL(&object
);
1441 guard
->in_isset
= 1; /* prevent circular getting */
1442 rv
= zend_std_call_issetter(object
, member TSRMLS_CC
);
1444 result
= zend_is_true(rv
);
1446 if (has_set_exists
&& result
) {
1447 if (EXPECTED(!EG(exception
)) && zobj
->ce
->__get
&& !guard
->in_get
) {
1449 rv
= zend_std_call_getter(object
, member TSRMLS_CC
);
1453 result
= i_zend_is_true(rv
);
1463 guard
->in_isset
= 0;
1464 zval_ptr_dtor(&object
);
1467 switch (has_set_exists
) {
1469 result
= (Z_TYPE_PP(value
) != IS_NULL
);
1472 result
= zend_is_true(*value
);
1480 if (UNEXPECTED(tmp_member
!= NULL
)) {
1481 zval_ptr_dtor(&tmp_member
);
1487 zend_class_entry
*zend_std_object_get_class(const zval
*object TSRMLS_DC
) /* {{{ */
1490 zobj
= Z_OBJ_P(object
);
1496 int zend_std_object_get_class_name(const zval
*object
, const char **class_name
, zend_uint
*class_name_len
, int parent TSRMLS_DC
) /* {{{ */
1499 zend_class_entry
*ce
;
1500 zobj
= Z_OBJ_P(object
);
1503 if (!zobj
->ce
->parent
) {
1506 ce
= zobj
->ce
->parent
;
1511 *class_name_len
= ce
->name_length
;
1512 *class_name
= estrndup(ce
->name
, ce
->name_length
);
1517 ZEND_API
int zend_std_cast_object_tostring(zval
*readobj
, zval
*writeobj
, int type TSRMLS_DC
) /* {{{ */
1520 zend_class_entry
*ce
;
1524 ce
= Z_OBJCE_P(readobj
);
1525 if (ce
->__tostring
&&
1526 (zend_call_method_with_0_params(&readobj
, ce
, &ce
->__tostring
, "__tostring", &retval
) || EG(exception
))) {
1527 if (UNEXPECTED(EG(exception
) != NULL
)) {
1529 zval_ptr_dtor(&retval
);
1531 EG(exception
) = NULL
;
1532 zend_error_noreturn(E_ERROR
, "Method %s::__toString() must not throw an exception", ce
->name
);
1535 if (EXPECTED(Z_TYPE_P(retval
) == IS_STRING
)) {
1536 INIT_PZVAL(writeobj
);
1537 if (readobj
== writeobj
) {
1540 ZVAL_ZVAL(writeobj
, retval
, 1, 1);
1541 if (Z_TYPE_P(writeobj
) != type
) {
1542 convert_to_explicit_type(writeobj
, type
);
1546 zval_ptr_dtor(&retval
);
1547 INIT_PZVAL(writeobj
);
1548 if (readobj
== writeobj
) {
1551 ZVAL_EMPTY_STRING(writeobj
);
1552 zend_error(E_RECOVERABLE_ERROR
, "Method %s::__toString() must return a string value", ce
->name
);
1558 INIT_PZVAL(writeobj
);
1559 ZVAL_BOOL(writeobj
, 1);
1562 ce
= Z_OBJCE_P(readobj
);
1563 zend_error(E_NOTICE
, "Object of class %s could not be converted to int", ce
->name
);
1564 INIT_PZVAL(writeobj
);
1565 if (readobj
== writeobj
) {
1568 ZVAL_LONG(writeobj
, 1);
1571 ce
= Z_OBJCE_P(readobj
);
1572 zend_error(E_NOTICE
, "Object of class %s could not be converted to double", ce
->name
);
1573 INIT_PZVAL(writeobj
);
1574 if (readobj
== writeobj
) {
1577 ZVAL_DOUBLE(writeobj
, 1);
1580 INIT_PZVAL(writeobj
);
1581 Z_TYPE_P(writeobj
) = IS_NULL
;
1588 int zend_std_get_closure(zval
*obj
, zend_class_entry
**ce_ptr
, zend_function
**fptr_ptr
, zval
**zobj_ptr TSRMLS_DC
) /* {{{ */
1590 zend_class_entry
*ce
;
1591 if (Z_TYPE_P(obj
) != IS_OBJECT
) {
1595 ce
= Z_OBJCE_P(obj
);
1597 if (zend_hash_find(&ce
->function_table
, ZEND_INVOKE_FUNC_NAME
, sizeof(ZEND_INVOKE_FUNC_NAME
), (void**)fptr_ptr
) == FAILURE
) {
1602 if ((*fptr_ptr
)->common
.fn_flags
& ZEND_ACC_STATIC
) {
1615 ZEND_API zend_object_handlers std_object_handlers
= {
1616 zend_objects_store_add_ref
, /* add_ref */
1617 zend_objects_store_del_ref
, /* del_ref */
1618 zend_objects_clone_obj
, /* clone_obj */
1620 zend_std_read_property
, /* read_property */
1621 zend_std_write_property
, /* write_property */
1622 zend_std_read_dimension
, /* read_dimension */
1623 zend_std_write_dimension
, /* write_dimension */
1624 zend_std_get_property_ptr_ptr
, /* get_property_ptr_ptr */
1627 zend_std_has_property
, /* has_property */
1628 zend_std_unset_property
, /* unset_property */
1629 zend_std_has_dimension
, /* has_dimension */
1630 zend_std_unset_dimension
, /* unset_dimension */
1631 zend_std_get_properties
, /* get_properties */
1632 zend_std_get_method
, /* get_method */
1633 NULL
, /* call_method */
1634 zend_std_get_constructor
, /* get_constructor */
1635 zend_std_object_get_class
, /* get_class_entry */
1636 zend_std_object_get_class_name
, /* get_class_name */
1637 zend_std_compare_objects
, /* compare_objects */
1638 zend_std_cast_object_tostring
, /* cast_object */
1639 NULL
, /* count_elements */
1640 NULL
, /* get_debug_info */
1641 zend_std_get_closure
, /* get_closure */
1642 zend_std_get_gc
, /* get_gc */
1649 * indent-tabs-mode: t