File: arguments.xml

package info (click to toggle)
php-doc 20100521-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze, wheezy
  • size: 59,992 kB
  • ctags: 4,085
  • sloc: xml: 796,833; php: 21,338; cpp: 500; sh: 117; makefile: 58; awk: 28
file content (1028 lines) | stat: -rw-r--r-- 40,784 bytes parent folder | download | duplicates (2)
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
<?xml version="1.0" encoding="utf-8"?>
 <!-- $Revision: 297078 $ -->
 <sect2 xml:id="internals2.ze1.zendapi.arguments" xmlns="http://docbook.org/ns/docbook"> 
  <title>Accepting Arguments</title> 
  <para>
   One of the most important issues for language extensions is
   accepting and dealing with data passed via arguments. Most
   extensions are built to deal with specific input data (or require
   parameters to perform their specific actions), and function
   arguments are the only real way to exchange data between the PHP
   level and the C level. Of course, there's also the possibility of
   exchanging data using predefined global values (which is also
   discussed later), but this should be avoided by all means, as it's
   extremely bad practice. 
  </para> 
  <para>
   PHP doesn't make use of any formal function declarations; this is
   why call syntax is always completely dynamic and never checked for
   errors. Checking for correct call syntax is left to the user code.
   For example, it's possible to call a function using only one
   argument at one time and four arguments the next time - both
   invocations are syntactically absolutely correct.
  </para> 
  <sect3 xml:id="internals2.ze1.zendapi.arguments.count"> 
   <title>Determining the Number of Arguments</title> 
   <para>
    Since PHP doesn't have formal function definitions with support
    for call syntax checking, and since PHP features variable
    arguments, sometimes you need to find out with how many arguments
    your function has been called. You can use the
    <literal>ZEND_NUM_ARGS</literal> macro in this case. In previous
    versions of PHP, this macro retrieved the number of arguments with
    which the function has been called based on the function's hash
    table entry, <envar>ht</envar>, which is passed in the
    <literal>INTERNAL_FUNCTION_PARAMETERS</literal> list. As
    <envar>ht</envar> itself now contains the number of arguments that
    have been passed to the function, <literal>ZEND_NUM_ARGS</literal>
    has been stripped down to a dummy macro (see its definition in
    <filename>zend_API.h</filename>). But it's still good practice to
    use it, to remain compatible with future changes in the call
    interface. <emphasis>Note:</emphasis> The old PHP equivalent of
    this macro is <literal>ARG_COUNT</literal>.
   </para> 
   <para>
    The following code checks for the correct number of arguments:
    <programlisting role="c">
if(ZEND_NUM_ARGS() != 2) WRONG_PARAM_COUNT;
    </programlisting> 
    If the function is not called with two
    arguments, it exits with an error message. The code snippet above
    makes use of the tool macro <literal>WRONG_PARAM_COUNT</literal>,
    which can be used to generate a standard error message like:
<![CDATA[
"Warning: Wrong parameter count for firstmodule() in /home/www/htdocs/firstmod.php on line 5"
]]>
   </para>
   <para>
    This macro prints a default error message and then returns to the caller.
    Its definition can also be found in <filename>zend_API.h</filename> and looks
    like this: 
    <programlisting role="c">
<![CDATA[
ZEND_API void wrong_param_count(void);

#define WRONG_PARAM_COUNT { wrong_param_count(); return; }
]]>
    </programlisting>
    As you can see, it calls an internal function
    named <function>wrong_param_count</function> that's responsible for printing
    the warning. For details on generating customized error
    messages, see the later section "Printing Information."
   </para> 
  </sect3> 

  <sect3 xml:id="internals2.ze1.zendapi.arguments.retrieval">
   <title>Retrieving Arguments</title>
   
   <note>
    <title>
     New parameter parsing API
    </title>
    <para>
     This chapter documents the new Zend parameter parsing API
     introduced by Andrei Zmievski. It was introduced in the
     development stage between PHP 4.0.6 and 4.1.0.
    </para>
   </note>
   
   <para>
    Parsing parameters is a very common operation and it may get a bit
    tedious. It would also be nice to have standardized error checking
    and error messages. Since PHP 4.1.0, there is a way to do just
    that by using the new parameter parsing API. It greatly simplifies
    the process of receiving parameters, but it has a drawback in
    that it can't be used for functions that expect variable number of
    parameters. But since the vast majority of functions do not fall
    into those categories, this parsing API is recommended as the new
    standard way.
   </para>
   
   <para>
    The prototype for parameter parsing function looks like this:
    <programlisting role="c">
