2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
19 #include "php_pq_object.h"
20 #include "php_pq_misc.h"
22 void *php_pq_object_create(zend_class_entry
*ce
, void *intern
, size_t obj_size
, zend_object_handlers
*oh
, HashTable
*ph
)
24 php_pq_object_t
*o
= ecalloc(1, obj_size
+ zend_object_properties_size(ce
));
26 zend_object_std_init(&o
->zo
, ce
);
27 object_properties_init(&o
->zo
, ce
);
32 zend_hash_init(&o
->gc
, 0, NULL
, NULL
, 0);
37 void php_pq_object_dtor(zend_object
*o
)
39 php_pq_object_t
*obj
= PHP_PQ_OBJ(NULL
, o
);
41 zend_hash_destroy(&obj
->gc
);
42 zend_object_std_dtor(o
);
45 void php_pq_object_to_zval(void *o
, zval
*zv
)
47 php_pq_object_t
*obj
= o
;
49 ZVAL_OBJ(zv
, &obj
->zo
);
53 void php_pq_object_to_zval_no_addref(void *o
, zval
*zv
)
55 php_pq_object_t
*obj
= o
;
57 ZVAL_OBJ(zv
, &obj
->zo
);
60 void php_pq_object_addref(void *o
)
62 php_pq_object_t
*obj
= o
;
66 ++GC_REFCOUNT(&obj
->zo
);
70 void php_pq_object_delref(void *o
)
72 php_pq_object_t
*obj
= o
;
75 /* this should gc immediately */
76 ZVAL_OBJ(&tmp
, &obj
->zo
);
80 struct apply_pi_to_ht_arg
{
82 php_pq_object_t
*pq_obj
;
86 static int apply_pi_to_ht(zval
*p
, void *a
)
88 zend_property_info
*pi
= Z_PTR_P(p
);
89 struct apply_pi_to_ht_arg
*arg
= a
;
92 php_pq_object_prophandler_t
*handler
;
94 if ((handler
= zend_hash_find_ptr(arg
->pq_obj
->prophandler
, pi
->name
)) && handler
->gc
) {
97 ZVAL_ARR(&return_value
, arg
->ht
);
98 handler
->gc(arg
->pq_obj
, &return_value
);
101 zval tmp_prop
, *property
;
102 #if PHP_VERSION_ID < 80000
105 ZVAL_OBJ(&zobj
, &arg
->pq_obj
->zo
);
106 # if PHP_VERSION_ID < 70100
107 property
= zend_read_property(arg
->pq_obj
->zo
.ce
, &zobj
, pi
->name
->val
, pi
->name
->len
, 0, &tmp_prop
);
109 property
= zend_read_property_ex(arg
->pq_obj
->zo
.ce
, &zobj
, pi
->name
, 0, &tmp_prop
);
112 property
= zend_read_property_ex(arg
->pq_obj
->zo
.ce
, &arg
->pq_obj
->zo
, pi
->name
, 0, &tmp_prop
);
114 zend_hash_update(arg
->ht
, pi
->name
, property
);
117 return ZEND_HASH_APPLY_KEEP
;
120 static inline HashTable
*php_pq_object_debug_info_ex(zend_object
*object
, int *temp
)
122 struct apply_pi_to_ht_arg arg
= {NULL
};
125 ALLOC_HASHTABLE(arg
.ht
);
126 ZEND_INIT_SYMTABLE(arg
.ht
);
128 arg
.pq_obj
= PHP_PQ_OBJ(NULL
, object
);
131 zend_hash_apply_with_argument(&arg
.pq_obj
->zo
.ce
->properties_info
, apply_pi_to_ht
, &arg
);
135 #if PHP_VERSION_ID >= 80000
136 HashTable
*php_pq_object_debug_info(zend_object
*object
, int *temp
)
138 return php_pq_object_debug_info_ex(object
, temp
);
141 HashTable
*php_pq_object_debug_info(zval
*object
, int *temp
)
143 return php_pq_object_debug_info_ex(Z_OBJ_P(object
), temp
);
147 static inline HashTable
*php_pq_object_properties_ex(zend_object
*object
, HashTable
*props
)
149 struct apply_pi_to_ht_arg arg
= {NULL
};
152 arg
.pq_obj
= PHP_PQ_OBJ(NULL
, object
);
155 zend_hash_apply_with_argument(&arg
.pq_obj
->zo
.ce
->properties_info
, apply_pi_to_ht
, &arg
);
159 #if PHP_VERSION_ID >= 80000
160 HashTable
*php_pq_object_properties(zend_object
*object
)
162 return php_pq_object_properties_ex(object
, zend_std_get_properties(object
));
165 HashTable
*php_pq_object_properties(zval
*object
)
167 return php_pq_object_properties_ex(Z_OBJ_P(object
), zend_std_get_properties(object
));
171 static inline HashTable
*php_pq_object_get_gc_ex(zend_object
*object
, HashTable
*props
, zval
**table
, int *n
)
173 struct apply_pi_to_ht_arg arg
= {NULL
};
175 arg
.pq_obj
= PHP_PQ_OBJ(NULL
, object
);
176 arg
.ht
= &arg
.pq_obj
->gc
;
179 if (GC_REFCOUNT(arg
.ht
) == 1) {
180 zend_hash_clean(arg
.ht
);
181 zend_hash_copy(arg
.ht
, props
, NULL
);
182 zend_hash_apply_with_argument(&arg
.pq_obj
->zo
.ce
->properties_info
, apply_pi_to_ht
, &arg
);
190 #if PHP_VERSION_ID >= 80000
191 HashTable
*php_pq_object_get_gc(zend_object
*object
, zval
**table
, int *n
)
193 return php_pq_object_get_gc_ex(object
, zend_std_get_properties(object
), table
, n
);
196 HashTable
*php_pq_object_get_gc(zval
*object
, zval
**table
, int *n
)
198 return php_pq_object_get_gc_ex(Z_OBJ_P(object
), zend_std_get_properties(object
), table
, n
);
202 zend_class_entry
*ancestor(zend_class_entry
*ce
)
210 static inline int php_pq_object_read_prop_ex(zend_object
*object
, zend_string
*member
, int type
, zval
*return_value
)
212 php_pq_object_t
*obj
= PHP_PQ_OBJ(NULL
, object
);
213 php_pq_object_prophandler_t
*handler
;
216 php_error(E_RECOVERABLE_ERROR
, "%s not initialized", ancestor(obj
->zo
.ce
)->name
->val
);
217 } else if (!(handler
= zend_hash_find_ptr(obj
->prophandler
, member
)) || !handler
->read
) {
218 /* default handler */
219 } else if (type
!= BP_VAR_R
) {
220 php_error(E_WARNING
, "Cannot access %s properties by reference or array key/index", ancestor(obj
->zo
.ce
)->name
->val
);
222 handler
->read(obj
, return_value
);
228 #if PHP_VERSION_ID >= 80000
229 zval
*php_pq_object_read_prop(zend_object
*object
, zend_string
*member
, int type
, void **cache_slot
, zval
*tmp
)
231 if (SUCCESS
!= php_pq_object_read_prop_ex(object
, member
, type
, tmp
)) {
232 return zend_std_read_property(object
, member
, type
, cache_slot
, tmp
);
235 zend_std_write_property(object
, member
, tmp
, cache_slot
);
243 zval
*php_pq_object_read_prop(zval
*object
, zval
*member
, int type
, void **cache_slot
, zval
*tmp
)
245 zend_string
*member_str
= zval_get_string(member
);
247 if (SUCCESS
!= php_pq_object_read_prop_ex(Z_OBJ_P(object
), member_str
, type
, tmp
)) {
248 zend_string_release(member_str
);
249 return zend_get_std_object_handlers()->read_property(object
, member
, type
, cache_slot
, tmp
);
251 zend_string_release(member_str
);
253 zend_std_write_property(object
, member
, tmp
, cache_slot
);
262 static inline int php_pq_object_write_prop_ex(zend_object
*object
, zend_string
*member
, zval
*value
)
264 php_pq_object_t
*obj
= PHP_PQ_OBJ(NULL
, object
);
265 php_pq_object_prophandler_t
*handler
;
268 php_error(E_RECOVERABLE_ERROR
, "%s not initialized", ancestor(obj
->zo
.ce
)->name
->val
);
269 } else if (!(handler
= zend_hash_find_ptr(obj
->prophandler
, member
))) {
270 /* default handler */
272 if (handler
->write
) {
273 handler
->write(obj
, value
);
279 #if PHP_VERSION_ID >= 80000
280 zval
*php_pq_object_write_prop(zend_object
*object
, zend_string
*member
, zval
*value
, void **cache_slot
)
282 if (SUCCESS
!= php_pq_object_write_prop_ex(object
, member
, value
)) {
283 return zend_std_write_property(object
, member
, value
, cache_slot
);
287 #elif PHP_VERSION_ID >= 70400
288 zval
*php_pq_object_write_prop(zval
*object
, zval
*member
, zval
*value
, void **cache_slot
)
290 zend_string
*member_str
= zval_get_string(member
);
291 if (SUCCESS
!= php_pq_object_write_prop_ex(Z_OBJ_P(object
), member_str
, value
)) {
292 value
= zend_std_write_property(object
, member
, value
, cache_slot
);
294 zend_string_release(member_str
);
298 void php_pq_object_write_prop(zval
*object
, zval
*member
, zval
*value
, void **cache_slot
)
300 zend_string
*member_str
= zval_get_string(member
);
301 if (SUCCESS
!= php_pq_object_write_prop_ex(Z_OBJ_P(object
), member_str
, value
)) {
302 zend_std_write_property(object
, member
, value
, cache_slot
);
304 zend_string_release(member_str
);
308 #if PHP_VERSION_ID >= 80000
309 zval
*php_pq_object_get_prop_ptr_null(zend_object
*object
, zend_string
*member
, int type
, void **cache_slot
)
314 zval
*php_pq_object_get_prop_ptr_null(zval
*object
, zval
*member
, int type
, void **cache_slot
)
320 void php_pq_object_prophandler_dtor(zval
*zv
) {
321 pefree(Z_PTR_P(zv
), 1);