summaryrefslogtreecommitdiff
path: root/documentation/inheritance.html
blob: f4f027ef85ccb42e8cf5064015f1da9d350da416 (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
<h1>Inheritance</h1>
<p>
    Both PHP and C++ are object oriented programming languages that support
    class inheritance. There are some differences: C++ supports multiple 
    inheritance, while a PHP class can only have a single base class.
    To make up for not having multiple inheritance, PHP supports interfaces
    and traits.
</p>
<p>
    The PHP-CPP library also allows you to define PHP interfaces and to create 
    hierarchies of PHP classes and PHP interfaces.
<p>
<h2 id="defining-interfaces">Defining interfaces</h2>
<p>
    In case you want your extension to <i>define</i> an interface, so that the
    interface can be implemented from PHP user space scripts, you can do that
    almost in a similar way to how you would define a class. The only 
    difference is that you do not use Php::Class&lt;YourClass&gt;, but a 
    Php::Interface instance.
</p>
<p>
<pre class="language-c++"><code>
/**
 *  Switch to C context to ensure that the get_module() function
 *  is callable by C programs (which the Zend engine is)
 */
extern "C" {
    /**
     *  Startup function that is called by the Zend engine 
     *  to retrieve all information about the extension
     *  @return void*
     */
    PHPCPP_EXPORT void *get_module() {
        // create static instance of the extension object
        static Php::Extension myExtension("my_extension", "1.0");
        
        // description of the interface so that PHP knows which methods 
        // are defined by it
        Php::Interface interface("MyInterface");
        
        // define an interface method
        interface.method("myMethod", { 
            Php::ByVal("value", Php::Type::String, true) 
        });
        
        // register other methods
        ...

        // add the interface to the extension
        // (or move it into the extension, which is faster)
        myExtension.add(std::move(interface));
        
        // return the extension
        return myExtension;
    }
}
</code></pre>
</p>
<h2 id="deriving-and-implementing">Deriving and implementing</h2>
<p>
    The PHP-CPP library tries to make working with PHP and C++ as transparent
    as possible. C++ functions can be called from PHP userspace scripts,
    and C++ classes can be made accessible from PHP. However, in the end PHP
    and C++ are still different languages, and because C++ does not have the 
    same reflection features as PHP, you will have to explicit tell the PHP
    engine which base classes and interfaces the class implements.
</p>
<p>
    The Php::Class&lt;YourClass&gt; object has a method 'extends()' and a 
    method 'implements()' that can be used for specifying the base classes
    and implemented interfaces. You need to pass in a class or interface that
    you configured before. Let's look at an example.
</p>
<p>
<p>
<pre class="language-c++"><code>
/**
 *  Switch to C context to ensure that the get_module() function
 *  is callable by C programs (which the Zend engine is)
 */
extern "C" {
    /**
     *  Startup function that is called by the Zend engine 
     *  to retrieve all information about the extension
     *  @return void*
     */
    PHPCPP_EXPORT void *get_module() {
        // create static instance of the extension object
        static Php::Extension myExtension("my_extension", "1.0");
        
        // description of the interface so that PHP knows which methods 
        // are defined by it
        Php::Interface myInterface("MyInterface");
        
        // define an interface method
        myInterface.method("myMethod", { 
            Php::ByVal("value", Php::Type::String, true) 
        });
        
        // register our own class
        Php::Class&lt;MyClass&gt; myClass("MyClass");
        
        // from PHP user space scripts, it must look like the myClass implements
        // the MyInterface interface
        myClass.implements(myInterface);
        
        // the interface requires that the myMethod method is implemented
        myClass.method("myMethod", &amp;MyClass::myMethod, {
            Php::ByVal("value", Php::Type::String, true) 
        });
        
        // create a third class
        Php::Class&lt;DerivedClass&gt; derivedClass("DerivedClass");
        
        // in PHP scripts, it should look like DerivedClass has "MyClass" 
        // as its base
        derivedClass.extends(myClass);
        
        // add the interface and the classes to the extension
        myExtension.add(myInterface);
        myExtension.add(myClass);
        myExtension.add(derivedClass);
        
        // return the extension
        return myExtension;
    }
}
</code></pre>
</p>
<p>
    Be aware that the PHP class hierarchy that you define inside the get_module()
    function does not have to match the C++ class hierarchy. Your C++ class 
    "DerivedClass" does not at all have to have "MyClass" as its base, even
    although in PHP scripts it would look like it has. For code maintainability
    is it of course better to make the PHP signature more or less similar to the
    C++ implementation.
<p>