<![CDATA[
int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...);
]]>
    </programlisting>
    The first argument to this function is supposed to be the number
    of actual parameters passed to your function, so
    <literal>ZEND_NUM_ARGS()</literal> can be used for that. The
    second parameter should always be <literal>TSRMLS_CC</literal>
    macro. The third argument is a string that specifies the number
    and types of arguments your function is expecting, similar to how
    printf format string specifies the number and format of the output
    values it should operate on. And finally the rest of the arguments
    are pointers to variables which should receive the values from the
    parameters.
   </para>
   
   <para>
    <function>zend_parse_parameters</function> also performs type
    conversions whenever possible, so that you always receive the data
    in the format you asked for. Any type of scalar can be converted
    to another one, but conversions between complex types (arrays,
    objects, and resources) and scalar types are not allowed.
   </para>
   
   <para>
    If the parameters could be obtained successfully and there were no
    errors during type conversion, the function will return
    <literal>SUCCESS</literal>, otherwise it will return
    <literal>FAILURE</literal>.  The function will output informative
    error messages, if the number of received parameters does not
    match the requested number, or if type conversion could not be
    performed.
   </para>
   
   <para>
    Here are some sample error messages:
    <screen>
     Warning - ini_get_all() requires at most 1 parameter, 2 given
     Warning - wddx_deserialize() expects parameter 1 to be string, array given
    </screen>
    Of course each error message is accompanied by the filename and
    line number on which it occurs.
   </para>

   <para>
    Here is the full list of type specifiers:
    <itemizedlist>
     <listitem>
      <para><literal>l</literal> - long</para>
     </listitem>
     <listitem>
      <para><literal>d</literal> - double</para>
     </listitem>
     <listitem>
      <para><literal>s</literal> - string (with possible null bytes) and its length</para>
     </listitem>
     <listitem>
      <para><literal>b</literal> - boolean</para>
     </listitem>
     <listitem>
      <para><literal>r</literal> - resource, stored in <literal>zval*</literal></para>
     </listitem>
     <listitem>
      <para><literal>a</literal> - array, stored in <literal>zval*</literal></para>
     </listitem>
     <listitem>
      <para><literal>o</literal> - object (of any class), stored in <literal>zval*</literal></para>
     </listitem>
     <listitem>
      <para><literal>O</literal> - object (of class specified by class entry), stored in <literal>zval*</literal></para>
     </listitem>
     <listitem>
      <para><literal>z</literal> - the actual <literal>zval*</literal></para>
     </listitem>
    </itemizedlist>
    The following characters also have a meaning in the specifier
    string:
    <itemizedlist>
     <listitem>
      <para>
       <literal>|</literal> - indicates that the remaining
       parameters are optional. The storage variables
       corresponding to these parameters should be initialized to
       default values by the extension, since they will not be
       touched by the parsing function if the parameters are not
       passed.
      </para>
     </listitem>
     <listitem>
      <para>
       <literal>/</literal> - the parsing function will
       call <function>SEPARATE_ZVAL_IF_NOT_REF</function> on
       the parameter it follows, to provide a copy of the
       parameter, unless it's a reference.  
      </para>
     </listitem>
     <listitem>
      <para>
       <literal>!</literal> - the parameter it follows can
       be of specified type or <literal>NULL</literal> (only
       applies to a, o, O, r, and z). If <literal>NULL</literal>
       value is passed by the user, the storage pointer will be
       set to <literal>NULL</literal>.
      </para>
     </listitem>
    </itemizedlist>
   </para>
   
   <para>
    The best way to illustrate the usage of this function is through
    examples:
    <programlisting role="c">
<![CDATA[
/* Gets a long, a string and its length, and a zval. */
long l;
char *s;
int s_len;
zval *param;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                          "lsz", &l, &s, &s_len, &param) == FAILURE) {
    return;
}

/* Gets an object of class specified by my_ce, and an optional double. */
zval *obj;
double d = 0.5;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                          "O|d", &obj, my_ce, &d) == FAILURE) {
    return;
}

/* Gets an object or null, and an array.
   If null is passed for object, obj will be set to NULL. */
zval *obj;
zval *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!a", &obj, &arr) == FAILURE) {
    return;
}

/* Gets a separated array. */
zval *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &arr) == FAILURE) {
    return;
}

