summaryrefslogtreecommitdiff
path: root/src/classinfo.cpp
blob: 7de7522874e0e7f4547df5edb66f5cca2740ed7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/**
 *  ClassInfo.cpp
 *
 *  Implementation for the class info
 *
 *  @documentation private
 */
#include "includes.h"

/**
 *  Set up namespace
 */
namespace Php {

/**
 *  Structure that combines a C++ object with a zend object
 */
struct MixedObject
{
    zend_object php;
    Base *cpp;
};

/**
 *  Function that is called to clean up space that is occupied by the object
 *  @param  object      The object to be deallocated
 */
static void deallocate_object(void *object TSRMLS_DC)
{
    // allocate memory for the object
    MixedObject *obj = (MixedObject *)object;
    
    // deallocate the cpp object
    if (obj->cpp) delete obj->cpp;
    
    // get rid of the object properties
    zend_hash_destroy(obj->php.properties);
    FREE_HASHTABLE(obj->php.properties);

    // deallocate the entire object
    efree(obj);
}

/**
 *  Function that is called to create space for a cloned object
 *  @param  object      The object to be cloned
 *  @param  clone       The address that should become the clone
 */
static void clone_object(void *object, void **clone TSRMLS_DC)
{
    std::cout << "clone_object" << std::endl;
    
    // @todo implementation
}

/**
 *  Function that is called when an instance of the class needs to be created.
 *  This function will create the C++ class, and the PHP object
 *  @param  type        Pointer to the class
 */
static zend_object_value create_object(zend_class_entry *type TSRMLS_DC)
{
    // allocate memory for the object
    MixedObject *object = (MixedObject *)emalloc(sizeof(MixedObject));
    
    // retrieve the classinfo object
    _ClassInfo *info = (_ClassInfo *)type->info.user.doc_comment;
    
    // construct the cpp object
    object->cpp = info->construct();
    
    // store the class
    object->php.ce = type;

    // the original create_object fills the initial object with the default properties,
    // we're going to do exactly the same. start with setting up a hashtable for the props
    ALLOC_HASHTABLE(object->php.properties);

    // initialize the hash table
    zend_hash_init(object->php.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
    
    // initialize the properties
    object_properties_init(&(object->php), type);

    // the thing we're going to return
    zend_object_value result;

    // use default object handlers
    result.handlers = zend_get_std_object_handlers();
    
    // put the object in the storage, and assign a method for deallocating and cloning
    result.handle = zend_objects_store_put(object, NULL, deallocate_object, clone_object TSRMLS_CC); 

    // done
    return result;
}

/**
 *  Function that is called by the Zend engine every time the constructor gets called
 *  @param  ht      
 *  @param  return_value
 *  @param  return_value_ptr
 *  @param  this_ptr
 *  @param  return_value_used
 *  @param  tsrm_ls
 */
static void invoke_constructor(INTERNAL_FUNCTION_PARAMETERS)
{
    // get the mixed object
    MixedObject *obj = (MixedObject *)zend_object_store_get_object(this_ptr TSRMLS_CC);

    // construct parameters
    Parameters params(ZEND_NUM_ARGS());

    // call the constructor
    obj->cpp->__construct(*PHPCPP_G(environment), params);
}

/**
 *  Function that is called by the Zend engine every time the destructor gets called
 *  @param  ht      
 *  @param  return_value
 *  @param  return_value_ptr
 *  @param  this_ptr
 *  @param  return_value_used
 *  @param  tsrm_ls
 */
static void invoke_destructor(INTERNAL_FUNCTION_PARAMETERS)
{
    // get the mixed object
    MixedObject *obj = (MixedObject *)zend_object_store_get_object(this_ptr TSRMLS_CC);

    // call the destructor
    obj->cpp->__destruct(*PHPCPP_G(environment));
}

/**
 *  Constructor
 *  @param  name
 */
_ClassInfo::_ClassInfo(const char *name) : _name(name), _entry(NULL) 
{
    // allocate internal functions
    _constructor = new InternalFunction(invoke_constructor, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR);
    _destructor = new InternalFunction(invoke_destructor, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR);
}

/**
 *  Destructor
 */
_ClassInfo::~_ClassInfo() 
{
    // deallocate internal function
    delete _constructor;
    delete _destructor;
}

/**
 *  Initialize the class
 *  @param  mixed       Optional threading ID 
 */
void _ClassInfo::initialize(TSRMLS_D)
{
    // the class entry
    zend_class_entry entry;

    // initialize the class entry
    INIT_CLASS_ENTRY_EX(entry, _name.c_str(), _name.size(), NULL);

    // we need a special constructor
    entry.create_object = create_object;
    entry.constructor = _constructor->function();
    entry.destructor = _destructor->function();
    
    // register the class
    _entry = zend_register_internal_class(&entry TSRMLS_CC);

    // store pointer to the class in the unused doc_comment member
    _entry->info.user.doc_comment = (const char *)this;
}

/**
 *  End of namespace
 */
}