File: globals.xml

package info (click to toggle)
php-doc 20081024-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 57,752 kB
  • ctags: 3,858
  • sloc: xml: 686,554; php: 19,446; perl: 610; cpp: 500; makefile: 336; sh: 114; awk: 28
file content (239 lines) | stat: -rw-r--r-- 7,667 bytes parent folder | download
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
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- $Revision: 1.5 $ -->
 <sect1 xml:id="internals2.structure.globals" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
  <title>Extension globals</title>

  <sect2 xml:id="internals2.structure.globals.intro">
   <title>Introduction to globals in a PHP extension</title>

   <simpara>
    In a language such as C, a "global" variable is a variable that can be
    accessed from any function without any extra declaration. These traditional
    globals have a few drawbacks:
   </simpara>

   <itemizedlist>

    <listitem>
     <simpara>
      Barring any special options passed to the compiler, a global varaible can
      be accessed and changed by any piece of code anywhere in the program,
      whether or not that code should be doing so.
     </simpara>
    </listitem>

    <listitem>
     <simpara>
      A typical global variable is not thread safe.
     </simpara>
    </listitem>

    <listitem>
     <simpara>
      The names of global variables are as global as the variables themselves.
     </simpara>
    </listitem>

   </itemizedlist>

   <simpara>
    A PHP extension's globals are more properly called the "extension state",
    since most modules must remember what they're doing between function calls.
    The "counter" extension is a perfect example of this need: The basic
    interface calls for a counter with a persistant value. A programmer new to
    Zend and PHP might do something like this in <filename>counter.c</filename>
    to store that value:
   </simpara>

   <example xml:id="internals2.structure.globals.intro.wrong-way">
    <title>The wrong way to store the basic counter interface's value</title>
    <programlisting role="c">
<![CDATA[
/* ... */
static long basic_counter_value;

/* ... */

PHP_FUNCTION(counter_get)
{
    RETURN_LONG(basic_counter_value);
}
]]>
    </programlisting>
   </example>

   <simpara>
    On the surface this appears a viable solution, and indeed in a simple test
    it would function correctly. However, there are a number of situations in
    which more than one copy of PHP is running in the same thread, which means
    more than one instance of the counter module. Suddenly these multiple
    threads are sharing the same counter value, which is clearly undesireable.
    Another problem shows itself when considering that another extension might
    someday happen to have a global with the same name, and due to the rules of
    C scoping, this has the potential to cause a compile failure, or worse, a
    runtime error. Something more elaborate is needed, and so exists Zend's
    support for threadsafe per-module globals.
   </simpara>

  </sect2>

  <sect2 xml:id="internals2.structure.globals.declaring">
   <title>Declaring module globals</title>
   
   <simpara>
    Whether a module uses only a single global or dozens, they must be defined
    in a structure, and that structure must be declared. There are some macros
    that assist with doing so in a way that avoids name conflicts between
    modules: <function>ZEND_BEGIN_MODULE_GLOBALS</function>,
    <function>ZEND_END_MODULE_GLOBALS</function>, and
    <function>ZEND_DECLARE_MODULE_GLOBALS</function>. All three take as a
    parameter the short name of the module, which in the case of the counter
    module is simply <literal>"counter"</literal>. Here is the global structure
    declaration from <filename>php_counter.h</filename>:
   </simpara>

   <example xml:id="internals2.structure.globals.declaring.doth">
    <title>The counter module's globals</title>
    <programlisting role="c">
<![CDATA[
ZEND_BEGIN_MODULE_GLOBALS(counter)
    long        basic_counter_value;
ZEND_END_MODULE_GLOBALS(counter)
]]>
    </programlisting>
   </example>

   <simpara>
    And this is the declaration from <filename>counter.c</filename>:
   </simpara>

   <example xml:id="internals2.structure.globals.declaring.dotc">
    <title>The counter module's global structure declaration</title>
    <programlisting role="c">
<![CDATA[
ZEND_DECLARE_MODULE_GLOBALS(counter)
]]>
    </programlisting>
   </example>
  
  </sect2>
  
  <sect2 xml:id="internals2.structure.globals.using">
   <title>Accessing module globals</title>
   
   <simpara>
    As discussed above, per-module globals are declared inside a C structure
    whose name is obscured by Zend macros. As a result, the ideal way to access
    members of this structure is by the use of further macros. Accordingly, most
    if not all extensions which have globals have a declaration like this
    somewhere in their header file:
   </simpara>

   <example xml:id="internals2.structure.globals.using.accessor">
    <title>Accessor macros for per-module globals</title>
    <programlisting role="c">
<![CDATA[
#ifdef ZTS
#define COUNTER_G(v) TSRMG(counter_globals_id, zend_counter_globals *, v)
#else
#define COUNTER_G(v) (counter_globals.v)
#endif
]]>
    </programlisting>
   </example>

   <note>
    <simpara>
     This could have been generalized into a macro of its own by the Zend API,
     but as of PHP 5.3 (and PHP 6 at the time of this writing), that hasn't
     happened. The global accessor construct is written into the header by
     <command>ext_skel</command> and thus is generally left alone by extension
     writers, unless they wish to change the name of the accessor macro.
    </simpara>
   </note>

   <note>
    <simpara>
     <constant>COUNTER_G</constant> was the name given to the macro by
     <command>ext_skel</command>, but it's not necessary for it to have that
     name and could just as easily be called <literal>FOO</literal> instead.
    </simpara>
   </note>

   <simpara>
    Any code in the counter extension that accesses a global must thus wrap it
    in the macro <constant>COUNTER_G</constant>.
   </simpara>

   <warning>
    <simpara>
     Any function which accesses globals must either be declared by Zend macros,
     have <constant>TSRMLS_DC</constant> as its last argument, or call the macro
     <constant>TSRMLS_FETCH</constant> before accessing the globals. See
     <!--<link linkend="internals2.memory.tsrm">-->the TSRM documentation<!--</link>--> for
     more information.
    </simpara>
   </warning>

   <simpara>
    So with all of that in mind, here is our new version of the
    <function>counter_get</function>:
   </simpara>
  
   <example xml:id="internals2.structure.globals.intro.right-way">
    <title>The right way to store the basic counter interface's value</title>
    <programlisting role="c">
<![CDATA[
/* php_counter.h */
ZEND_BEGIN_MODULE_GLOBALS(counter)
    long        basic_counter_value;
ZEND_END_MODULE_GLOBALS(counter)

#ifdef ZTS
#define COUNTER_G(v) TSRMG(counter_globals_id, zend_counter_globals *, v)
#else
#define COUNTER_G(v) (counter_globals.v)
#endif

/* counter.c */
ZEND_DECLARE_MODULE_GLOBALS(counter)

/* ... */

PHP_FUNCTION(counter_get)
{
    RETURN_LONG(COUNTER_G(basic_counter_value));
}
]]>
    </programlisting>
   </example>

   <simpara>
    This is a correct implementation. It is not, however, a complete one. The
    section <xref linkend="internals2.structure.lifecycle"/> explains why.
   </simpara>
  
  </sect2>

 </sect1>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"../../../manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->