/* Get only the first three parameters (useful for varargs functions). */
zval *z;
zend_bool b;
zval *r;
if (zend_parse_parameters(3, "zbr!", &z, &b, &r) == FAILURE) {
    return;
}
]]>
    </programlisting>
   </para>
   
   <para>
    Note that in the last example we pass 3 for the number of received
    parameters, instead of <function>ZEND_NUM_ARGS</function>. What
    this lets us do is receive the least number of parameters if our
    function expects a variable number of them. Of course, if you want
    to operate on the rest of the parameters, you will have to use
    <function>zend_get_parameters_array_ex</function> to obtain
    them.
   </para>
   
   <para>
    The parsing function has an extended version that allows for an
    additional flags argument that controls its actions.
    <programlisting role="c">
<![CDATA[
int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...);
]]>
    </programlisting>
   </para>
   
   <para>
    The only flag you can pass currently is <literal>ZEND_PARSE_PARAMS_QUIET</literal>,
    which instructs the function to not output any error messages
    during its operation. This is useful for functions that expect
    several sets of completely different arguments, but you will have
    to output your own error messages.
   </para>
   
   <para>
    For example, here is how you would get either a set of three longs
    or a string:
    <programlisting role="c">
<![CDATA[
long l1, l2, l3;
char *s;
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                             ZEND_NUM_ARGS() TSRMLS_CC,
                             "lll", &l1, &l2, &l3) == SUCCESS) {
    /* manipulate longs */
} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                                    ZEND_NUM_ARGS(), "s", &s, &s_len) == SUCCESS) {
    /* manipulate string */
} else {
    php_error(E_WARNING, "%s() takes either three long values or a string as argument",
              get_active_function_name(TSRMLS_C));
    return;
}]]>
    </programlisting>
   </para>
   
   <para>
    With all the abovementioned ways of receiving function parameters
    you should have a good handle on this process.  For even more
    example, look through the source code for extensions that are
    shipped with PHP - they illustrate every conceivable situation.
   </para>
  </sect3>
  
  <sect3 xml:id="internals2.ze1.zendapi.arguments.deprecated-retrieval"> 
   <title>Old way of retrieving arguments (deprecated)</title> 
   <note>
    <title>
     Deprecated parameter parsing API
    </title>
    <para>
     This API is deprecated and superseded by the new ZEND
     parameter parsing API.
    </para>
   </note>
   <para>
    After having checked the number of arguments, you need to get access
    to the arguments themselves. This is done with the help of 
    <function>zend_get_parameters_ex</function>: 
    <programlisting role="c">
