root/trunk/midgard/apis/php5/php_midgard_gobject_generic.c

Revision 16340, 38.1 kB (checked in by piotras, 7 months ago)

Convert boxed type to zend array only if value holds array.
In any other case throw warning.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* Copyright (C) 2007 Piotr Pokora <piotrek.pokora@gmail.com>
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU Lesser General Public License as published
4  * by the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15 */
16
17 #include "php_midgard.h"
18 #include "php_midgard_gobject.h"
19 #include <TSRM.h>
20 #include <zend_interfaces.h>
21
22 /* static prototypes */
23 static void php_midgard_datetime_from_string(const gchar *date, zval *zvalue);
24 static zval *php_midgard_string_from_datetime(zval *zvalue);
25 static gboolean __callback_call(zval *callback_array, zval **retval, guint n_params, zval ***params);
26 static void __php_midgard_closure_free(gpointer data);
27
28 static void php_midgard_closure_default_marshal(GClosure *closure,
29                 GValue *return_value, guint n_param_values,
30                 const GValue *param_values, gpointer invocation_hint,
31                 gpointer marshal_data);
32 static GClosure *php_midgard_closure_new_default(zval *callback, zval *zobject, zval *zval_array TSRMLS_DC);
33
34 php_midgard_gobject *php_midgard_zend_object_store_get_object(zval *zobject TSRMLS_CC);
35
36 /* GVALUE ROUTINES */
37
38 static gboolean php_midgard_gvalue_from_zval(zval *zvalue, GValue *gvalue)
39 {
40         g_assert(zvalue != NULL);
41
42         HashTable *zhash;
43         GValueArray *array;
44         zval **value;
45         HashPosition iterator;
46         GValue *tmpval;
47         zval*date_zval;
48         zend_class_entry *dtce;
49         gchar *lstring;
50
51         switch(Z_TYPE_P(zvalue)) {
52                
53                 case IS_ARRAY:                 
54                         zhash = Z_ARRVAL_P(zvalue);
55                         array = g_value_array_new(zend_hash_num_elements(zhash));
56                        
57                         zend_hash_internal_pointer_reset_ex(zhash, &iterator);
58                         while (zend_hash_get_current_data_ex(
59                                                 zhash, (void **)&value, &iterator) == SUCCESS) {
60                                
61                                 tmpval = php_midgard_zval2gvalue(*value);
62                                 g_value_array_append(array, tmpval);
63                                 g_value_unset(tmpval);
64                                 g_free(tmpval);
65                                 zend_hash_move_forward_ex(zhash, &iterator);
66                         }
67                        
68                         g_value_init(gvalue, G_TYPE_VALUE_ARRAY);
69                         g_value_take_boxed(gvalue, array);
70                         break;
71
72                 case IS_BOOL:                   
73                         g_value_init(gvalue, G_TYPE_BOOLEAN);
74                         g_value_set_boolean(gvalue, Z_BVAL_P(zvalue));
75                         break;
76
77                 case IS_LONG:                   
78                         g_value_init(gvalue, G_TYPE_INT);
79                         g_value_set_int(gvalue, Z_LVAL_P(zvalue));     
80                         break;
81
82                 case IS_DOUBLE:                 
83                         g_value_init(gvalue, G_TYPE_FLOAT);
84                         lstring = setlocale(LC_NUMERIC, "0");
85                         setlocale(LC_NUMERIC, "C");
86                         g_value_set_float(gvalue, (gfloat)Z_DVAL_P(zvalue));
87                         setlocale(LC_ALL, lstring);
88                         break;
89
90                 case IS_STRING:                 
91                         g_value_init(gvalue, G_TYPE_STRING);
92                         g_value_set_string(gvalue, Z_STRVAL_P(zvalue));
93                         break;
94        
95                 case IS_OBJECT:
96                        
97                         dtce = php_midgard_get_baseclass_ptr_by_name((const gchar *)"DateTime");
98
99                         /* DateTime object, convert to string value */
100                         if(Z_OBJCE_P(zvalue) == dtce) {
101                                
102                                 date_zval = php_midgard_string_from_datetime(zvalue);
103                                 g_value_init(gvalue, G_TYPE_STRING);
104                                 g_value_set_string(gvalue, Z_STRVAL_P(date_zval));
105                                 zval_dtor(date_zval);                                   
106
107                         } else {
108                                        
109                                 php_midgard_gobject *php_gobject =
110                                         php_midgard_zend_object_store_get_object(
111                                                         zvalue TSRMLS_CC);
112                        
113                                 if(php_gobject && php_gobject->gobject) {
114
115                                         if(!G_IS_OBJECT(php_gobject->gobject)) {
116                                                
117                                                 g_warning("zval2gvalue conversion failed");
118                                                 return FALSE;
119                                         }
120                                
121                                         GObject *gobject = G_OBJECT(php_gobject->gobject);
122                                                
123                                         g_value_init(gvalue, G_TYPE_OBJECT);
124                                         g_value_set_object(gvalue, gobject);
125                                 }
126                         }
127                         break;
128
129                 default:
130                         /* FIXME, we can not fallback to string type */
131                         convert_to_string(zvalue);
132                         g_value_init(gvalue, G_TYPE_STRING);
133                         g_value_set_string(gvalue, Z_STRVAL_P(zvalue));
134         }       
135
136         return TRUE;
137 }
138
139 GValue *php_midgard_zval2gvalue(zval *zvalue)
140 {
141         g_assert(zvalue != NULL);
142
143         GValue *gvalue = g_new0(GValue, 1);
144        
145         if(!php_midgard_gvalue_from_zval(zvalue, gvalue))
146                 return NULL;
147
148         return gvalue;
149 }
150
151 gboolean php_midgard_gvalue2zval(GValue *gvalue, zval *zvalue) 
152 {
153         g_assert(gvalue);
154         g_assert(zvalue);
155         gchar *tmpstr;
156         double f, dpval, tmp_val;
157         const gchar *gclass_name;
158         guint i;
159         GObject *gobject_property;
160         GValueArray *array;
161         GValue *arr_val;
162         zval *zarr_val;
163
164         /* It's overloaded, but we need to initialize DateTime object */
165         /* Disabled for a while
166         if(dbklass != NULL) {
167                 
168                 MidgardReflectionProperty *mrp =
169                         midgard_reflection_property_new(dbklass);
170                 GType mtype =
171                         midgard_reflection_property_get_midgard_type(mrp, pname);
172                 
173                 if(mtype == MGD_TYPE_TIMESTAMP) {
174
175                         php_midgard_datetime_from_string(
176                                         g_value_get_string(gvalue), zvalue);
177                         return TRUE;
178                 }
179         }*/
180
181         /* Generic GValue */
182         switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(gvalue))) {
183                
184                 case G_TYPE_STRING:
185                         tmpstr = (gchar *)g_value_get_string(gvalue);
186                         if(!tmpstr)
187                                 tmpstr = "";
188                         ZVAL_STRING(zvalue, tmpstr, 1);
189                         return TRUE;
190                         break;
191
192                 case G_TYPE_INT:
193                         ZVAL_LONG(zvalue, g_value_get_int(gvalue));
194                         return TRUE;
195                         break;
196                
197                 case G_TYPE_UINT:
198                         ZVAL_LONG(zvalue, g_value_get_uint(gvalue));
199                         return TRUE;
200                         break;
201                
202                 case G_TYPE_BOOLEAN:
203                         ZVAL_BOOL(zvalue, g_value_get_boolean(gvalue));
204                         return TRUE;
205                         break;
206                
207                 case G_TYPE_FLOAT:
208                         /* I follow code from PHP_ROUND_WITH_FUZZ macro.
209                          * If You find better way to add double property value,
210                          * fell free to change this code. We do not have to worry
211                          * about locale settings at this point ( I hope so ) */
212                         dpval = (gdouble)g_value_get_float(gvalue);
213                         tmp_val=dpval;
214                         f = pow(10.0, (double) 6);
215                         tmp_val *= f;
216                         if (tmp_val >= 0.0) {
217                                 tmp_val = floor(tmp_val + 0.50000000001);
218                         } else {
219                                 tmp_val = ceil(tmp_val - 0.50000000001);
220                         }
221                         tmp_val /= f;
222                         dpval = !zend_isnan(tmp_val) ? tmp_val : dpval;
223                         ZVAL_DOUBLE(zvalue, dpval);
224                         return TRUE;
225                         break;
226
227                 case G_TYPE_OBJECT:
228                
229                         gobject_property = g_value_get_object(gvalue);
230
231                         if(gobject_property) {
232                                
233                                 gclass_name =
234                                         G_OBJECT_TYPE_NAME(gobject_property);
235                                        
236                                 if (!gclass_name)
237                                         return FALSE;
238                                
239                                 /* TODO , check zval ref and alloc */
240                                 php_midgard_gobject_init(zvalue,
241                                                 gclass_name, gobject_property, FALSE);
242
243                                 return TRUE;
244                        
245                         } else {
246
247                                 ZVAL_NULL(zvalue);
248                                 /* TODO, implement this, currently we do not
249                                  * handle such case */
250                                 /*zvalue->value.obj =
251                                         php_midgard_gobject_new(*ce TSRMLS_CC);
252                                         //zend_objects_new(&zobject, *ce TSRMLS_CC);
253                                 Z_OBJ_HT_P(zvalue) = &php_midgard_gobject_handlers;
254                                 zend_object_std_init(zobject, *ce TSRMLS_CC); */               
255                         }                       
256
257                         break;
258                        
259                 case G_TYPE_BOXED:
260
261                         if(G_VALUE_TYPE(gvalue) == G_TYPE_VALUE_ARRAY) {
262
263                                 array_init(zvalue);
264
265                                 array = (GValueArray *) g_value_get_boxed(gvalue);
266
267                                 if(array == NULL)
268                                         return TRUE;
269
270                                 for (i = 0; i < array->n_values; i++) {
271
272                                         arr_val = g_value_array_get_nth(array, i);
273                                         MAKE_STD_ZVAL(zarr_val);
274                                         php_midgard_gvalue2zval(arr_val, zarr_val);
275                                         add_index_zval(zvalue, i, zarr_val);
276                                 }
277                        
278                         } else {
279                                
280                                 g_warning("Can not convert boxed Gvalue to zend zval");
281                                 ZVAL_NULL(zvalue);
282                         }
283                         break;
284                
285                 default:
286                         ZVAL_NULL(zvalue);
287                         break;
288         }
289        
290         return FALSE;
291 }
292
293 /* OBJECTS ROUTINES */
294
295 php_midgard_gobject *
296 php_midgard_zend_object_store_get_object(zval *zobject TSRMLS_CC)
297 {
298         php_midgard_gobject *php_gobject =
299                 (php_midgard_gobject *) zend_object_store_get_object(zobject TSRMLS_CC);
300
301         if(php_gobject) {
302
303                 if(php_gobject->gobject)
304                         return php_gobject;
305
306                 /* Important! We must ensure we have underlying GObject always! */
307                 /* Failed code case: custom construstor wich does not invoke parent's one */
308                 /* Or any other behaviour which makes underlying gobject
309                  * not being initialized */
310                 if(php_gobject->gobject == NULL) {
311
312                         /* Enable this log when MidCOM 3 is stable */
313                         /* php_error(E_NOTICE, "Invalid object's constructor (%s)", Z_OBJCE_P(zobject)->name); */
314
315                         zend_class_entry *ce =
316                                 Z_OBJCE_P(zobject);
317                         while (ce->type != ZEND_INTERNAL_CLASS && ce->parent != NULL) {
318                                 ce = ce->parent;
319                         }
320
321                         guint classname_length = strlen(
322                                         ce->name);
323                         gchar *_classname = g_ascii_strdown(
324                                         ce->name, classname_length);
325                        
326                         GType class_type =
327                                 g_type_from_name((const gchar *) _classname);
328                        
329                         if(g_type_parent(class_type) == MIDGARD_TYPE_OBJECT) {
330                                
331                                 php_gobject->gobject =
332                                         (GObject *)midgard_object_new(
333                                                         mgd_handle(),
334                                                         (const gchar *) _classname,
335                                                         NULL); 
336                         } else {
337                        
338                                 g_warning("Creating new underlying '%s' GObject. Missed constructor?",
339                                                 g_type_name(class_type));
340                                 php_gobject->gobject =
341                                                 g_object_new(class_type, NULL);
342                        
343                         }
344                        
345                         g_free(_classname);
346
347                         return php_gobject;
348                 }       
349         }
350
351         return NULL;
352 }
353
354 int php_midgard_gobject_has_property(zval *zobject, zval *prop, int type TSRMLS_DC)
355 {
356         int _retval = 0;
357         zend_object_handlers *std_hnd;
358        
359         php_midgard_gobject *php_gobject =
360                 php_midgard_zend_object_store_get_object(zobject TSRMLS_CC);
361        
362         GObject *gobject =
363                 G_OBJECT(php_gobject->gobject);
364        
365         if(Z_STRVAL_P(prop) == NULL) {
366                 g_warning("Can not check property with NULL name");
367                 return _retval = 0;
368         }
369
370         if(g_str_equal(Z_STRVAL_P(prop), "")) {
371                 g_warning("Can not check property with empty name");
372                 return _retval = 0;
373         }
374
375         GParamSpec *pspec =
376                 g_object_class_find_property(
377                                 G_OBJECT_GET_CLASS(gobject), Z_STRVAL_P(prop));
378
379         if(pspec) {
380
381                 if(type == 2) {
382                         _retval = 1;
383                 } else {
384                         GValue pval = {0, };
385                         g_value_init(&pval, pspec->value_type);
386                         g_object_get_property(gobject, Z_STRVAL_P(prop), &pval);
387
388                         switch(pspec->value_type) {
389                                
390                                 case G_TYPE_STRING:
391                                         if(g_value_get_string(&pval))
392                                                 _retval = 1;   
393                                         break;
394
395                                 case G_TYPE_OBJECT:
396                                         if(g_value_get_object(&pval))
397                                                 _retval = 1;
398                                         break;
399
400                                 default:
401                                         _retval = 1;
402                                         break;
403                         }
404
405                         g_value_unset(&pval);
406                 }
407         } else {
408                
409                 std_hnd = zend_get_std_object_handlers();
410                 _retval = std_hnd->has_property(zobject, prop, BP_VAR_NA TSRMLS_CC);
411         }
412
413         return _retval;
414 }
415
416 /* Read Zend object property using underlying GObject's one */
417 zval *php_midgard_gobject_read_property(
418                 zval *zobject, zval *prop, int type TSRMLS_DC)
419 {
420         zval *_retval;
421         zend_object_handlers *std_hnd;
422         gboolean is_native_property = FALSE;
423         GParamSpec *pspec = NULL;
424
425         php_midgard_gobject *php_gobject =
426                 php_midgard_zend_object_store_get_object(zobject TSRMLS_CC);
427
428         GObject *gobject =
429                 G_OBJECT(php_gobject->gobject);
430
431
432         if(gobject && Z_STRVAL_P(prop) != NULL) {
433                
434                 GObjectClass *klass = G_OBJECT_GET_CLASS(gobject);
435                
436                 /* Find GObject property */
437                 if(G_IS_OBJECT_CLASS(klass)) {
438                        
439                         pspec = g_object_class_find_property(klass, Z_STRVAL_P(prop));
440                        
441                         if(pspec != NULL)
442                                 is_native_property = TRUE;
443                 }
444         }
445
446         /* If found, get property's gvalue. Create zval from it and return */
447         if(is_native_property) {
448
449                 GValue pval = {0, };
450                 g_value_init(&pval, pspec->value_type);
451                 g_object_get_property(G_OBJECT(gobject), Z_STRVAL_P(prop), &pval);
452                 MAKE_STD_ZVAL(_retval);
453                 php_midgard_gvalue2zval(&pval, _retval);
454                 g_value_unset(&pval);
455
456                 /* if(pspec->value_type == MGD_TYPE_TIMESTAMP) g_warning("IS DATE"); */
457        
458         } else {
459                
460                 /* Property is not found. Fallback to zend's property handler
461                  * Piotras: I have no idea what type should be passed instead
462                  * of BP_VAR_NA. The point is to throw warning when property
463                  * is not registered for (sub)class. */
464                 std_hnd = zend_get_std_object_handlers();
465                 _retval = std_hnd->read_property(zobject, prop, BP_VAR_NA TSRMLS_CC);
466         }
467
468         return _retval;
469 }
470
471 static void _convert_value(zval *value, GType vtype)
472 {
473         switch(vtype) {
474
475                 case G_TYPE_STRING:
476                         if(Z_TYPE_P(value) != IS_STRING)
477                                 convert_to_string(value);
478                         break;
479
480                 case G_TYPE_UINT:
481                 case G_TYPE_INT:
482                         if(Z_TYPE_P(value) != IS_LONG)
483                                 convert_to_long(value);
484                         break;
485                
486                 case G_TYPE_BOOLEAN:
487                         if(Z_TYPE_P(value) != IS_BOOL)
488                                 convert_to_boolean(value);
489                         break;
490
491                 case G_TYPE_FLOAT:
492                         if(Z_TYPE_P(value) != IS_DOUBLE)
493                                 convert_to_double(value);
494                         break;
495
496                 case G_TYPE_OBJECT:
497                         if(Z_TYPE_P(value) == IS_NULL)
498                                 return;
499                         if(Z_TYPE_P(value) != IS_OBJECT)
500                                 convert_to_object(value);
501                         break;
502         }
503
504         return;
505 }
506
507 void php_midgard_gobject_write_property(
508                 zval *zobject, zval *prop, zval *value TSRMLS_DC)
509 {
510         zend_object_handlers *std_hnd =
511                 zend_get_std_object_handlers();
512
513         php_midgard_gobject *php_gobject =
514                 php_midgard_zend_object_store_get_object(zobject TSRMLS_CC);
515
516         GObject *gobject = G_OBJECT(php_gobject->gobject);
517
518         /* Find GObject property */
519         GParamSpec *pspec =
520                 g_object_class_find_property(
521                                 G_OBJECT_GET_CLASS(gobject), Z_STRVAL_P(prop));
522                
523         /* If found, set property's gvalue.*/
524         if(pspec) {
525
526                 /* Property type might be initialized with IS_STRING or unset type.
527                  * Check property's type and convert if needed. */
528                 _convert_value(value, pspec->value_type);       
529
530                 GValue *gvalue =
531                         php_midgard_zval2gvalue(value);
532                 if(gvalue)
533                         g_object_set_property(gobject, Z_STRVAL_P(prop), gvalue);
534                 g_value_unset(gvalue);
535                 g_free(gvalue);
536                 std_hnd->write_property(zobject, prop, value TSRMLS_CC);
537
538         } else {
539
540                 std_hnd->write_property(zobject, prop, value TSRMLS_CC);
541         }
542        
543         return;
544 }
545
546 /* "Register" object's properties ( constructor time ) */
547 void php_midgard_zendobject_register_properties (
548                 zval *zobject, GObject *gobject)
549 {
550         if(gobject == NULL)
551                 return;
552
553         guint n_prop, i, cnl;
554         zval *tmp_object;
555         const gchar *gclass_name;
556         gchar *classname;
557         zend_class_entry **ce;
558         GValue pval = {0, };
559
560         GParamSpec **props =
561                 g_object_class_list_properties(
562                                 G_OBJECT_GET_CLASS(gobject), &n_prop);
563
564         for (i = 0; i < n_prop; i++) { 
565
566                 switch(props[i]->value_type) {
567
568                         case G_TYPE_STRING:
569                                 add_property_string(zobject,
570                                                 (gchar*)props[i]->name, "", 1);
571                                 break;
572
573                         case G_TYPE_UINT:
574                         case G_TYPE_INT:
575                                 add_property_long(zobject,
576                                                 (gchar*)props[i]->name, 0);
577                                 break;
578
579                         case G_TYPE_BOOLEAN:
580                                 add_property_bool(zobject,
581                                                 (gchar*)props[i]->name, FALSE);
582                                 break;
583
584                         case G_TYPE_FLOAT:
585                                 add_property_double(zobject,
586                                                 (gchar*)props[i]->name, 0);
587                                 break;
588
589                         case G_TYPE_OBJECT:
590                                 g_value_init(&pval, props[i]->value_type);
591                                 g_object_get_property(gobject,
592                                                 (gchar*)props[i]->name, &pval);
593                                 gclass_name = g_type_name(G_OBJECT_TYPE(
594                                                         G_OBJECT(g_value_get_object(&pval))));
595                                 if(gclass_name) {
596                                         cnl = strlen(gclass_name);
597                                         classname =
598                                                 g_ascii_strdown(gclass_name, cnl);
599                                         if (zend_hash_find(CG(class_table),
600                                                                 classname,
601                                                                 cnl+1,
602                                                                 (void **) &ce)  == SUCCESS) {
603                                                 MAKE_STD_ZVAL(tmp_object);
604                                                 object_init_ex(tmp_object, *ce);
605                                                 php_midgard_zendobject_register_properties(tmp_object, G_OBJECT(g_value_get_object(&pval)));
606                                                 add_property_zval(zobject,
607                                                                 (gchar*)props[i]->name,
608                                                                 tmp_object);
609                                         }
610
611                                 }
612                                 break;
613
614                         default:
615                                 add_property_unset(zobject, (gchar*)props[i]->name);
616                                 break;
617                 }
618         }
619
620         g_free(props);
621
622         return;
623 }
624
625 /* Get object's properties */
626 HashTable *php_midgard_zendobject_get_properties (
627                 zval *zobject TSRMLS_DC)
628 {
629         php_midgard_gobject *php_gobject =
630                 php_midgard_zend_object_store_get_object(zobject TSRMLS_CC);
631
632         GObject *gobject = G_OBJECT(php_gobject->gobject);
633
634         /* Properties already set, we will update properties hash in
635          * write_property handler's hook */
636         if(php_gobject->properties)
637                 return php_gobject->zo.properties;
638
639         GParamSpec **props;
640         guint propn, i;
641         GValue pval = {0, };
642         zval *tmp;
643
644         props = g_object_class_list_properties(
645                         G_OBJECT_GET_CLASS(gobject), &propn);
646
647         for (i = 0; i < propn; i++) {
648        
649                 if(g_object_class_find_property(
650                                         G_OBJECT_GET_CLASS(gobject),
651                                         props[i]->name)) {     
652
653                         g_value_init(&pval, props[i]->value_type);
654                         g_object_get_property(gobject,
655                                         (gchar*)props[i]->name, &pval);
656
657                         /* TODO , add this functionality if needed.
658                          *
659                          * GType base_type = G_TYPE_FUNDAMENTAL(props[i]->value_type);
660                          * if(base_type == G_TYPE_OBJECT) {
661                          *     
662                          *      MgdObject *new_object =
663                          *              midgard_object_new(mgd_handle(),
664                          *                      g_param_spec_get_nick(props[i]), NULL);
665                          *
666                          *      g_value_set_object(&pval, new_object);
667                          *     
668                          *      // Create new zend object and add it to store
669                          * }
670                          *
671                          */
672                        
673                         MAKE_STD_ZVAL(tmp);
674                         php_midgard_gvalue2zval(&pval, tmp);
675                         zend_hash_update(php_gobject->zo.properties,
676                                         props[i]->name, strlen(props[i]->name)+1,
677                                         (void *)&tmp, sizeof(zval *), NULL);
678                         g_value_unset(&pval);
679                 }
680         }
681        
682         g_free(props);
683
684         /* "Cache" result */
685         php_gobject->properties = TRUE;
686
687         return php_gobject->zo.properties;
688 }
689
690 /* Object destructor */
691 static void __php_midgard_gobject_dtor(void *object TSRMLS_DC)
692 {
693         php_midgard_gobject *php_gobject =
694                 (php_midgard_gobject *) object;
695
696         if(!object)
697                 return;
698
699         zend_object_std_dtor(&php_gobject->zo TSRMLS_CC);
700
701         if(php_gobject->gobject == NULL) {
702                
703                 /* This may be disabled, it's just for debugging purpose */
704                 /* php_error(E_NOTICE, "__php_midgard_gobject_dtor. Underlying GObject is NULL"); */
705        
706         } else if(G_IS_OBJECT(php_gobject->gobject)
707                         && G_OBJECT_TYPE_NAME(G_OBJECT(php_gobject->gobject)) != NULL){
708                
709                 if(G_IS_OBJECT(php_gobject->gobject)) {
710                
711                         g_object_unref(G_OBJECT(php_gobject->gobject));
712                         php_gobject->gobject = NULL;
713                 }
714         }
715
716         php_gobject->gobject = NULL;
717
718         efree(php_gobject);
719
720         php_gobject = NULL;
721 }
722
723 void php_midgard_init_properties_objects(zval *zobject)
724 {
725         if(zobject == NULL)
726                 return;
727
728         GParamSpec **pspecs;
729         guint n_param, i;
730
731         php_midgard_gobject *php_gobject =
732                 php_midgard_zend_object_store_get_object(zobject TSRMLS_CC);
733         GObject *gobject = G_OBJECT(php_gobject->gobject);
734
735         if(!gobject)
736                 return;
737
738         pspecs = g_object_class_list_properties(G_OBJECT_GET_CLASS(gobject), &n_param);
739
740         if(!pspecs)
741                 return;
742
743         for(i = 0; i < n_param; i++) {
744
745                 if(pspecs[i]->value_type != G_TYPE_OBJECT)
746                         continue;
747
748                 zval *prop_zobject;
749                 MAKE_STD_ZVAL(prop_zobject);
750
751                 GValue oval = {0, };
752                 g_value_init(&oval, G_TYPE_OBJECT);
753                 g_object_get_property(gobject, pspecs[i]->name, &oval);
754                 GObject *prop_gobject = g_value_get_object(&oval);     
755        
756                 zend_class_entry *ce =
757                         php_midgard_get_baseclass_ptr_by_name(G_OBJECT_TYPE_NAME(prop_gobject));
758
759                 object_init_ex(prop_zobject, ce);
760                 php_midgard_gobject_new_with_gobject(prop_zobject, ce, prop_gobject, TRUE); /* SHOULD BE SET TO TRUE */
761
762                 zval *zprop;
763                 MAKE_STD_ZVAL(zprop);
764                 php_midgard_gvalue2zval(&oval, zprop);
765                 zend_update_property(Z_OBJCE_P(zobject), zobject,
766                                 pspecs[i]->name, strlen(pspecs[i]->name),
767                                 zprop TSRMLS_CC);
768
769                 g_value_unset(&oval);
770         }
771
772         g_free(pspecs);
773 }
774
775 /* Object constructor */
776 zend_object_value php_midgard_gobject_new(zend_class_entry *class_type TSRMLS_DC)
777 {
778         php_midgard_gobject *php_gobject;
779         zend_object_value retval;
780         zval *tmp;     
781
782         php_gobject = ecalloc(1, sizeof(php_midgard_gobject));
783         zend_object_std_init(&php_gobject->zo, class_type TSRMLS_CC);
784
785         php_gobject->gobject = NULL;
786         php_gobject->properties = FALSE;
787
788         zend_hash_copy(php_gobject->zo.properties,
789                         &class_type->default_properties,
790                         (copy_ctor_func_t) zval_add_ref,
791                         (void *) &tmp, sizeof(zval *));
792
793         retval.handle = zend_objects_store_put(php_gobject,
794