summaryrefslogtreecommitdiff
path: root/documentation/loading-extensions.html
blob: 180cb3362194a41c2c5942dbb376885acb11fbb4 (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
<h1>How does PHP load its extensions?</h1>
<p>
    You probably know that native PHP extensions are compiled into *.so 
    files on unix-like systems, and *.dll files in Windows environments, and that
    the global php.ini file holds a list of all extensions available on your system.
    This means that if you're building your own extension, you are also going to
    create such a *.so or *.dll file and you have to update the PHP 
    configuration file so that your own extension is loaded by PHP.
</p>
<h2 id="get-module-startup-function">The get_module() startup function</h2>
<p>
    Before we explain how you can create your own extension, we first explain
    what PHP does to load an extension. When PHP starts, it loads the *.ini 
    configuration file(s) from its configuration directory and for each 
    "extension=name.so" line in these config files, it opens the appropriate 
    library, and calls the "get_module()" function from it. Each extension library 
    (your extension too) must therefore define and implement this "get_module()" 
    function. The function is called by PHP right after the library is loaded 
    (and thus way before pageviews are handled), and it should return a memory 
    address that points to a structure that holds information about all functions, 
    classes, variables and constants that are made available by the extension. 
</p>
<p>
    The structure that the get_module() returns is defined in the header files of 
    the Zend engine, but it is a pretty complicated structure without good documentation. 
    Luckily, the PHP-CPP library makes life easier for you, and offers an Extension 
    class that can be used instead.
</p>
<p>
<pre class="language-c++"><code>#include &lt;phpcpp.h&gt;

/**
 *  tell the compiler that the get_module is a pure C function
 */
extern "C" {
    
    /**
     *  Function that is called by PHP right after the PHP process
     *  has started, and that returns an address of an internal PHP
     *  structure with all the details and features of your extension
     *
     *  @return void*   a pointer to an address that is understood by PHP
     */
    PHPCPP_EXPORT void *get_module() 
    {
        // static(!) Php::Extension object that should stay in memory
        // for the entire duration of the process (that's why it's static)
        static Php::Extension myExtension("my_extension", "1.0");
        
        // @todo    add your own functions, classes, namespaces to the extension
        
        // return the extension
        return myExtension;
    }
}</code></pre>
</p>
<p>
    In the example above you see a very straightforward implementation of the
    get_module() function. Every PHP extension that uses the PHP-CPP library
    implements this function in a more or less similar way, and it is the 
    starting point of each extension. A number of elements require special attention. 
    For a start, the only header file that you see is the phpcpp.h header
    file. If you're using the PHP-CPP library to build your own extensions,
    you do not have to include the complicated, unstructured, and mostly undocumented
    header files of the Zend engine - all you need is this single phpcpp.h header 
    file of the PHP-CPP library. If you insist, you are of course free to also 
    include the header files of the core PHP engine - but you do not have to. 
    PHP-CPP takes care of dealing with the internals of the PHP engine, and offers 
    you a simple to use API.
</p>
<p>
    The next thing that you'll notice is that we placed the get_module() function
    inside an 'extern "C"' code block. As the name of the library already gives away, 
    PHP-CPP is a C++ library. However, PHP expects your library, and especially your 
    get_module() function, to be implemented in C and not in C++. That's why we've 
    wrapped the get_module() function in an 'extern "C"' block. This will instruct 
    the C++ compiler that the get_module() is a regular C function, and that it
    should not apply any C++ name mangling to it.
</p>
<p>
    The PHP-CPP library defines a "PHPCPP_EXPORT" macro that should be placed
    in front of the get_module() function. This macro makes sure that the get_module()
    function is publicly exported, and thus callable by PHP. The macro has a different
    implementation based on the compiler and operating system.
</p>
<p>
    This, by the way, is also the only macro that PHP-CPP offers. PHP-CPP intends to 
    be a plain C++ library, without using magic or tricks from 
    pre-processors. What you see is what you get: If something looks like a 
    function, you can be sure that it actually IS a function, and when something 
    looks like a variable, you can be sure that it also IS a variable.
</p>
<p>
    Let's move on. Inside the get_module() function the Php::Extension object is 
    instantiated, and it is returned. It is crucial that you make a <i>static</i>
    instance of this Php::Extension class, because the object must exist for the 
    entire lifetime of the PHP process, and not only for the duration of the get_module()
    call. The constructor takes two arguments: the name of your extension and 
    its version number.
</p>
<p>
    The final step in the get_module() function is that the extension object
    is returned. This may seem strange at first, because the get_module() function
    is supposed to return a pointer-to-void, and not a full Php::Extension object.
    Why does the compiler not complain about this? Well, the Php::Extension class 
    has a cast-to-void-pointer-operator. So although it seems that you're returning 
    the full extension object, in reality you only return a memory address that
    points to a data structure that is understood by the core PHP engine and that
    holds all the details of your extension.
</p>
<p>
    Note that the example above does not yet export any native functions or 
    native classes to PHP - it only creates the extension. That is going to be 
    <a href="your-first-extension">the next step</a>.
</p>