<![CDATA[
zval **parameter;

if(zend_get_parameters_ex(1, &parameter) != SUCCESS)
  WRONG_PARAM_COUNT;
]]>
    </programlisting>
    All arguments are stored in a <envar>zval</envar> container,
    which needs to be pointed to <emphasis>twice</emphasis>. The snippet above
    tries to retrieve one argument and make it available to us via the
    <envar>parameter</envar> pointer.
   </para> 
   <para>
    <function>zend_get_parameters_ex</function> accepts at least two
    arguments. The first argument is the number of arguments to
    retrieve (which should match the number of arguments with which
    the function has been called; this is why it's important to check
    for correct call syntax). The second argument (and all following
    arguments) are pointers to pointers to pointers to
    <envar>zval</envar>s. (Confusing, isn't it?) All these pointers
    are required because Zend works internally with
    <envar>**zval</envar>; to adjust a local <envar>**zval</envar> in
    our function,<function>zend_get_parameters_ex</function> requires
    a pointer to it.
   </para> 
   <para>
    The return value of <function>zend_get_parameters_ex</function>
    can either be <literal>SUCCESS</literal> or
    <literal>FAILURE</literal>, indicating (unsurprisingly) success or
    failure of the argument processing. A failure is most likely
    related to an incorrect number of arguments being specified, in
    which case you should exit with
    <literal>WRONG_PARAM_COUNT</literal>.
   </para> 
   <para>
    To retrieve more than one argument, you can use a similar snippet: 
    <programlisting role="c">
<![CDATA[
zval **param1, **param2, **param3, **param4;
     
if(zend_get_parameters_ex(4, &param1, &param2, &param3, &param4) != SUCCESS)
    WRONG_PARAM_COUNT;
]]>
    </programlisting>
   </para> 
   <para>
    <function>zend_get_parameters_ex</function> only checks whether
    you're trying to retrieve too many parameters. If the function is
    called with five arguments, but you're only retrieving three of
    them with <function>zend_get_parameters_ex</function>, you won't
    get an error but will get the first three parameters instead.
    Subsequent calls of <function>zend_get_parameters_ex</function>
    won't retrieve the remaining arguments, but will get the same
    arguments again.
   </para>
  </sect3>

  <sect3 xml:id="internals2.ze1.zendapi.arguments.variable"> 
   <title>Dealing with a Variable Number of Arguments/Optional Parameters</title> 
   <para>
    If your function is meant to accept a variable number of
    arguments, the snippets just described are sometimes suboptimal
    solutions. You have to create a line calling
    <function>zend_get_parameters_ex</function> for every possible
    number of arguments, which is often unsatisfying.
   </para> 
   <para>
    For this case, you can use the
    function <function>zend_get_parameters_array_ex</function>, which accepts the
    number of parameters to retrieve and an array in which to store them: 
    <programlisting role="c">
<![CDATA[
zval **parameter_array[4];

/* get the number of arguments */
argument_count = ZEND_NUM_ARGS();

/* see if it satisfies our minimal request (2 arguments) */
/* and our maximal acceptance (4 arguments) */
if(argument_count < 2 || argument_count > 4)
    WRONG_PARAM_COUNT;

/* argument count is correct, now retrieve arguments */
if(zend_get_parameters_array_ex(argument_count, parameter_array) != SUCCESS)
    WRONG_PARAM_COUNT;
]]>
    </programlisting>
    First, the number of arguments is checked to make sure that it's in the accepted range. After that,
    <function>zend_get_parameters_array_ex</function> is used to
    fill <envar>parameter_array</envar> with valid pointers to the argument
    values.
   </para> 
   <para>
    A very clever implementation of this can be found in the code
    handling PHP's <function>fsockopen</function> located in
    <filename>ext/standard/fsock.c</filename>, as shown in 
    <xref linkend="internals2.ze1.zendapi.example.fsockopen"/>. Don't worry if you don't know all the functions used in this
    source yet; we'll get to them shortly.
   </para> 

   <example xml:id="internals2.ze1.zendapi.example.fsockopen"> 
    <title>PHP's implementation of variable arguments in fsockopen().</title> 
    <programlisting role="c">
<![CDATA[
pval **args[5];
int *sock=emalloc(sizeof(int));
int *sockp;
int arg_count=ARG_COUNT(ht);
int socketd = -1;
unsigned char udp = 0;
struct timeval timeout = { 60, 0 };
unsigned short portno;
unsigned long conv;
char *key = NULL;
FLS_FETCH();

if (arg_count > 5 || arg_count < 2 || zend_get_parameters_array_ex(arg_count,args)==FAILURE) {
    CLOSE_SOCK(1);
    WRONG_PARAM_COUNT;
}

switch(arg_count) {
    case 5:
        convert_to_double_ex(args[4]);
        conv = (unsigned long) (Z_DVAL_PP(args[4]) * 1000000.0);
        timeout.tv_sec = conv / 1000000;
        timeout.tv_usec = conv % 1000000;
        /* fall-through */
    case 4:
        if (!PZVAL_IS_REF(*args[3])) {
            php_error(E_WARNING,"error string argument to fsockopen not passed by reference");
        }
        pval_copy_constructor(*args[3]);
        ZVAL_EMPTY_STRING(*args[3]);
        /* fall-through */
    case 3:
        if (!PZVAL_IS_REF(*args[2])) {
            php_error(E_WARNING,"error argument to fsockopen not passed by reference");
            return;
        }
        ZVAL_LONG(*args[2], 0);
        break;
}

convert_to_string_ex(args[0]);
convert_to_long_ex(args[1]);
portno = (unsigned short) Z_LVAL_P(args[1]);

key = emalloc(Z_STRLEN_P(args[0]) + 10);
]]>
    </programlisting> 
   </example> 
   <para>
    <function>fsockopen</function> accepts two, three, four, or five
    parameters. After the obligatory variable declarations, the
    function checks for the correct range of arguments. Then it uses a
    fall-through mechanism in a <literal>switch()</literal> statement
    to deal with all arguments. The  <literal>switch()</literal>
    statement starts with the maximum number of arguments being passed
    (five). After that, it automatically processes the case of four
    arguments being passed, then three, by omitting the otherwise
    obligatory <literal>break</literal> keyword in all stages. After
    having processed the last case, it exits the
    <literal>switch()</literal> statement and does the minimal
    argument processing needed if the function is invoked with only
    two arguments.
   </para> 
   <para>
    This multiple-stage type of processing, similar to a stairway, allows
    convenient processing of a variable number of arguments.
   </para> 
  </sect3>
 
  <sect3 xml:id="zend.arguments.access"> 
   <title>Accessing Arguments</title> 
   <para>
    To access arguments, it's necessary for each argument to have a
    clearly defined type. Again, PHP's extremely dynamic nature
    introduces some quirks. Because PHP never does any kind of type
    checking, it's possible for a caller to pass any kind of data to
    your functions, whether you want it or not. If you expect an
    integer, for example, the caller might pass an array, and vice
    versa - PHP simply won't notice.
   </para> 
   <para>
    To work around this, you have to use a set of API functions to
    force a type conversion on every argument that's being passed (see
    <xref linkend="internals2.ze1.zendapi.tab.arg-conv"/>).
   </para>
   <para>
    <emphasis>Note:</emphasis> All conversion functions expect a
    <envar>**zval</envar> as parameter.
   </para> 
   <table xml:id="internals2.ze1.zendapi.tab.arg-conv">
    <title>Argument Conversion Functions</title> 
     <tgroup cols="2">
      <colspec colnum="1" colname="col1" colwidth="1.02*"/>
      <colspec colnum="2" colname="col2" colwidth="1.00*"/> 
      <tbody> 
       <row> 
        <entry colname="col1">Function</entry> 
        <entry colname="col2">Description</entry> 
       </row> 
       <row> 
        <entry colname="col1"><function>convert_to_boolean_ex</function></entry>
        <entry colname="col2">
         Forces conversion to a Boolean type. Boolean values remain
         untouched. Longs, doubles, and strings containing
         <literal>0</literal> as well as NULL values will result in
         Boolean <literal>0</literal> (FALSE). Arrays and objects are
         converted based on the number of entries or properties,
         respectively, that they have. Empty arrays and objects are
         converted to FALSE; otherwise, to TRUE. All other values
         result in a Boolean <literal>1</literal> (TRUE).
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><function>convert_to_long_ex</function></entry> 
        <entry colname="col2">
         Forces conversion to a long, the default integer type. NULL
         values, Booleans, resources, and of course longs remain
         untouched. Doubles are truncated. Strings containing an
         integer are converted to their corresponding numeric
         representation, otherwise resulting in <literal>0</literal>.
         Arrays and objects are converted to <literal>0</literal> if
         empty,  <literal>1</literal> otherwise.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><function>convert_to_double_ex</function></entry> 
        <entry colname="col2">
         Forces conversion to a double, the default floating-point
         type. NULL values, Booleans, resources, longs, and of course
         doubles remain untouched. Strings containing a number are
         converted to their corresponding numeric representation,
         otherwise resulting in <literal>0.0</literal>. Arrays and
         objects are converted to <literal>0.0</literal> if empty,
         <literal>1.0</literal> otherwise.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><function>convert_to_string_ex</function></entry> 
        <entry colname="col2">
         Forces conversion to a string. Strings remain untouched. NULL
         values are converted to an empty string. Booleans containing
         TRUE are converted to <literal>"1"</literal>, otherwise
         resulting in an empty string. Longs and doubles are converted
         to their corresponding string representation. Arrays are
         converted to the string <literal>"Array"</literal> and
         objects to the string <literal>"Object"</literal>.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>convert_to_array_ex(value)</literal></entry> 
        <entry colname="col2">
         Forces conversion to an array. Arrays remain untouched.
         Objects are converted to an array by assigning all their
         properties to the array table. All property names are used as
         keys, property contents as values. NULL values are converted
         to an empty array. All other values are converted to an array
         that contains the specific source value in the element with
         the key <literal>0</literal>.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>convert_to_object_ex(value)</literal></entry> 
        <entry colname="col2">
         Forces conversion to an object. Objects remain untouched.
         NULL values are converted to an empty object. Arrays are
         converted to objects by introducing their keys as properties
         into the objects and their values as corresponding property
         contents in the object. All other types result in an object
         with the property <literal>scalar</literal> , having the
         corresponding source value as content.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>convert_to_null_ex(value)</literal></entry> 
        <entry colname="col2">Forces the type to become a NULL value, meaning empty.</entry> 
       </row> 
      </tbody> 
     </tgroup> 
   </table> 
   <note> 
    <para>
     You can find a demonstration of the behavior in
     <filename>cross_conversion.php</filename> on the accompanying
     CD-ROM.
    </para> 
   </note> 
   <mediaobject xml:id="internals2.ze1.zendapi.fig.cross-convert">
    <alt>Cross-conversion behavior of PHP.</alt>
    <imageobject>
     <imagedata fileref="en/internals2/ze1/zendapi/figures/zend.04-cross-converter.png"/>
    </imageobject>
   </mediaobject>
   <para>
    Using these functions on your arguments will ensure type safety
    for all data that's passed to you. If the supplied type doesn't
    match the required type, PHP forces dummy contents on the
    resulting value (empty strings, arrays, or objects,
    <literal>0</literal> for numeric values, <literal>FALSE</literal>
    for Booleans) to ensure a defined state.
   </para>
   <para>
    Following is a quote from the sample module discussed
    previously, which makes use of the conversion functions: 
    <programlisting role="c">
