summaryrefslogtreecommitdiff
path: root/include/class.h
blob: d1afab2891935819638b427ab927de6197ae0cdf (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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/**
 *  Class.h
 *
 *  When a class is registered in the extension, you need this helper class
 *  for that.
 *
 *  The use of it is simple:
 *
 *  Extension::add(Class<YourClass>);
 *
 *  Note that YourClass must extend from Php::Object
 *
 *  @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
 *  changed by Valeriy Dmitriev <ufabiz@gmail.com>
 *  @copyright 2013, 2014 Copernica BV
 */

/**
 *  Zend/SPL interfaces that we support
 */
//extern struct _zend_class_entry *zend_ce_traversable;
//extern struct _zend_class_entry *zend_ce_aggregate;
//extern struct _zend_class_entry *zend_ce_iterator;
extern struct _zend_class_entry *zend_ce_arrayaccess;
//extern struct _zend_class_entry *zend_ce_serializable;

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

/**
 *  Class definition of the class
 */
template <typename T>
class Class : private ClassBase
{
public:
    /**
     *  Constructor
     * 
     *  The flags can be a combination of Php::Final and Php::Abstract. If no
     *  flags are set, a regular public class will be formed.
     * 
     *  @param  name        Name of the class
     */
    Class(const char *name) : ClassBase(name)
    {
        // check for special classes, and register the interface if it does
        // register the interface (we register a pointer-to-a-pointer here,
        // because when this code runs (during the get_module() call), the 
        // interfaces are not yet initialized by the zend engine, this only
        // happens later when the all classes are registered (after the
        // get_module() call)
//        if (std::is_base_of<ArrayAccess, T>::value) interface(&zend_ce_arrayaccess);
    }
    
    /**
     *  Copy constructor
     *  @param  that
     */
    Class(const Class<T> &that) : ClassBase(that) {}
    
    /**
     *  Move constructor
     *  @param  that
     */
    Class(Class<T> &&that) : ClassBase(std::move(that)) {}

    /**
     *  Destructor
     */
    virtual ~Class() {}
    
    /**
     *  Add a regular method to the class
     *  
     *  The method will be accessible as one of the class methods in your PHP
     *  code. When the method is called, it will automatically be forwarded
     *  to the C++ implementation. The flags can be Php::Public, Php::Protected
     *  or Php::Private (using private methods can be useful if you for example
     *  want to make the __construct() function private). The access-modified
     *  flag can be bitwise combined with the flag Php::Final or Php::Abstract).
     *  
     *  @param  name        Name of the method
     *  @param  method      The actual method
     *  @param  flags       Optional flags
     *  @param  args        Argument descriptions
     */
    void method(const char *name, void  (T::*method)(),                         int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_0>(method), flags,  args); }
    void method(const char *name, void  (T::*method)(Parameters &params),       int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_1>(method), flags,  args); }
    void method(const char *name, Value (T::*method)(),                         int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_2>(method), flags,  args); }
    void method(const char *name, Value (T::*method)(Parameters &params),       int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_3>(method), flags,  args); }
    void method(const char *name, void  (T::*method)(),                                    const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_0>(method), Public, args); }
    void method(const char *name, void  (T::*method)(Parameters &params),                  const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_1>(method), Public, args); }
    void method(const char *name, Value (T::*method)(),                                    const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_2>(method), Public, args); }
    void method(const char *name, Value (T::*method)(Parameters &params),                  const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_3>(method), Public, args); }
    void method(const char *name, void  (T::*method)()                   const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_4>(method), flags,  args); }
    void method(const char *name, void  (T::*method)(Parameters &params) const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_5>(method), flags,  args); }
    void method(const char *name, Value (T::*method)()                   const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_6>(method), flags,  args); }
    void method(const char *name, Value (T::*method)(Parameters &params) const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_7>(method), flags,  args); }
    void method(const char *name, void  (T::*method)()                   const,            const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_4>(method), Public, args); }
    void method(const char *name, void  (T::*method)(Parameters &params) const,            const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_5>(method), Public, args); }
    void method(const char *name, Value (T::*method)()                   const,            const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_6>(method), Public, args); }
    void method(const char *name, Value (T::*method)(Parameters &params) const,            const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_7>(method), Public, args); }

    /**
     *  Add a static method to a class
     * 
     *  In C++ a static method is just a plain function, that only at compile
     *  time has access to the private variables. You can therefore also supply
     *  global functions as static method, and real static methods (that do not
     *  even have to come from the same class.
     * 
     *  In PHP scripts, the function will only be callable as real static method
     * 
     *  @param  name        Name of the method
     *  @param  method      The actual method
     *  @param  flags       Optional flags
     *  @param  args        Argument descriptions
     */
    void method(const char *name, const native_callback_0 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags,  args); }
    void method(const char *name, const native_callback_1 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags,  args); }
    void method(const char *name, const native_callback_2 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags,  args); }
    void method(const char *name, const native_callback_3 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags,  args); }
    void method(const char *name, const native_callback_0 &function,            const Arguments &args = {}) { ClassBase::method(name, function, Public, args); }
    void method(const char *name, const native_callback_1 &function,            const Arguments &args = {}) { ClassBase::method(name, function, Public, args); }
    void method(const char *name, const native_callback_2 &function,            const Arguments &args = {}) { ClassBase::method(name, function, Public, args); }
    void method(const char *name, const native_callback_3 &function,            const Arguments &args = {}) { ClassBase::method(name, function, Public, args); }

    /**
     *  Add an abstract method to the class
     * 
     *  This is only meaningful for classes that can be extended. Because the 
     *  method is abstract, you will not have to pass an implementation. You
     *  can pass in flags to mark the method as protected
     * 
     *  @param  name        Name of the method
     *  @param  flags       Optional flags
     *  @param  args        Argument descriptions
     */
    void method(const char *name, int flags, const Arguments &args = {}) { ClassBase::method(name, flags  | Abstract, args); }
    void method(const char *name,            const Arguments &args = {}) { ClassBase::method(name, Public | Abstract, args); }

    /**
     *  Add a property to the class
     * 
     *  Every instance of this class will have this property. The property
     *  can be Php::Public, Php::Protected or Php::Private (altough setting
     *  private properties is odd as the implementation of the class is in CPP,
     *  so why use private properties while the whole implementation is already
     *  hidden)
     * 
     *  @param  name        Name of the property
     *  @param  value       Actual property value
     *  @param  flags       Optional flags
     */
    void property(const char *name, std::nullptr_t value,     int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, uint64_t value,           int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, uint32_t value,           int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, uint16_t value,           int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, char value,               int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, const char *value,        int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, const std::string &value, int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, bool value,               int flags = Public) { ClassBase::property(name, value, flags); }
    void property(const char *name, double value,             int flags = Public) { ClassBase::property(name, value, flags); }
     
