1 : /*
2 : +----------------------------------------------------------------------+
3 : | Zend Engine |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1998-2009 Zend Technologies Ltd. (http://www.zend.com) |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 2.00 of the Zend license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.zend.com/license/2_00.txt. |
11 : | If you did not receive a copy of the Zend license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@zend.com so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Andi Gutmans <andi@zend.com> |
16 : | Zeev Suraski <zeev@zend.com> |
17 : +----------------------------------------------------------------------+
18 : */
19 :
20 : /* $Id: zend_object_handlers.c 288082 2009-09-05 17:11:44Z jani $ */
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 :
31 : #define DEBUG_OBJECT_HANDLERS 0
32 :
33 : #define Z_OBJ_P(zval_p) zend_objects_get_address(zval_p TSRMLS_CC)
34 :
35 : /*
36 : __X accessors explanation:
37 :
38 : if we have __get and property that is not part of the properties array is
39 : requested, we call __get handler. If it fails, we return uninitialized.
40 :
41 : if we have __set and property that is not part of the properties array is
42 : set, we call __set handler. If it fails, we do not change the array.
43 :
44 : for both handlers above, when we are inside __get/__set, no further calls for
45 : __get/__set for this property of this object will be made, to prevent endless
46 : recursion and enable accessors to change properties array.
47 :
48 : if we have __call and method which is not part of the class function table is
49 : called, we cal __call handler.
50 : */
51 :
52 : static HashTable *zend_std_get_properties(zval *object TSRMLS_DC)
53 201594 : {
54 : zend_object *zobj;
55 201594 : zobj = Z_OBJ_P(object);
56 201594 : return zobj->properties;
57 : }
58 :
59 : static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC)
60 107 : {
61 107 : zval *retval = NULL;
62 107 : zend_class_entry *ce = Z_OBJCE_P(object);
63 :
64 : /* __get handler is called with one argument:
65 : property name
66 :
67 : it should return whether the call was successfull or not
68 : */
69 :
70 107 : SEPARATE_ARG_IF_REF(member);
71 :
72 107 : zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member);
73 :
74 107 : zval_ptr_dtor(&member);
75 :
76 107 : if (retval) {
77 105 : retval->refcount--;
78 : }
79 :
80 107 : return retval;
81 : }
82 :
83 : static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC)
84 61 : {
85 61 : zval *retval = NULL;
86 : int result;
87 61 : zend_class_entry *ce = Z_OBJCE_P(object);
88 :
89 61 : SEPARATE_ARG_IF_REF(member);
90 61 : value->refcount++;
91 :
92 : /* __set handler is called with two arguments:
93 : property name
94 : value to be set
95 :
96 : it should return whether the call was successfull or not
97 : */
98 61 : zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value);
99 :
100 61 : zval_ptr_dtor(&member);
101 61 : zval_ptr_dtor(&value);
102 :
103 61 : if (retval) {
104 60 : result = i_zend_is_true(retval) ? SUCCESS : FAILURE;
105 60 : zval_ptr_dtor(&retval);
106 60 : return result;
107 : } else {
108 1 : return FAILURE;
109 : }
110 : }
111 :
112 : static void zend_std_call_unsetter(zval *object, zval *member TSRMLS_DC)
113 5 : {
114 5 : zend_class_entry *ce = Z_OBJCE_P(object);
115 :
116 : /* __unset handler is called with one argument:
117 : property name
118 : */
119 :
120 5 : SEPARATE_ARG_IF_REF(member);
121 :
122 5 : zend_call_method_with_1_params(&object, ce, &ce->__unset, ZEND_UNSET_FUNC_NAME, NULL, member);
123 :
124 5 : zval_ptr_dtor(&member);
125 5 : }
126 :
127 : static zval *zend_std_call_issetter(zval *object, zval *member TSRMLS_DC)
128 3 : {
129 3 : zval *retval = NULL;
130 3 : zend_class_entry *ce = Z_OBJCE_P(object);
131 :
132 : /* __isset handler is called with one argument:
133 : property name
134 :
135 : it should return whether the property is set or not
136 : */
137 :
138 3 : SEPARATE_ARG_IF_REF(member);
139 :
140 3 : zend_call_method_with_1_params(&object, ce, &ce->__isset, ZEND_ISSET_FUNC_NAME, &retval, member);
141 :
142 3 : zval_ptr_dtor(&member);
143 :
144 3 : return retval;
145 : }
146 :
147 : static int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC)
148 30464 : {
149 30464 : switch (property_info->flags & ZEND_ACC_PPP_MASK) {
150 : case ZEND_ACC_PUBLIC:
151 16189 : return 1;
152 : case ZEND_ACC_PROTECTED:
153 4992 : return zend_check_protected(property_info->ce, EG(scope));
154 : case ZEND_ACC_PRIVATE:
155 9283 : if ((ce==EG(scope) || property_info->ce == EG(scope)) && EG(scope)) {
156 9161 : return 1;
157 : } else {
158 122 : return 0;
159 : }
160 : break;
161 : }
162 0 : return 0;
163 : }
164 :
165 : static inline zend_bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class)
166 356820 : {
167 356820 : child_class = child_class->parent;
168 716026 : while (child_class) {
169 4201 : if (child_class == parent_class) {
170 1815 : return 1;
171 : }
172 2386 : child_class = child_class->parent;
173 : }
174 :
175 355005 : return 0;
176 : }
177 :
178 : ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC)
179 383828 : {
180 383828 : zend_property_info *property_info = NULL;
181 : zend_property_info *scope_property_info;
182 383828 : zend_bool denied_access = 0;
183 : ulong h;
184 :
185 383828 : if (Z_STRVAL_P(member)[0] == '\0') {
186 5 : if (!silent) {
187 1 : if (Z_STRLEN_P(member) == 0) {
188 1 : zend_error(E_ERROR, "Cannot access empty property");
189 : } else {
190 0 : zend_error(E_ERROR, "Cannot access property started with '\\0'");
191 : }
192 : }
193 4 : return NULL;
194 : }
195 383823 : h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
196 383823 : if (zend_hash_quick_find(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &property_info)==SUCCESS) {
197 31068 : if(property_info->flags & ZEND_ACC_SHADOW) {
198 : /* if it's a shadow - go to access it's private */
199 1597 : property_info = NULL;
200 : } else {
201 29471 : if (zend_verify_property_access(property_info, ce TSRMLS_CC)) {
202 29295 : if (property_info->flags & ZEND_ACC_CHANGED
203 : && !(property_info->flags & ZEND_ACC_PRIVATE)) {
204 : /* We still need to make sure that we're not in a context
205 : * where the right property is a different 'statically linked' private
206 : * continue checking below...
207 : */
208 : } else {
209 29274 : if (!silent && (property_info->flags & ZEND_ACC_STATIC)) {
210 12 : zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name, Z_STRVAL_P(member));
211 : }
212 29274 : return property_info;
213 : }
214 : } else {
215 : /* Try to look in the scope instead */
216 176 : denied_access = 1;
217 : }
218 : }
219 : }
220 354549 : if (EG(scope) != ce
221 : && is_derived_class(ce, EG(scope))
222 : && EG(scope)
223 : && zend_hash_quick_find(&EG(scope)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &scope_property_info)==SUCCESS
224 : && scope_property_info->flags & ZEND_ACC_PRIVATE) {
225 1570 : return scope_property_info;
226 352979 : } else if (property_info) {
227 172 : if (denied_access) {
228 : /* Information was available, but we were denied access. Error out. */
229 162 : if (silent) {
230 149 : return NULL;
231 : }
232 13 : zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, Z_STRVAL_P(member));
233 : } else {
234 : /* fall through, return property_info... */
235 : }
236 : } else {
237 352807 : EG(std_property_info).flags = ZEND_ACC_PUBLIC;
238 352807 : EG(std_property_info).name = Z_STRVAL_P(member);
239 352807 : EG(std_property_info).name_length = Z_STRLEN_P(member);
240 352807 : EG(std_property_info).h = h;
241 352807 : EG(std_property_info).ce = ce;
242 352807 : property_info = &EG(std_property_info);
243 : }
244 352817 : return property_info;
245 : }
246 :
247 :
248 : ZEND_API int zend_check_property_access(zend_object *zobj, char *prop_info_name, int prop_info_name_len TSRMLS_DC)
249 516 : {
250 : zend_property_info *property_info;
251 : char *class_name, *prop_name;
252 : zval member;
253 :
254 516 : zend_unmangle_property_name(prop_info_name, prop_info_name_len, &class_name, &prop_name);
255 516 : ZVAL_STRING(&member, prop_name, 0);
256 516 : property_info = zend_get_property_info(zobj->ce, &member, 1 TSRMLS_CC);
257 516 : if (!property_info) {
258 70 : return FAILURE;
259 : }
260 446 : if (prop_info_name[0] == '\0' && prop_info_name[1] != '*') {
261 82 : if (!(property_info->flags & ZEND_ACC_PRIVATE)) {
262 : /* we we're looking for a private prop but found a non private one of the same name */
263 17 : return FAILURE;
264 65 : } else if (strcmp(prop_info_name+1, property_info->name+1)) {
265 : /* we we're looking for a private prop but found a private one of the same name but another class */
266 11 : return FAILURE;
267 : }
268 : }
269 418 : return zend_verify_property_access(property_info, zobj->ce TSRMLS_CC) ? SUCCESS : FAILURE;
270 : }
271 :
272 : static int zend_get_property_guard(zend_object *zobj, zend_property_info *property_info, zval *member, zend_guard **pguard)
273 214 : {
274 : zend_property_info info;
275 : zend_guard stub;
276 :
277 214 : if (!property_info) {
278 22 : property_info = &info;
279 22 : info.name = Z_STRVAL_P(member);
280 22 : info.name_length = Z_STRLEN_P(member);
281 22 : info.h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
282 : }
283 214 : if (!zobj->guards) {
284 40 : ALLOC_HASHTABLE(zobj->guards);
285 40 : zend_hash_init(zobj->guards, 0, NULL, NULL, 0);
286 174 : } else if (zend_hash_quick_find(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void **) pguard) == SUCCESS) {
287 141 : return SUCCESS;
288 : }
289 73 : stub.in_get = 0;
290 73 : stub.in_set = 0;
291 73 : stub.in_unset = 0;
292 73 : stub.in_isset = 0;
293 73 : return zend_hash_quick_add(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
294 : }
295 :
296 : zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
297 21679 : {
298 : zend_object *zobj;
299 21679 : zval *tmp_member = NULL;
300 : zval **retval;
301 21679 : zval *rv = NULL;
302 : zend_property_info *property_info;
303 : int silent;
304 :
305 21679 : silent = (type == BP_VAR_IS);
306 21679 : zobj = Z_OBJ_P(object);
307 :
308 21679 : if (member->type != IS_STRING) {
309 4 : ALLOC_ZVAL(tmp_member);
310 4 : *tmp_member = *member;
311 4 : INIT_PZVAL(tmp_member);
312 4 : zval_copy_ctor(tmp_member);
313 4 : convert_to_string(tmp_member);
314 4 : member = tmp_member;
315 : }
316 :
317 : #if DEBUG_OBJECT_HANDLERS
318 : fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
319 : #endif
320 :
321 : /* make zend_get_property_info silent if we have getter - we may want to use it */
322 21679 : property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC);
323 :
324 21676 : if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) {
325 : zend_guard *guard;
326 :
327 425 : if (zobj->ce->__get &&
328 : zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
329 : !guard->in_get) {
330 : /* have getter - try with it! */
331 107 : ZVAL_ADDREF(object);
332 107 : guard->in_get = 1; /* prevent circular getting */
333 107 : rv = zend_std_call_getter(object, member TSRMLS_CC);
334 107 : guard->in_get = 0;
335 :
336 107 : if (rv) {
337 105 : retval = &rv;
338 105 : if (!rv->is_ref &&
339 : (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)) {
340 17 : if (rv->refcount > 0) {
341 8 : zval *tmp = rv;
342 :
343 8 : ALLOC_ZVAL(rv);
344 8 : *rv = *tmp;
345 8 : zval_copy_ctor(rv);
346 8 : rv->is_ref = 0;
347 8 : rv->refcount = 0;
348 : }
349 17 : if (Z_TYPE_P(rv) != IS_OBJECT) {
350 13 : zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", zobj->ce->name, Z_STRVAL_P(member));
351 : }
352 : }
353 : } else {
354 2 : retval = &EG(uninitialized_zval_ptr);
355 : }
356 107 : zval_ptr_dtor(&object);
357 : } else {
358 211 : if (!silent) {
359 30 : zend_error(E_NOTICE,"Undefined property: %s::$%s", zobj->ce->name, Z_STRVAL_P(member));
360 : }
361 211 : retval = &EG(uninitialized_zval_ptr);
362 : }
363 : }
364 21676 : if (tmp_member) {
365 4 : (*retval)->refcount++;
366 4 : zval_ptr_dtor(&tmp_member);
367 4 : (*retval)->refcount--;
368 : }
369 21676 : return *retval;
370 : }
371 :
372 :
373 : static void zend_std_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
374 359241 : {
375 : zend_object *zobj;
376 359241 : zval *tmp_member = NULL;
377 : zval **variable_ptr;
378 : zend_property_info *property_info;
379 :
380 359241 : zobj = Z_OBJ_P(object);
381 :
382 359241 : if (member->type != IS_STRING) {
383 4 : ALLOC_ZVAL(tmp_member);
384 4 : *tmp_member = *member;
385 4 : INIT_PZVAL(tmp_member);
386 4 : zval_copy_ctor(tmp_member);
387 4 : convert_to_string(tmp_member);
388 4 : member = tmp_member;
389 : }
390 :
391 359241 : property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__set != NULL) TSRMLS_CC);
392 :
393 368125 : if (property_info && zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) {
394 : /* if we already have this value there, we don't actually need to do anything */
395 8893 : if (*variable_ptr != value) {
396 : /* if we are assigning reference, we shouldn't move it, but instead assign variable
397 : to the same pointer */
398 8882 : if (PZVAL_IS_REF(*variable_ptr)) {
399 39 : zval garbage = **variable_ptr; /* old value should be destroyed */
400 :
401 : /* To check: can't *variable_ptr be some system variable like error_zval here? */
402 39 : (*variable_ptr)->type = value->type;
403 39 : (*variable_ptr)->value = value->value;
404 39 : if (value->refcount>0) {
405 39 : zval_copy_ctor(*variable_ptr);
406 : }
407 39 : zval_dtor(&garbage);
408 : } else {
409 8843 : zval *garbage = *variable_ptr;
410 :
411 : /* if we assign referenced variable, we should separate it */
412 8843 : value->refcount++;
413 8843 : if (PZVAL_IS_REF(value)) {
414 7 : SEPARATE_ZVAL(&value);
415 : }
416 8843 : *variable_ptr = value;
417 8843 : zval_ptr_dtor(&garbage);
418 : }
419 : }
420 : } else {
421 350339 : int setter_done = 0;
422 : zend_guard *guard;
423 :
424 350339 : if (zobj->ce->__set &&
425 : zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
426 : !guard->in_set) {
427 61 : ZVAL_ADDREF(object);
428 61 : guard->in_set = 1; /* prevent circular setting */
429 61 : if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) {
430 : /* for now, just ignore it - __set should take care of warnings, etc. */
431 : }
432 61 : setter_done = 1;
433 61 : guard->in_set = 0;
434 61 : zval_ptr_dtor(&object);
435 : }
436 350339 : if (!setter_done && property_info) {
437 : zval **foo;
438 :
439 : /* if we assign referenced variable, we should separate it */
440 350277 : value->refcount++;
441 350277 : if (PZVAL_IS_REF(value)) {
442 11 : SEPARATE_ZVAL(&value);
443 : }
444 350277 : zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void **) &foo);
445 : }
446 : }
447 :
448 359232 : if (tmp_member) {
449 4 : zval_ptr_dtor(&tmp_member);
450 : }
451 359232 : }
452 :
453 : zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
454 132 : {
455 132 : zend_class_entry *ce = Z_OBJCE_P(object);
456 : zval *retval;
457 :
458 132 : if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
459 131 : if(offset == NULL) {
460 : /* [] construct */
461 0 : ALLOC_INIT_ZVAL(offset);
462 : } else {
463 131 : SEPARATE_ARG_IF_REF(offset);
464 : }
465 131 : zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
466 :
467 131 : zval_ptr_dtor(&offset);
468 :
469 131 : if (!retval) {
470 1 : if (!EG(exception)) {
471 0 : zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
472 : }
473 1 : return 0;
474 : }
475 130 : if (EG(exception)) {
476 0 : zval_ptr_dtor(&retval);
477 0 : return 0;
478 : }
479 :
480 : /* Undo PZVAL_LOCK() */
481 130 : retval->refcount--;
482 :
483 130 : return retval;
484 : } else {
485 1 : zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
486 0 : return 0;
487 : }
488 : }
489 :
490 :
491 : static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
492 46 : {
493 46 : zend_class_entry *ce = Z_OBJCE_P(object);
494 :
495 46 : if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
496 46 : if (!offset) {
497 4 : ALLOC_INIT_ZVAL(offset);
498 : } else {
499 42 : SEPARATE_ARG_IF_REF(offset);
500 : }
501 46 : zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value);
502 46 : zval_ptr_dtor(&offset);
503 : } else {
504 0 : zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
505 : }
506 46 : }
507 :
508 :
509 : static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
510 45 : {
511 45 : zend_class_entry *ce = Z_OBJCE_P(object);
512 : zval *retval;
513 : int result;
514 :
515 45 : if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
516 45 : SEPARATE_ARG_IF_REF(offset);
517 45 : zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
518 45 : if (retval) {
519 43 : result = i_zend_is_true(retval);
520 43 : zval_ptr_dtor(&retval);
521 43 : if (check_empty && result && !EG(exception)) {
522 8 : zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
523 8 : if (retval) {
524 8 : result = i_zend_is_true(retval);
525 8 : zval_ptr_dtor(&retval);
526 : }
527 : }
528 : } else {
529 2 : result = 0;
530 : }
531 45 : zval_ptr_dtor(&offset);
532 : } else {
533 0 : zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
534 0 : return 0;
535 : }
536 45 : return result;
537 : }
538 :
539 :
540 : static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC)
541 1728 : {
542 : zend_object *zobj;
543 : zval tmp_member;
544 : zval **retval;
545 : zend_property_info *property_info;
546 :
547 1728 : zobj = Z_OBJ_P(object);
548 :
549 1728 : if (member->type != IS_STRING) {
550 0 : tmp_member = *member;
551 0 : zval_copy_ctor(&tmp_member);
552 0 : convert_to_string(&tmp_member);
553 0 : member = &tmp_member;
554 : }
555 :
556 : #if DEBUG_OBJECT_HANDLERS
557 : fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
558 : #endif
559 :
560 1728 : property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC);
561 :
562 1727 : if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) {
563 : zval *new_zval;
564 : zend_guard *guard;
565 :
566 234 : if (!zobj->ce->__get ||
567 : zend_get_property_guard(zobj, property_info, member, &guard) != SUCCESS ||
568 : (property_info && guard->in_get)) {
569 : /* we don't have access controls - will just add it */
570 99 : new_zval = &EG(uninitialized_zval);
571 :
572 : /* zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */
573 99 : new_zval->refcount++;
574 99 : zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval);
575 : } else {
576 : /* we do have getter - fail and let it try again with usual get/set */
577 36 : retval = NULL;
578 : }
579 : }
580 1727 : if (member == &tmp_member) {
581 0 : zval_dtor(member);
582 : }
583 1727 : return retval;
584 : }
585 :
586 :
587 : static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
588 118 : {
589 : zend_object *zobj;
590 118 : zval *tmp_member = NULL;
591 : zend_property_info *property_info;
592 :
593 118 : zobj = Z_OBJ_P(object);
594 :
595 118 : if (member->type != IS_STRING) {
596 0 : ALLOC_ZVAL(tmp_member);
597 0 : *tmp_member = *member;
598 0 : INIT_PZVAL(tmp_member);
599 0 : zval_copy_ctor(tmp_member);
600 0 : convert_to_string(tmp_member);
601 0 : member = tmp_member;
602 : }
603 :
604 118 : property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__unset != NULL) TSRMLS_CC);
605 :
606 117 : if (!property_info || zend_hash_del(zobj->properties, property_info->name, property_info->name_length+1) == FAILURE) {
607 : zend_guard *guard;
608 :
609 13 : if (zobj->ce->__unset &&
610 : zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
611 : !guard->in_unset) {
612 : /* have unseter - try with it! */
613 5 : ZVAL_ADDREF(object);
614 5 : guard->in_unset = 1; /* prevent circular unsetting */
615 5 : zend_std_call_unsetter(object, member TSRMLS_CC);
616 5 : guard->in_unset = 0;
617 5 : zval_ptr_dtor(&object);
618 : }
619 : }
620 :
621 117 : if (tmp_member) {
622 0 : zval_ptr_dtor(&tmp_member);
623 : }
624 117 : }
625 :
626 :
627 : static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC)
628 23 : {
629 23 : zend_class_entry *ce = Z_OBJCE_P(object);
630 :
631 23 : if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
632 23 : SEPARATE_ARG_IF_REF(offset);
633 23 : zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", NULL, offset);
634 23 : zval_ptr_dtor(&offset);
635 : } else {
636 0 : zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
637 : }
638 23 : }
639 :
640 :
641 : ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS)
642 379 : {
643 379 : zend_internal_function *func = (zend_internal_function *)EG(function_state_ptr)->function;
644 : zval *method_name_ptr, *method_args_ptr;
645 379 : zval *method_result_ptr = NULL;
646 379 : zend_class_entry *ce = Z_OBJCE_P(this_ptr);
647 :
648 379 : ALLOC_ZVAL(method_args_ptr);
649 379 : INIT_PZVAL(method_args_ptr);
650 379 : array_init(method_args_ptr);
651 :
652 379 : if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
653 0 : zval_dtor(method_args_ptr);
654 0 : zend_error(E_ERROR, "Cannot get arguments for __call");
655 0 : RETURN_FALSE;
656 : }
657 :
658 379 : ALLOC_ZVAL(method_name_ptr);
659 379 : INIT_PZVAL(method_name_ptr);
660 379 : ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */
661 :
662 : /* __call handler is called with two arguments:
663 : method name
664 : array of method parameters
665 :
666 : */
667 379 : zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);
668 :
669 371 : if (method_result_ptr) {
670 365 : if (method_result_ptr->is_ref || method_result_ptr->refcount > 1) {
671 2 : RETVAL_ZVAL(method_result_ptr, 1, 1);
672 : } else {
673 361 : RETVAL_ZVAL(method_result_ptr, 0, 1);
674 : }
675 : }
676 :
677 : /* now destruct all auxiliaries */
678 371 : zval_ptr_dtor(&method_args_ptr);
679 371 : zval_ptr_dtor(&method_name_ptr);
680 :
681 : /* destruct the function also, then - we have allocated it in get_method */
682 371 : efree(func);
683 : }
684 :
685 : /* Ensures that we're allowed to call a private method.
686 : * Returns the function address that should be called, or NULL
687 : * if no such function exists.
688 : */
689 : static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
690 67 : {
691 67 : if (!ce) {
692 4 : return 0;
693 : }
694 :
695 : /* We may call a private function if:
696 : * 1. The class of our object is the same as the scope, and the private
697 : * function (EX(fbc)) has the same scope.
698 : * 2. One of our parent classes are the same as the scope, and it contains
699 : * a private function with the same name that has the same scope.
700 : */
701 63 : if (fbc->common.scope == ce && EG(scope) == ce) {
702 : /* rule #1 checks out ok, allow the function call */
703 34 : return fbc;
704 : }
705 :
706 :
707 : /* Check rule #2 */
708 29 : ce = ce->parent;
709 68 : while (ce) {
710 14 : if (ce == EG(scope)) {
711 4 : if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==SUCCESS
712 : && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE
713 : && fbc->common.scope == EG(scope)) {
714 4 : return fbc;
715 : }
716 0 : break;
717 : }
718 10 : ce = ce->parent;
719 : }
720 25 : return NULL;
721 : }
722 :
723 :
724 : ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
725 21 : {
726 21 : return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen TSRMLS_CC) != NULL;
727 : }
728 :
729 :
730 : /* Ensures that we're allowed to call a protected method.
731 : */
732 : ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
733 5094 : {
734 5094 : zend_class_entry *fbc_scope = ce;
735 :
736 : /* Is the context that's calling the function, the same as one of
737 : * the function's parents?
738 : */
739 10556 : while (fbc_scope) {
740 5250 : if (fbc_scope==scope) {
741 4882 : return 1;
742 : }
743 368 : fbc_scope = fbc_scope->parent;
744 : }
745 :
746 : /* Is the function's scope the same as our current object context,
747 : * or any of the parents of our context?
748 : */
749 548 : while (scope) {
750 229 : if (scope==ce) {
751 105 : return 1;
752 : }
753 124 : scope = scope->parent;
754 : }
755 107 : return 0;
756 : }
757 :
758 :
759 : static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc)
760 52 : {
761 52 : return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope;
762 : }
763 :
764 :
765 : static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */
766 381 : {
767 381 : zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
768 381 : call_user_call->type = ZEND_INTERNAL_FUNCTION;
769 381 : call_user_call->module = ce->module;
770 381 : call_user_call->handler = zend_std_call_user_call;
771 381 : call_user_call->arg_info = NULL;
772 381 : call_user_call->num_args = 0;
773 381 : call_user_call->scope = ce;
774 381 : call_user_call->fn_flags = 0;
775 381 : call_user_call->function_name = estrndup(method_name, method_len);
776 381 : call_user_call->pass_rest_by_reference = 0;
777 381 : call_user_call->return_reference = ZEND_RETURN_VALUE;
778 :
779 381 : return (union _zend_function *)call_user_call;
780 : }
781 : /* }}} */
782 :
783 : static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC)
784 206627 : {
785 : zend_object *zobj;
786 : zend_function *fbc;
787 : char *lc_method_name;
788 206627 : zval *object = *object_ptr;
789 : ALLOCA_FLAG(use_heap)
790 :
791 206627 : lc_method_name = do_alloca_with_limit(method_len+1, use_heap);
792 : /* Create a zend_copy_str_tolower(dest, src, src_length); */
793 206627 : zend_str_tolower_copy(lc_method_name, method_name, method_len);
794 :
795 206627 : zobj = Z_OBJ_P(object);
796 206627 : if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) {
797 464 : free_alloca_with_limit(lc_method_name, use_heap);
798 464 : if (zobj->ce->__call) {
799 360 : return zend_get_user_call_function(zobj->ce, method_name, method_len);
800 : } else {
801 104 : return NULL;
802 : }
803 : }
804 :
805 : /* Check access level */
806 206163 : if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
807 : zend_function *updated_fbc;
808 :
809 : /* Ensure that if we're calling a private function, we're allowed to do so.
810 : * If we're not and __call() handler exists, invoke it, otherwise error out.
811 : */
812 30 : 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);
813 30 : if (updated_fbc) {
814 24 : fbc = updated_fbc;
815 : } else {
816 6 : if (zobj->ce->__call) {
817 2 : fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
818 : } else {
819 4 : 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 : "");
820 : }
821 : }
822 : } else {
823 : /* Ensure that we haven't overridden a private function and end up calling
824 : * the overriding public function...
825 : */
826 206133 : if (EG(scope) &&
827 : is_derived_class(fbc->common.scope, EG(scope)) &&
828 : fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {
829 : zend_function *priv_fbc;
830 :
831 8 : if (zend_hash_find(&EG(scope)->function_table, lc_method_name, method_len+1, (void **) &priv_fbc)==SUCCESS
832 : && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
833 : && priv_fbc->common.scope == EG(scope)) {
834 7 : fbc = priv_fbc;
835 : }
836 : }
837 206133 : if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
838 : /* Ensure that if we're calling a protected function, we're allowed to do so.
839 : * If we're not and __call() handler exists, invoke it, otherwise error out.
840 : */
841 36 : if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
842 9 : if (zobj->ce->__call) {
843 2 : fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
844 : } else {
845 7 : 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 : "");
846 : }
847 : }
848 : }
849 : }
850 :
851 206152 : free_alloca_with_limit(lc_method_name, use_heap);
852 206152 : return fbc;
853 : }
854 :
855 :
856 : /* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
857 : ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
858 2438 : {
859 : char *lc_function_name;
860 : zend_function *fbc;
861 :
862 2438 : lc_function_name = zend_str_tolower_dup(function_name_strval, function_name_strlen);
863 :
864 2438 : if (zend_hash_find(&ce->function_table, lc_function_name, function_name_strlen+1, (void **) &fbc)==FAILURE) {
865 18 : efree(lc_function_name);
866 :
867 18 : if (ce->__call &&
868 : EG(This) &&
869 : Z_OBJ_HT_P(EG(This))->get_class_entry &&
870 : instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
871 17 : return zend_get_user_call_function(ce, function_name_strval, function_name_strlen);
872 : } else {
873 1 : char *class_name = ce->name;
874 :
875 1 : if (!class_name) {
876 0 : class_name = "";
877 : }
878 1 : zend_error(E_ERROR, "Call to undefined method %s::%s()", class_name, function_name_strval);
879 : }
880 : }
881 2420 : efree(lc_function_name);
882 :
883 2420 : if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
884 : /* No further checks necessary, most common case */
885 26 : } else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
886 : zend_function *updated_fbc;
887 :
888 : /* Ensure that if we're calling a private function, we're allowed to do so.
889 : */
890 16 : updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC);
891 16 : if (!updated_fbc) {
892 6 : 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 : "");
893 : }
894 10 : fbc = updated_fbc;
895 10 : } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
896 : /* Ensure that if we're calling a protected function, we're allowed to do so.
897 : */
898 10 : if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
899 2 : 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 : "");
900 : }
901 : }
902 :
903 2412 : return fbc;
904 : }
905 :
906 :
907 : ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC)
908 575 : {
909 575 : zval **retval = NULL;
910 575 : zend_class_entry *tmp_ce = ce;
911 : zend_property_info *property_info;
912 : zend_property_info std_property_info;
913 :
914 575 : if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE || (property_info->flags & ZEND_ACC_SHADOW)) {
915 20 : std_property_info.flags = ZEND_ACC_PUBLIC;
916 20 : std_property_info.name = property_name;
917 20 : std_property_info.name_length = property_name_len;
918 20 : std_property_info.h = zend_get_hash_value(std_property_info.name, std_property_info.name_length+1);
919 20 : std_property_info.ce = ce;
920 20 : property_info = &std_property_info;
921 : }
922 :
923 : #if DEBUG_OBJECT_HANDLERS
924 : zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags));
925 : #endif
926 :
927 575 : if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) {
928 14 : if (!silent) {
929 2 : zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
930 : }
931 12 : return NULL;
932 : }
933 :
934 561 : zend_update_class_constants(tmp_ce TSRMLS_CC);
935 :
936 561 : zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval);
937 :
938 561 : if (!retval) {
939 10 : if (silent) {
940 5 : return NULL;
941 : } else {
942 5 : zend_error(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
943 : }
944 : }
945 :
946 551 : return retval;
947 : }
948 :
949 :
950 : ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC)
951 0 : {
952 0 : zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name);
953 0 : return 0;
954 : }
955 :
956 :
957 : ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC)
958 109644 : {
959 109644 : zend_object *zobj = Z_OBJ_P(object);
960 109644 : zend_function *constructor = zobj->ce->constructor;
961 :
962 109644 : if (constructor) {
963 4438 : if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) {
964 : /* No further checks necessary */
965 15 : } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
966 : /* Ensure that if we're calling a private function, we're allowed to do so.
967 : */
968 9 : if (constructor->common.scope != EG(scope)) {
969 3 : if (EG(scope)) {
970 1 : zend_error(E_ERROR, "Call to private %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
971 : } else {
972 2 : zend_error(E_ERROR, "Call to private %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
973 : }
974 : }
975 6 : } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) {
976 : /* Ensure that if we're calling a protected function, we're allowed to do so.
977 : */
978 6 : if (!zend_check_protected(zend_get_function_root_class(constructor), EG(scope))) {
979 2 : if (EG(scope)) {
980 1 : zend_error(E_ERROR, "Call to protected %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
981 : } else {
982 1 : zend_error(E_ERROR, "Call to protected %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
983 : }
984 : }
985 : }
986 : }
987 :
988 109639 : return constructor;
989 : }
990 :
991 :
992 : int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC);
993 :
994 :
995 : static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC)
996 345 : {
997 : zend_object *zobj1, *zobj2;
998 :
999 345 : zobj1 = Z_OBJ_P(o1);
1000 345 : zobj2 = Z_OBJ_P(o2);
1001 :
1002 345 : if (zobj1->ce != zobj2->ce) {
1003 33 : return 1; /* different classes */
1004 : }
1005 312 : return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC);
1006 : }
1007 :
1008 : static int zend_std_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC)
1009 242 : {
1010 : zend_object *zobj;
1011 : int result;
1012 : zval **value;
1013 242 : zval *tmp_member = NULL;
1014 : zend_property_info *property_info;
1015 :
1016 242 : zobj = Z_OBJ_P(object);
1017 :
1018 242 : if (member->type != IS_STRING) {
1019 4 : ALLOC_ZVAL(tmp_member);
1020 4 : *tmp_member = *member;
1021 4 : INIT_PZVAL(tmp_member);
1022 4 : zval_copy_ctor(tmp_member);
1023 4 : convert_to_string(tmp_member);
1024 4 : member = tmp_member;
1025 : }
1026 :
1027 : #if DEBUG_OBJECT_HANDLERS
1028 : fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
1029 : #endif
1030 :
1031 242 : property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC);
1032 :
1033 364 : if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) {
1034 : zend_guard *guard;
1035 :
1036 122 : result = 0;
1037 122 : if ((has_set_exists != 2) &&
1038 : zobj->ce->__isset &&
1039 : zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
1040 : !guard->in_isset) {
1041 : zval *rv;
1042 :
1043 : /* have issetter - try with it! */
1044 3 : ZVAL_ADDREF(object);
1045 3 : guard->in_isset = 1; /* prevent circular getting */
1046 3 : rv = zend_std_call_issetter(object, member TSRMLS_CC);
1047 3 : if (rv) {
1048 3 : result = zend_is_true(rv);
1049 3 : zval_ptr_dtor(&rv);
1050 3 : if (has_set_exists && result && !EG(exception) && zobj->ce->__get && !guard->in_get) {
1051 0 : guard->in_get = 1;
1052 0 : rv = zend_std_call_getter(object, member TSRMLS_CC);
1053 0 : guard->in_get = 0;
1054 0 : if (rv) {
1055 0 : rv->refcount++;
1056 0 : result = i_zend_is_true(rv);
1057 0 : zval_ptr_dtor(&rv);
1058 : }
1059 : }
1060 : }
1061 3 : guard->in_isset = 0;
1062 3 : zval_ptr_dtor(&object);
1063 : }
1064 : } else {
1065 120 : switch (has_set_exists) {
1066 : case 0:
1067 59 : result = (Z_TYPE_PP(value) != IS_NULL);
1068 59 : break;
1069 : default:
1070 20 : result = zend_is_true(*value);
1071 20 : break;
1072 : case 2:
1073 41 : result = 1;
1074 : break;
1075 : }
1076 : }
1077 :
1078 242 : if (tmp_member) {
1079 4 : zval_ptr_dtor(&tmp_member);
1080 : }
1081 242 : return result;
1082 : }
1083 :
1084 :
1085 : zend_class_entry *zend_std_object_get_class(zval *object TSRMLS_DC)
1086 130614 : {
1087 : zend_object *zobj;
1088 130614 : zobj = Z_OBJ_P(object);
1089 :
1090 130614 : return zobj->ce;
1091 : }
1092 :
1093 : int zend_std_object_get_class_name(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
1094 3835 : {
1095 : zend_object *zobj;
1096 : zend_class_entry *ce;
1097 3835 : zobj = Z_OBJ_P(object);
1098 :
1099 3835 : if (parent) {
1100 7 : if (!zobj->ce->parent) {
1101 4 : return FAILURE;
1102 : }
1103 3 : ce = zobj->ce->parent;
1104 : } else {
1105 3828 : ce = zobj->ce;
1106 : }
1107 :
1108 3831 : *class_name_len = ce->name_length;
1109 3831 : *class_name = estrndup(ce->name, ce->name_length);
1110 3831 : return SUCCESS;
1111 : }
1112 :
1113 : ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC)
1114 173016 : {
1115 : zval *retval;
1116 : zend_class_entry *ce;
1117 :
1118 173016 : switch (type) {
1119 : case IS_STRING:
1120 101640 : ce = Z_OBJCE_P(readobj);
1121 101640 : if (ce->__tostring &&
1122 : (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
1123 101052 : if (EG(exception)) {
1124 3 : if (retval) {
1125 1 : zval_ptr_dtor(&retval);
1126 : }
1127 3 : zend_error(E_ERROR, "Method %s::__toString() must not throw an exception", ce->name);
1128 0 : return FAILURE;
1129 : }
1130 101049 : if (Z_TYPE_P(retval) == IS_STRING) {
1131 101045 : INIT_PZVAL(writeobj);
1132 101045 : if (readobj == writeobj) {
1133 100132 : zval_dtor(readobj);
1134 : }
1135 101045 : ZVAL_ZVAL(writeobj, retval, 1, 1);
1136 101045 : if (Z_TYPE_P(writeobj) != type) {
1137 0 : convert_to_explicit_type(writeobj, type);
1138 : }
1139 101045 : return SUCCESS;
1140 : } else {
1141 4 : zval_ptr_dtor(&retval);
1142 4 : INIT_PZVAL(writeobj);
1143 4 : if (readobj == writeobj) {
1144 0 : zval_dtor(readobj);
1145 : }
1146 4 : ZVAL_EMPTY_STRING(writeobj);
1147 4 : zend_error(E_RECOVERABLE_ERROR, "Method %s::__toString() must return a string value", ce->name);
1148 4 : return SUCCESS;
1149 : }
1150 : }
1151 588 : return FAILURE;
1152 : case IS_BOOL:
1153 71058 : INIT_PZVAL(writeobj);
1154 71058 : ZVAL_BOOL(writeobj, 1);
1155 71058 : return SUCCESS;
1156 : case IS_LONG:
1157 192 : ce = Z_OBJCE_P(readobj);
1158 192 : zend_error(E_NOTICE, "Object of class %s could not be converted to int", ce->name);
1159 192 : INIT_PZVAL(writeobj);
1160 192 : if (readobj == writeobj) {
1161 0 : zval_dtor(readobj);
1162 : }
1163 192 : ZVAL_LONG(writeobj, 1);
1164 192 : return SUCCESS;
1165 : case IS_DOUBLE:
1166 58 : ce = Z_OBJCE_P(readobj);
1167 58 : zend_error(E_NOTICE, "Object of class %s could not be converted to double", ce->name);
1168 58 : INIT_PZVAL(writeobj);
1169 58 : if (readobj == writeobj) {
1170 0 : zval_dtor(readobj);
1171 : }
1172 58 : ZVAL_DOUBLE(writeobj, 1);
1173 58 : return SUCCESS;
1174 : default:
1175 68 : INIT_PZVAL(writeobj);
1176 68 : Z_TYPE_P(writeobj) = IS_NULL;
1177 : break;
1178 : }
1179 68 : return FAILURE;
1180 : }
1181 :
1182 :
1183 : ZEND_API zend_object_handlers std_object_handlers = {
1184 : zend_objects_store_add_ref, /* add_ref */
1185 : zend_objects_store_del_ref, /* del_ref */
1186 : zend_objects_clone_obj, /* clone_obj */
1187 :
1188 : zend_std_read_property, /* read_property */
1189 : zend_std_write_property, /* write_property */
1190 : zend_std_read_dimension, /* read_dimension */
1191 : zend_std_write_dimension, /* write_dimension */
1192 : zend_std_get_property_ptr_ptr, /* get_property_ptr_ptr */
1193 : NULL, /* get */
1194 : NULL, /* set */
1195 : zend_std_has_property, /* has_property */
1196 : zend_std_unset_property, /* unset_property */
1197 : zend_std_has_dimension, /* has_dimension */
1198 : zend_std_unset_dimension, /* unset_dimension */
1199 : zend_std_get_properties, /* get_properties */
1200 : zend_std_get_method, /* get_method */
1201 : NULL, /* call_method */
1202 : zend_std_get_constructor, /* get_constructor */
1203 : zend_std_object_get_class, /* get_class_entry */
1204 : zend_std_object_get_class_name, /* get_class_name */
1205 : zend_std_compare_objects, /* compare_objects */
1206 : zend_std_cast_object_tostring, /* cast_object */
1207 : NULL, /* count_elements */
1208 : };
1209 :
1210 : /*
1211 : * Local variables:
1212 : * tab-width: 4
1213 : * c-basic-offset: 4
1214 : * indent-tabs-mode: t
1215 : * End:
1216 : */
|