<![CDATA[
zval **parameter;

if((ZEND_NUM_ARGS() != 1) || (zend_get_parameters_ex(1, &parameter) != SUCCESS))
{
    WRONG_PARAM_COUNT;
}

convert_to_long_ex(parameter);

RETURN_LONG(Z_LVAL_P(parameter));
]]>
    </programlisting>
    After retrieving the parameter pointer, the parameter value is
    converted to a long (an integer), which also forms the return value of
    this function. Understanding access to the contents of the value requires a
    short discussion of the <envar>zval</envar> type, whose definition is shown in <xref linkend="internals2.ze1.zendapi.example.zval-typedef"/>.
   </para> 
   
   <example xml:id="internals2.ze1.zendapi.example.zval-typedef"> 
    <title>PHP/Zend <envar>zval</envar> type definition.</title> 
    <programlisting role="c">
<![CDATA[
typedef pval zval;
     
typedef struct _zval_struct zval;

typedef union _zvalue_value {
    long lval;                 /* long value */
    double dval;               /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;             /* hash table value */
    struct {
        zend_class_entry *ce;
        HashTable *properties;
    } obj;
} zvalue_value;

struct _zval_struct {
    /* Variable information */
    zvalue_value value;        /* value */
    unsigned char type;        /* active type */
    unsigned char is_ref;
    short refcount;
};
]]>
    </programlisting> 
   </example> 
   <para>
    Actually, <envar>pval</envar> (defined in <filename>php.h</filename>) is
    only an alias of <envar>zval</envar> (defined in <filename>zend.h</filename>),
    which in turn refers to <envar>_zval_struct</envar>. This is a most interesting
    structure. <envar>_zval_struct</envar> is the "master" structure, containing
    the value structure, type, and reference information. The substructure
    <envar>zvalue_value</envar> is a union that contains the variable's contents.
    Depending on the variable's type, you'll have to access different members of
    this union. For a description of both structures, see 
    <xref linkend="internals2.ze1.zendapi.tab.struct-zval"/>,
    <xref linkend="internals2.ze1.zendapi.tab.struct-zvalue-value"/> and
    <xref linkend="internals2.ze1.zendapi.tab.ztype-constants"/>.
   </para> 
   <table xml:id="internals2.ze1.zendapi.tab.struct-zval"> 
    <title>Zend <envar>zval</envar> Structure</title> 
     <tgroup cols="2">
      <colspec colnum="1" colname="col1" colwidth="1.00*"/>
      <colspec colnum="2" colname="col2" colwidth="1.66*"/> 
      <tbody> 
       <row> 
        <entry colname="col1">Entry</entry> 
        <entry colname="col2">Description</entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>value</envar></entry> 
        <entry colname="col2">
         Union containing this variable's contents. See 
         <xref linkend="internals2.ze1.zendapi.tab.struct-zvalue-value"/> for a description.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>type</envar></entry> 
        <entry colname="col2">
         Contains this variable's type. For a list of available
         types, see <xref linkend="internals2.ze1.zendapi.tab.ztype-constants"/>.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>is_ref</envar></entry> 
        <entry colname="col2">
         0 means that this variable is not a reference; 1 means that this variable is a reference to another variable.
        </entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>refcount</envar></entry> 
        <entry colname="col2">
         The number of references that exist for this variable. For
         every new reference to the value stored in this variable,
         this counter is increased by 1. For every lost reference,
         this counter is decreased by 1. When the reference counter
         reaches 0, no references exist to this value anymore, which
         causes automatic freeing of the value.
        </entry> 
       </row> 
      </tbody> 
     </tgroup> 
   </table> 
   <table xml:id="internals2.ze1.zendapi.tab.struct-zvalue-value">
    <title>Zend <envar>zvalue_value</envar> Structure</title> 
     <tgroup cols="2">
      <colspec colnum="1" colname="col1" colwidth="1.00*"/>
      <colspec colnum="2" colname="col2" colwidth="1.66*"/> 
      <tbody> 
       <row> 
        <entry colname="col1">Entry</entry> 
        <entry colname="col2">Description</entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>lval</envar></entry> 
        <entry colname="col2">Use this property if the variable is of the
         type <literal>IS_LONG</literal>,
         <literal>IS_BOOLEAN</literal>, or <literal>IS_RESOURCE</literal>.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>dval</envar></entry> 
        <entry colname="col2">Use this property if the variable is of the
         type <literal>IS_DOUBLE</literal>.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>str</envar></entry> 
        <entry colname="col2">
         This structure can be used to access variables of
         the type <literal>IS_STRING</literal>. The member <envar>len</envar> contains the
         string length; the member <envar>val</envar> points to the string itself. Zend
         uses C strings; thus, the string length contains a trailing
         <literal>0x00</literal>.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>ht</envar></entry> 
        <entry colname="col2">This entry points to the variable's hash table entry if the variable is an array.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><envar>obj</envar></entry> 
        <entry colname="col2">Use this property if the variable is of the
         type <literal>IS_OBJECT</literal>.</entry> 
       </row> 
      </tbody> 
     </tgroup> 
   </table>
 
   <table xml:id="internals2.ze1.zendapi.tab.ztype-constants">
    <title>Zend Variable Type Constants</title> 
     <tgroup cols="2">
      <colspec colnum="1" colname="col1" colwidth="1.00*"/>
      <colspec colnum="2" colname="col2" colwidth="1.65*"/> 
      <tbody> 
       <row> 
        <entry colname="col1">Constant</entry> 
        <entry colname="col2">Description</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_NULL</literal></entry> 
        <entry colname="col2">Denotes a NULL (empty) value.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_LONG</literal></entry> 
        <entry colname="col2">A long (integer) value.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_DOUBLE</literal></entry> 
        <entry colname="col2">A double (floating point) value.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_STRING</literal></entry> 
        <entry colname="col2">A string.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_ARRAY</literal></entry> 
        <entry colname="col2">Denotes an array.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_OBJECT</literal></entry> 
        <entry colname="col2">An object.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_BOOL</literal></entry> 
        <entry colname="col2">A Boolean value.</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_RESOURCE</literal></entry> 
        <entry colname="col2">A resource (for a discussion of resources, see the
         appropriate section below).</entry> 
       </row> 
       <row> 
        <entry colname="col1"><literal>IS_CONSTANT</literal></entry> 
        <entry colname="col2">A constant (defined) value.</entry> 
       </row> 
      </tbody> 
     </tgroup> 
   </table> 
   <para>
    To access a long you access <envar>zval.value.lval</envar>, to
    access a double you use <envar>zval.value.dval</envar>, and so on.
    Because all values are stored in a union, trying to access data
    with incorrect union members results in meaningless output.
   </para> 
   <para>
    Accessing arrays and objects is a bit more complicated and
    is discussed later.
   </para> 
  </sect3> 

  <sect3 xml:id="internals2.ze1.zendapi.arguments.by-reference"> 
   <title>Dealing with Arguments Passed by Reference</title> 
   <para>
    If your function accepts arguments passed by reference that you
    intend to modify, you need to take some precautions.
   </para> 
   <para>
    What we didn't say yet is that under the circumstances presented so
    far, you don't have write access to any <envar>zval</envar> containers
    designating function parameters that have been passed to you. Of course, you
    can change any <envar>zval</envar> containers that you created within
    your function, but you mustn't change any <envar>zval</envar>s that refer to
    Zend-internal data!
   </para> 
   <para>
    We've only discussed the so-called <function>*_ex</function> API
    so far. You may have noticed that the API functions we've used are
    called <function>zend_get_parameters_ex</function> instead of
    <function>zend_get_parameters</function>,
    <function>convert_to_long_ex</function> instead of
    <function>convert_to_long</function>, etc. The
    <function>*_ex</function> functions form the so-called new
    "extended" Zend API. They give a minor speed increase over the old
    API, but as a tradeoff are only meant for providing read-only
    access.
   </para> 
   <para>
    Because Zend works internally with references, different variables
    may reference the same value. Write access to a
    <envar>zval</envar> container requires this container to contain
    an isolated value, meaning a value that's not referenced by any
    other containers. If a <envar>zval</envar> container were
    referenced by other containers and you changed the referenced
    <envar>zval</envar>, you would automatically change the contents
    of the other containers referencing this <envar>zval</envar>
    (because they'd simply point to the changed value and thus change
    their own value as well).
   </para> 
   <para>
    <function>zend_get_parameters_ex</function> doesn't care about
    this situation, but simply returns a pointer to the desired
    <envar>zval</envar> containers, whether they consist of references
    or not. Its corresponding function in the traditional API,
    <function>zend_get_parameters</function>, immediately checks for
    referenced values. If it finds a reference, it creates a new,
    isolated <envar>zval</envar> container; copies the referenced data
    into this newly allocated space; and then returns a pointer to the
    new, isolated value.
   </para> 
   <para>
    This action is called <emphasis>zval separation</emphasis>
    (or pval separation). Because the <function>*_ex</function> API
    doesn't perform zval separation, it's considerably faster, while
    at the same time disabling write access.
   </para> 
   <para>
    To change parameters, however, write access is required. Zend deals
    with this situation in a special way: Whenever a parameter to a function is
    passed by reference, it performs automatic zval separation. This means that
    whenever you're calling a function like 
    this in PHP, Zend will automatically ensure
    that <envar>$parameter</envar> is being passed as an isolated value, rendering it
    to a write-safe state:
    <programlisting role="c">