protected:
    /**
     *  Protected constructor
     *  @param  name
     *  @param  flags
     */
    Class(const char *name, int flags) : ClassBase(name, flags) {}

private:
    /**
     *  Construct a new instance of the object
     *  @return Base
     */
    virtual Base* construct() const override
    {
        // construct an instance
        return new T();
    }
    
    /**
     *  Construct a clone
     *  @param  orig
     *  @return Base
     */
    virtual Base *clone(Base *orig) const override
    {
        // cast to the original object
        T *t = (T *)orig;
        
        // construct a new base by calling the copy constructor
        return new T(*t);
    }
    
    /**
     *  Is this class traversable?
     *  @return bool
     */
    virtual bool traversable() const override
    {
        // check if the templated class overrides from the base
        return std::is_base_of<Traversable,T>::value;
    }
    
    /**
     *  Compare two objects
     *  @param  object1
     *  @param  object2
     *  @return int
     */
    virtual int compare(Base *object1, Base *object2) const override
    {
        // cast to the actual implementation type
        T *t1 = (T *)object1;
        T *t2 = (T *)object2;
        
        // compare the two objects
        if (*t1 < *t2) return -1;
        if (*t2 < *t1) return  1;
        
        // they must be identical
        return 0;
    }
    
    /**
     *  Namespaces have access to the private base class
     */
    friend class Namespace;
};

/**
 *  End of namespace
 */
}