summaryrefslogtreecommitdiff
path: root/documentation/classes-and-objects.html
blob: 0fed8266030bc4b2ff26c56c0a60350f99e0f6d0 (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
<h1>Classes and objects</h1>
<p>
    Serious business now. C++ and PHP are both object oriented programming 
    languages, in which you can create classes and objects. The PHP-CPP library
    gives you the tools to combine these two and make a native C++ class 
    accessible from PHP.
</p>
<p>
    Sadly (but also logically if you think about it) not every thinkable C++ class can be directly 
    exported to PHP. It takes a little more work (although not so much). For a
    start, you must make sure that your class is derived from Php::Base, and 
    secondly, when you add your class to the extension object, you must also  
    specify all methods that you want to make accessible from PHP.
</p>
<p>
<pre class="language-c++"><code>
#include &lt;phpcpp.h&gt;

// actual class implementation
class Counter : public Php::Base
{
private:
    int _value = 0;

public:
    Counter() {}
    virtual ~Counter() {}
    
    Php::Value increment() { return ++_value; }
    Php::Value decrement() { return --_value; }
    Php::Value value() const { return _value; }
};

extern "C" {
    PHPCPP_EXPORT void *get_module() {
        static Php::Extension myExtension("my_extension", "1.0");
        
        // description of the class so that PHP knows which methods are accessible
        Php::Class&lt;Counter&gt; counter("Counter");
        counter.method("increment", &Counter::increment);
        counter.method("decrement", &Counter::decrement);
        counter.method("value", &Counter::value);
        
        // add the class to the extension
        myExtension.add(std::move(counter));
        
        // return the extension
        return myExtension;
    }
}
</code></pre>
</p>
<p>
    Let's talk about programming conventions first - I always use capitals for 
    the first letter of a classname, and my member variables always start with
    an underscore. Every class always has a destructor, and it always is virtual.
    That's just a convention - my convention - and you do not 
    have to follow that.
</p>
<p>
    On topic. The example shows a very simple Counter class with three methods:
    increment(), decrement() and value(). The two update methods return the value 
    of the counter after the operation, the value() method returns the current value.
</p>
<p>
    If you want to make a class method that is accessible from PHP, you must
    ensure that is has one of the four supported signatures (which are the same
    signatures that <a href="functions">exportable plain functions</a> can have):
</p>
<p>
<pre class="language-c++"><code>
void YourClass::example1();
void YourClass::example2(Php::Parameters &amp;params);
Php::Value YourClass::example3();
Php::Value YourClass::example4(Php::Parameters &amp;params);
</code></pre>
</p>
<p>
    In the example we have used the third method form, a method that does
    not take any parameters, and that returns a Php::Value object. Methods
    work exactly the same as <a href="functions">regular functions</a>, with the 
    difference that in the methods you have (of course) access to the member
    variables of the object.
</p>
<p>
    To make the class accessible from PHP, you must add it to the extension
    object inside the get_module() function. The Php::Class template class can be 
    be used for that. The template parameter should be your 
    implementation class, so that the Php::Class object internally knows which 
    class to instantiate the moment the "new" operator is used inside a PHP script.
</p>
<p>
    The Php::Class constructor receives a string parameter, with the name of 
    the class in PHP. After you've created an instance of the Php::Class object,
    you should specify all methods that you want to make accessible from PHP,
    and finally, when all methods have been registered, you should add the 
    class to your extension object so that it will be accessible from PHP.
    Note that in our example we have used the C++11 std::move() function for this, so
    that the class object is actually <i>moved</i> into the extension object,
    which is a more efficient operation than copying.
</p>
<h2>Method parameters</h2>
<p>
    Methods are just like functions, and just how you use the
    Php::ByVal and the Php::ByRef classes to <a href="parameters">specify the 
    parameters of a function</a>, you can specify method parameters too.
</p>
<p>
<pre class="language-c++"><code>
#include &lt;phpcpp.h&gt;

// actual class implementation
class Counter : public Php::Base
{
private:
    int _value = 0;

public:
    Counter() {}
    virtual ~Counter() {}
    
    Php::Value increment(Php::Parameters &params) 
    { 
        return _value += params.size() > 0 ? (int)params[0] : 1; 
    }
    
    Php::Value decrement(Php::Parameters &params) 
    { 
        return _value -= params.size() > 0 ? (int)params[0] : 1; 
    }
    
    Php::Value value() const 
    { 
        return _value; 
    }
};

extern "C" {
    PHPCPP_EXPORT void *get_module() {
        static Php::Extension myExtension("my_extension", "1.0");
        
        // description of the class so that PHP knows which methods are accessible
        Php::Class&lt;Counter&gt; counter("Counter");
        
        // register the increment method, and specify its parameters
        counter.method("increment", &Counter::increment, { 
            Php::ByVal("change", Php::Type::Numeric, false) 
        });
        
        // register the decrement, and specify its parameters
        counter.method("decrement", &Counter::decrement, { 
            Php::ByVal("change", Php::Type::Numeric, false) 
        });
        
        // register the value method
        counter.method("value", &Counter::value);
        
        // add the class to the extension
        myExtension.add(std::move(counter));
        
        // return the extension
        return myExtension;
    }
}
</code></pre>
</p>
<p>
    In the code above we have modified our first example. The increment and
    decrement method now get an optional 'change' parameter, which is a numeric
    value that holds the change that should be applied to the counter. Note that
    this parameter is optional - so inside the method implementation we 
    check if the number of parameters is bigger than zero to prevent nasty 
    segmentation faults.
</p>
<p>
<pre class="language-php"><code>
&lt;?php
$counter = new Counter();
$counter->increment(5);
$counter->increment();
$counter->decrement(3);
echo($counter->value()."\n");
?&gt;
</code></pre>
</p>
<p>
    The code above shows a PHP script that uses the native Counter class.
    The output of above script is (of course) 3.
</p>