<![CDATA[
my_function(&$parameter);
]]>
    </programlisting>
   </para> 
   <para>
    But this <emphasis>is not</emphasis> the case with regular parameters!
    All other parameters that are not passed by reference are in a read-only
    state.
   </para> 
 
   <para>
    This requires you to make sure that you're really working with a
    reference - otherwise you might produce unwanted results. To check for a
    parameter being passed by reference, you can use the macro
    <literal>PZVAL_IS_REF</literal>. This macro accepts a <literal>zval*</literal>
    to check if it is a reference or not. Examples are given in
    in <xref linkend="internals2.ze1.zendapi.example.pass-by-ref"/>.
   </para> 
   <example xml:id="internals2.ze1.zendapi.example.pass-by-ref">
    <title>Testing for referenced parameter passing.</title> 
    <programlisting role="c">
<![CDATA[
zval *parameter;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &parameter) == FAILURE)
    return;

/* check for parameter being passed by reference */
if (!PZVAL_IS_REF(parameter)) {
{
    zend_error(E_WARNING, "Parameter wasn't passed by reference");
    RETURN_NULL();
}

/* make changes to the parameter */
ZVAL_LONG(parameter, 10);
]]>
    </programlisting>
    <mediaobject>
     <alt>Testing for referenced parameter passing</alt>
     <imageobject>
      <imagedata fileref="en/internals2/ze1/zendapi/figures/zend.05-reference-test.png"/>
     </imageobject>
    </mediaobject>
   </example> 
  </sect3> 

  <sect3 xml:id="internals2.ze1.zendapi.arguments.write-safety"> 
   <title>Assuring Write Safety for Other Parameters</title> 
   <para>
    You might run into a situation in which you need write access to a
    parameter that's retrieved with <function>zend_get_parameters_ex</function> 
    but not passed by reference. For this case, you can use the macro
    <literal>SEPARATE_ZVAL</literal>, which does a zval separation on the provided
    container. The newly generated <envar>zval</envar> is detached from internal
    data and has only a local scope, meaning that it can be changed or destroyed
    without implying global changes in the script context:
    <programlisting role="c">
<![CDATA[
zval **parameter;
     
/* retrieve parameter */
zend_get_parameters_ex(1, &parameter);

/* at this stage, <parameter> still is connected */
/* to Zend's internal data buffers */

/* make <parameter> write-safe */
SEPARATE_ZVAL(parameter);

/* now we can safely modify <parameter> */
/* without implying global changes */
]]>
    </programlisting>
    <literal>SEPARATE_ZVAL</literal> uses <function>emalloc</function>
    to allocate the new <envar>zval</envar> container, which means that even if you
    don't deallocate this memory yourself, it will be destroyed automatically upon
    script termination. However, doing a lot of calls to this macro
    without freeing the resulting containers will clutter up your RAM.
   </para>
   <para>
    <emphasis>Note:</emphasis> As you can easily work around the lack
    of write access in the "traditional" API (with
    <function>zend_get_parameters</function> and so on), this API
    seems to be obsolete, and is not discussed further in this
    chapter.
   </para>
  </sect3>
 </sect2>
<!-- 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:"~/.phpdoc/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
-->