PHP Extension W riting Marcus Brger Johannes Schlter PHP Quebec - - PowerPoint PPT Presentation

php extension w riting
SMART_READER_LITE
LIVE PREVIEW

PHP Extension W riting Marcus Brger Johannes Schlter PHP Quebec - - PowerPoint PPT Presentation

PHP Extension W riting Marcus Brger Johannes Schlter PHP Quebec 2009 Creating PHP 5 Extension PHP Lifecycle Adding objects Adding iterators to objects Brger, Schlter PHP Extension Writing 2 How the slides work


slide-1
SLIDE 1

PHP Extension W riting

Marcus Börger Johannes Schlüter

PHP Quebec 2009

slide-2
SLIDE 2

PHP Extension Writing 2 Börger, Schlüter

  • Creating PHP 5 Extension
  • PHP Lifecycle
  • Adding objects
  • Adding iterators to objects
slide-3
SLIDE 3

PHP Extension Writing 3 Börger, Schlüter

Te xt i n ye l l ow Te xt you s houl d us e a s pr e s e nt e d Te x t i n gr e e n Te xt t ha t you ha ve t o r e pl a c e y our e x t Ext e ns i on na m e i n l owe r c a s e YOUREXT Ext e ns i on na m e i n uppe r c a s e Your Ex t Ext e ns i on na m e i n m i xe d c a s e ( c a m e l Ca ps )

How the slides work

  • Upper part contains some helpful hints
  • Lower part shows c code on blue background

Some special explanation use red text boxes

slide-4
SLIDE 4

PHP Extension Writing 4 Börger, Schlüter

Part I Creating PHP 5 Extensions

  • How PHP handles data
  • How to create your own extension skeleton
  • How to create your own functions
  • How to work with arrays and hash tables
slide-5
SLIDE 5

PHP Extension Writing 5 Börger, Schlüter

typedef struct _zval_struct { zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval;

In PHP all values are zval's

typedef union _zvalue_value { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; zend_object_value obj; } zvalue_value; IS_NULL IS_LONG IS_DOUBLE IS_BOOL IS_ARRAY IS_OBJECT IS_STRING IS_RESOURCE

slide-6
SLIDE 6

PHP Extension Writing 6 Börger, Schlüter

typedef struct _zval_struct { zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval;

In PHP all values are zval's

Userspace notion of "Reference" 0 == Not a reference 1 == Is a reference How many "labels" are associated with this zval?

slide-7
SLIDE 7

PHP Extension Writing 7 Börger, Schlüter

typedef struct _zval_struct { zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval;

Copy On Write

  • Has a value of 0 (zero)
  • zval shared by 1 or more labels
  • If one label wants to make a

change, it must leave other labels with the original value. $a = 123; $b = $a; $b = 456; value.lval = 123 refcount = 2 type = IS_LONG is_ref = 0 $a $b

slide-8
SLIDE 8

PHP Extension Writing 8 Börger, Schlüter

typedef struct _zval_struct { zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval;

Copy On Write

  • Has a value of 0 (zero)
  • zval shared by 1 or more labels
  • If one label wants to make a

change, it must leave other labels with the original value. $a = 123; $b = $a; $b = 456; value.lval = 123 refcount = 1 type = IS_LONG is_ref = 0 $a value.lval = 456 refcount = 1 type = IS_LONG is_ref = 0 $b

slide-9
SLIDE 9

PHP Extension Writing 9 Börger, Schlüter

typedef struct _zval_struct { zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval;

Full Reference

  • Has a value of 1 (one)
  • zval shared by 1 or more labels
  • If one label wants to make a

change, it does so, causing other labels to see the new value. $a = 123; $b = &$a; $b = 456; value.lval = 123 refcount = 2 type = IS_LONG is_ref = 1 $a $b

slide-10
SLIDE 10

PHP Extension Writing 10 Börger, Schlüter

typedef struct _zval_struct { zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval;

Full Reference

  • Has a value of 1 (one)
  • zval shared by 1 or more labels
  • If one label wants to make a

change, it does so, causing other labels to see the new value. $a = 123; $b = &$a; $b = 456; value.lval = 456 refcount = 2 type = IS_LONG is_ref = 1 $a $b

slide-11
SLIDE 11

PHP Extension Writing 11 Börger, Schlüter

Creating PHP 5 Extensions

  • Most PHP 4 exts will build in PHP5 w/ o Changes
  • ext_skel can be used to generate a basic skeleton

m a r c us @ z a phod s r c / php5/ ext $ . / e xt _s ke l - - ext na m e =ut i l Cr e a t i ng di r e ct or y ut i l Cr e a t i ng ba s i c f i l e s : c onf i g. m 4 . c vs i gnor e ut i l . c php_ut i l . h CREDI TS EXPERI M ENTAL t e s t s / 001. phpt ut i l . php [ done ] . To us e your new e xt e ns i on, you wi l l ha ve t o e xe c ut e t he f ol l owi ng s t e ps :

  • 1. $ c d . .
  • 2. $ vi e xt / ut i l / c onf i g. m

4

  • 3. $ . / bui l dconf - - f or ce
  • 4. $ . / c onf i gur e - - [ wi t h| e nabl e ] - ut i l
  • 5. $ m

a ke

  • 6. $ . / s a pi / cl i / php - f e xt / ut i l / ut i l . php
  • 7. $ vi e xt / ut i l / ut i l . c
  • 8. $ m

a ke Re pe a t s t e ps 3- 6 unt i l you a r e s a t i s f i e d wi t h e xt / ut i l / c onf i g. m 4 a nd s t e p 6 c onf i r m s t ha t your m

  • dul e i s c om

pi l ed i nt o PHP. Then, s t a r t wr i t i ng c ode and r e pe a t t he l a s t t wo s t e ps a s of t e n as ne ce s s a r y.

Necessary for non cvs source (e.g. release packages)

slide-12
SLIDE 12

PHP Extension Writing 12 Börger, Schlüter

Files in your extension

  • You need at least two code files
  • php_yourext.h

The header needed by php

  • php_yourext.c

The main extension code ('php_' prefix for .c is not necessary)

  • You need two configuration files
  • config.m4

Used under * nix

  • config.w32

Used under windows

  • Optional files
  • .cvsignore

List of files to be ignored by CVS

  • CREDITS

First line ext name 2nd line all authors

  • EXPERIMENTAL

If available the API is not yet stable

  • package2.xml

Required for PECL extensions

  • README

Probably good to provide some lines

slide-13
SLIDE 13

PHP Extension Writing 13 Börger, Schlüter

dnl $I d: $ dnl c onf i g. m 4 f or e xt e ns i on YOUREXT PHP_ARG_ENABLE( y our e x t , e na bl e Your Ex t s upppor t , [ - - e na bl e - y our e x t Ena bl e Your Ex t ] , no) i f t e s t " $PHP_YOUREXT" ! = " no" ; t he n AC_DEFI NE( HAVE_YOUREXT, 1, [ W he t he r Your Ex t i s pr e s e nt ] ) PHP_NEW _EXTENSI ON( y our e x t , php_y our e x t . c , $e xt _s ha r e d) f i

config.m4

  • PHP Dev is picky about coding style
  • Read CODING_STANDARDS in php-src
  • Watch your whitespace
  • Align your PHP_ARG_ENABLE output
  • Make your extension default disabled
  • 'phpize' or 'pear install' will enable it automatically
slide-14
SLIDE 14

PHP Extension Writing 14 Börger, Schlüter

config.m4

  • You can prevent the ext from becoming shared

dnl $I d: $ dnl c onf i g. m 4 f or e xt e ns i on YOUREXT PHP_ARG_ENABLE( y our e x t , e na bl e Your Ex t s upppor t , [ - - e na bl e - y our e x t Ena bl e Your Ex t ] , no) i f t e s t " $PHP_YOUREXT" ! = " no" ; t he n i f t e s t " $e xt _s ha r e d" = " ye s " ; t he n AC_M SG_ERROR( Ca nnot bui l d YOUREXT a s a s ha r e d m

  • dul e )

f i AC_DEFI NE( HAVE_YOUREXT, 1, [ W he t he r Your Ex t i s pr e s e nt ] ) PHP_NEW _EXTENSI ON( y our e x t , php_y our e x t . c , $e xt _s ha r e d) f i

slide-15
SLIDE 15

PHP Extension Writing 15 Börger, Schlüter

config.w32

  • Windows configuration uses JScript

/ / $I d: $ / / vi m : f t =j a va s c r i pt ARG_ENABLE( " y our e x t " , " Your Ex t s uppor t " , " ye s " ) ; i f ( PHP_YOUREXT == " ye s " ) { i f ( PHP_YOUREXT_SHARED) { ERROR( " YOUREXT c a nnot be c om pi l e d a s a s ha r e d e xt " ) ; } AC_DEFI NE( " HAVE_YOUREXT" , 1, " Your Ex t s uppor t " ) ; EXTENSI ON( " y our e x t " , " php_y our e x t . c " ) ; }

slide-16
SLIDE 16

PHP Extension Writing 16 Börger, Schlüter

Extension .h file

  • Declares data for static linking and

symbol exports

/ * Li c e ns e , Aut hor , CVS- Tag, Et c . . . */ #i f nde f PHP_YOUREXT_H #de f i ne PHP_YOUREXT_H #i nc l ude " php. h" e xt e r n z e nd_m

  • dul e _e nt r y y our e x t _m
  • dul e _e nt r y;

#de f i ne phpe xt _y our e x t _pt r & your e x t _m

  • dul e _e nt r y

/ * Onl y ne e de d i f you' l l be expor t i ng s ym bol s */ #i f de f PHP_W I N32 # de f i ne YOUREXT_API __de c l s pe c ( dl l e xpor t ) #e l s e # de f i ne YOUREXT_API #e ndi f / * Pl ac e f or gl obal s de f i ni t i on */ #e ndi f / * PHP_YOUREXT_H */

slide-17
SLIDE 17

PHP Extension Writing 17 Börger, Schlüter

Layout of the .c file

  • Header: License, Authors, CVS-Tag, ...
  • Includes
  • Structures and defines not in header
  • Helper Functions
  • PHP Functions
  • Globals Handling
  • MINFO
  • MINIT, MSHUTDOWN
  • RINIT, RSHUTDOWN
  • Function table
  • Module Entry
slide-18
SLIDE 18

PHP Extension Writing 18 Börger, Schlüter

Includes

  • Include path:
  • < PHP Root> /
  • < PHP Root> / Zend
  • < PHP Root> / main
  • < PHP Root> / ext/ < Your Extension>

#i f de f HAVE_CONFI G_H #i nc l ude " c onf i g. h" #e ndi f #i nc l ude " php. h" #i nc l ude " php_i ni . h" #i nc l ude " e xt / s t a nda r d/ i nf o. h" #i nc l ude " e xt / s t a nda r d/ php_s t r i ng. h" #i nc l ude " php_y our e x t . h"

slide-19
SLIDE 19

PHP Extension Writing 19 Börger, Schlüter

t ype de f s t r uc t _php_your e xt _da t a { i nt t ype ; c ha r *na m e ; i nt na m e _l e n; php_s t r e a m *s t r e a m ; } php_your e xt _da t a ; #de f i ne PHP_YOUREXT_M EANI NG 42 #de f i ne PHP_YOUREXT_COLOR " pur pl e " #de f i ne PHP_YOUREXT_STRLEN( v) ( v ? s t r l e n( v) : 0)

Structures and defines not in header

  • What ever you want
  • Local storage structures?
  • Constants?
  • Macros?
slide-20
SLIDE 20

PHP Extension Writing 20 Börger, Schlüter

Helper Functions

  • Use TSRMLS_xx as last function parameter

When dealing with PHP Data Use --enable-maintainer-zts when building PHP

  • Use static or inline

If you need the funtion only in your .c file

  • Use PHPAPI / YOREXT_API

If you plan to use the functions in other extensions

slide-21
SLIDE 21

PHP Extension Writing 21 Börger, Schlüter s t a t i c voi d m y_he l pe r ( TSRM LS_D) ; s t a t i c voi d s om e _f unc t i on( TSRM LS_D) { m y_he l pe r ( TSRM LS_C) ; }

Helper Functions

  • Use TSRMLS_xx as last function parameter

When dealing with PHP Data TSRMLS_D in declarations as only param TSRMLS_C in uses (calls) as only param

slide-22
SLIDE 22

PHP Extension Writing 22 Börger, Schlüter s t a t i c voi d m y_he l pe r ( voi d * p TSRM LS_DC) ; s t a t i c voi d s om e _f unc t i on( voi d * p TSRM LS_DC) { m y_he l pe r ( p TSRM LS_CC) ; }

Helper Functions

  • Use TSRMLS_xx as last function parameter

When dealing with PHP Data TSRMLS_D in declarations as only param TSRMLS_DC in declarations after last param w/ o comma TSRMLS_C in uses (calls) as only param TSRMLS_CC in uses after last param w/ o comma

slide-23
SLIDE 23

PHP Extension Writing 23 Börger, Schlüter s t a t i c voi d m y_he l pe r ( c ha r *p, i nt p_l e n TSRM LS_DC) ; s t a t i c voi d s om e _f unc t i on( c har *p) { i nt p_l e n; TSRM LS_FETCH( ) ; p_l e n = s t r l e n( p) ; m y_he l pe r ( p, p_l e n TSRM LS_CC) ; }

Helper Functions

  • Use TSRMLS_xx as last function parameter

When dealing with PHP Data TSRMLS_D in declarations as only param TSRMLS_DC in declarations after last param w/ o comma TSRMLS_C in implementations as only param TSRMLS_CC in impl. after last param w/ o comma TSRMLS_FETCH create a TSRM key, must follow last local var

slide-24
SLIDE 24

PHP Extension Writing 24 Börger, Schlüter

Module Entry

  • Keeps everything together
  • Tells PHP how to (de)initialize the extension

z e nd_m

  • dul e _e nt r y y our e x t _m
  • dul e _e nt r y = { / * {{{ */

STANDARD_M ODULE_HEADER, " Your Ex t " , y our e x t _f unc t i ons , PHP_M I NI T( y our e x t ) , PHP_M SHUTDOW N( y our e x t ) , PHP_RI NI T( y our e x t ) , PHP_RSHUTDOW N( y our e x t ) , PHP_M I NFO( y our e x t ) , " 0. 1" , STANDARD_M ODULE_PROPERTI ES }; / * }}} */ #i f COM PI LE_DL_YOUREXT ZEND_GET_M ODULE( y our e x t ) #e ndi f

  • r NULL
slide-25
SLIDE 25

PHP Extension Writing 25 Börger, Schlüter

Function List

  • Exports your functions to userspace
  • Must be terminated by NULL tripplet

z e nd_f unc t i on_e nt r y y our e x t _f unc t i ons [ ] = { / * {{{ */ PHP_FE( y our e x t _f unc 1, y our e x t _ar gs _f unc 1) PHP_FE( y our e x t _f unc 2, NULL) PHP_FALI AS( y our e x t _f unc 3, y our e x t _f unc 2, NULL) PHP_NAM ED_FE( y our e x t _f unc 4, _y our e x t _f unc 4_i mpl , NULL) {NULL, NULL, NULL} };

slide-26
SLIDE 26

PHP Extension Writing 26 Börger, Schlüter

s t a t i c ZEND_BEGI N_ARG_I NFO_EX( y our e x t _ar gs _f unc 1, 0, 0, 2) ZEND_ARG_I NFO( 0, par am_name 1) ZEND_ARG_ARRAY_I NFO( 1, par am_name 2) ZEND_END_ARG_I NFO( ) ;

ArgInfo / Signatures

  • The function table allows specifing the signature
  • ZEND_BEGIN_ARG_INFO_EX:

name, pass_rest_by_ref, return_ref, required_args

  • ZEND_ARG_INFO:

pass_by_ref, name

  • ZEND_ARG_PASS_INFO:

pass_by_ref

  • ZEND_ARG_ARRAY_INFO:

pass_by_ref, name

  • ZEND_ARG_OBJ_INFO:

pass_by_ref, name, classname, allow_null

slide-27
SLIDE 27

PHP Extension Writing 27 Börger, Schlüter

/ * {{{ pr ot o t y pe y our e x t _name ( par ams ) Shor t de s c r i pt i on */ PHP_FUNCTI ON( y our e x t _name ) { / * Loc al de c l ar at i ons */ / * Par ame t e r par s i ng */ / * Ac t ual c ode */ / * Re t ur n v al ue */ } / * }}} */

PHP Functions

  • Namespace your functions with your ext's name
  • Documentation is your friend

Avoid / / style C+ + com ments Avoid declarations inline with code

slide-28
SLIDE 28

PHP Extension Writing 28 Börger, Schlüter

Outputting Content

  • Do not send content to stdout
  • use PHP's output buffering mechanisms
  • php_printf() works just like printf()
  • PHPWRITE() respects binary safety

/ * {{{ pr ot o nul l y our e x t _he l l o_wor l d( ) Sa y He l l o */ PHP_FUNCTI ON( y our e x t _he l l o_wor l d) { c ha r *gr e e t i ng = " He l l o W

  • r l d" ;

php_pr i nt f ( " % s ! \ n" , gr e e t i ng) ; PHPW RI TE( gr e e t i ng, s t r l e n( gr e e t i ng) ) ; php_pr i nt f ( " ! \ n" ) ; } / * }}} */

slide-29
SLIDE 29

PHP Extension Writing 29 Börger, Schlüter

i nt z e nd_pa r s e _pa r a m e t e r s ( i nt num _a r gs TSRM LS_DC, c ha r *t ype _s pe c , . . . ) ; i nt z e nd_pa r s e _pa r a m e t e r s _e x( i nt f l a gs , i nt num _a r gs TSRM LS_DC, c ha r *t ype _s pe c , . . . ) ; f l a gs 0 or ZEND_PARSE_PARAM S_QUI ET num _a r gs us e ZEND_NUM _ARGS( ) t ype _s pe c s s c a nf l i ke t ype l i s t ( t hough no % ) . . . Re f e r e nc e s t o t he t ype s gi ve n i n t ype _s pe c r e t ur ns SUCCESS or FAI LURE i n c a s e of f a i l ur e a n e r r or i s a l r e a dy i s s ue d s o no ne e d f or ZEND_W RONG_PARAM _COUNT( ) unl e s s us i ng ZEND_PARSE_PARAM S_QUI ET

Parsing parameters

  • zend_parse_parameters is the easy way of parsing
slide-30
SLIDE 30

PHP Extension Writing 30 Börger, Schlüter

t ype _s pe c s s c a nf l i ke t ype l i s t ( t hough no % ) l l ong l ong * d doubl e doubl e * b bool e a n z e nd_bool * a a r r a y z va l **

  • bj e c t

z va l ** O

  • bj e c t

z va l **, z e nd_c l a s s _e nt r y * Obj e c t m us t be de r i ve d f r om gi ve n c l a s s s s t r i ng c ha r **, i nt * You r e c e i ve s t r i ng a nd l e ngt h r r e s our c e z va l ** z z va l z va l ** Z z va l - r e f z va l *** | r i ght pa r t i s opt i ona l / ne xt pa r a m ge t s s e pa r a t e d i f not r e f e r e nc e ! Ne xt pa r a m r e t ur ns NULL i f pa r a m t ype I S_NULL

Parsing parameters

slide-31
SLIDE 31

PHP Extension Writing 31 Börger, Schlüter

Parsing Parameters

/ * {{{ pr ot o nul l y our e x t _he l l o( s t r i ng na m e ) Gr e e t by na m e */ PHP_FUNCTI ON( y our e x t _he l l o) { c ha r *na m e ; i nt na m e _l e n; i f ( z e nd_pa r s e _pa r a m e t e r s ( ZEND_NUM _ARGS( ) TSRM LS_CC, " s " , & na m e , & na m e _l e n) == FAI LURE) { r e t ur n; } php_pr i nt f ( " He l l o % s ! \ n" , na m e ) ; } / * }}} */

slide-32
SLIDE 32

PHP Extension Writing 32 Börger, Schlüter

Returning Values

  • Marking success

/ * {{{ pr ot o bool y our e x t _he l l o( s t r i ng na m e ) Gr e e t by na m e */ PHP_FUNCTI ON( y our e x t _he l l o) { c ha r *na m e ; i nt na m e _l e n; i f ( z e nd_pa r s e _pa r a m e t e r s ( ZEND_NUM _ARGS( ) TSRM LS_CC, " s " , & na m e , & na m e _l e n) == FAI LURE) { r e t ur n; } php_pr i nt f ( " He l l o % s ! \ n" , na m e ) ; RETURN_TRUE; } / * }}} */ Makes the return value NULL

slide-33
SLIDE 33

PHP Extension Writing 33 Börger, Schlüter

Returning Values

  • Simple scalars use intuitive RETURN_* () macros

RETURN_NULL( ) ; RETURN_BOOL( b) ; b: 0 => FALSE, non- 0 => TRUE RETURN_TRUE; RETURN_BOOL( 1) RETURN_FALSE; RETURN_BOOL( 0) RETURN_LONG( l ) ; l : I nt e ge r va l ue RETURN_DOUBLE( d) ; d: Fl oa t i ng poi nt va l ue

slide-34
SLIDE 34

PHP Extension Writing 34 Börger, Schlüter

Returning Values

  • Strings are slightly more complex
  • The string value must "belong" to the engine
  • Will not survive the destruction of the zval
  • Will be freed using efree()
  • Pass 0 (zero) for dup to give it the string
  • Pass 1 (one) for dup to make a copy (duplicate)

RETURN_STRI NG( s t r , dup) s t r : c har * s t r i ng va l ue dup: 0/ 1 f l ag, dupl i c at e s t r i ng? RETURN_STRI NGL( s t r , l en, dup) l e n: Pr ede t er m i ne d s t r i ng l engt h RETURN_STRI NG( " He l l o W

  • r l d" , 1) ;

RETURN_STRI NG( es t r dup( " He l l o W

  • r l d" ) , 0) ;

RETURN_EM PTY_STRI NG( ) ;

slide-35
SLIDE 35

PHP Extension Writing 35 Börger, Schlüter

Setting Returning Values

  • RETURN_* () macros automatically exit function

#de f i ne RETURN_NULL( ) { RETVAL_NULL( ) ; r e t ur n; } #de f i ne RETURN_TRUE { RETVAL_TRUE; r e t ur n; } #de f i ne RETURN_FALSE { RETVAL_FALSE; r e t ur n; } #de f i ne RETURN_BOOL( b) { RETVAL_BOOL( b) ; r e t ur n; } #de f i ne RETURN_LONG( l ) { RETVAL_LONG( l ) ; r e t ur n; } #de f i ne RETURN_DOUBLE( d) { RETVAL_DOUBLE( d) ; r e t ur n; } #de f i ne RETURN_STRI NG( s t r , dup) \ { RETVAL_STRI NG( s t r , dup) ; r e t ur n; } #de f i ne RETURN_STRI NGL( s t r , l e n, dup) \ { RETVAL_STRI NGL( s t r , l e n, dup) ; r e t ur n; } #de f i ne RETURN_EM PTY_STRI NG( ) \ { RETVAL_EM PTY_STRI NG( ) ; r e t ur n; }

slide-36
SLIDE 36

PHP Extension Writing 36 Börger, Schlüter

Setting Returning Values

  • RETURN_* () macros automatically exit function
  • RETVAL_* () family work the same without exiting

#de f i ne RETVAL_NULL( ) ZVAL_NULL( r et ur n_va l ue) #de f i ne RETVAL_TRUE ZVAL_TRUE( r et ur n_va l ue) #de f i ne RETVAL_FALSE ZVAL_FALSE( r e t ur n_va l ue) #de f i ne RETVAL_BOOL( b) ZVAL_BOOL( r et ur n_va l ue, b) #de f i ne RETVAL_LONG( l ) ZVAL_LONG( r et ur n_va l ue, l ) #de f i ne RETVAL_DOUBLE( d) ZVAL_DOUBLE( r e t ur n_va l ue , d) #de f i ne RETVAL_STRI NG( s t r , dup) \ ZVAL_STRI NG( r e t ur n_va l ue , s t r , dup) #de f i ne RETVAL_STRI NGL( s t r , l e n, dup) \ ZVAL_STRI NGL( r et ur n_val ue , s t r , l e n, dup) #de f i ne RETVAL_EM PTY_STRI NG( ) \ ZVAL_EM PTY_STRI NG( r e t ur n_va l ue )

slide-37
SLIDE 37

PHP Extension Writing 37 Börger, Schlüter

Setting Returning Values

  • RETURN_* () macros automatically exit function
  • RETVAL_* () family work the same without exiting
  • ZVAL_* () family work on specific zval (later)

#de f i ne RETVAL_NULL( ) ZVAL_NULL( r et ur n_va l ue) #de f i ne RETVAL_TRUE ZVAL_TRUE( r et ur n_va l ue) #de f i ne RETVAL_FALSE ZVAL_FALSE( r e t ur n_va l ue) #de f i ne RETVAL_BOOL( b) ZVAL_BOOL( r et ur n_va l ue, b) #de f i ne RETVAL_LONG( l ) ZVAL_LONG( r et ur n_va l ue, l ) #de f i ne RETVAL_DOUBLE( d) ZVAL_DOUBLE( r e t ur n_va l ue , d) #de f i ne RETVAL_STRI NG( s t r , dup) \ ZVAL_STRI NG( r e t ur n_va l ue , s t r , dup) #de f i ne RETVAL_STRI NGL( s t r , l e n, dup) \ ZVAL_STRI NGL( r et ur n_val ue , s t r , l e n, dup) #de f i ne RETVAL_EM PTY_STRI NG( ) \ ZVAL_EM PTY_STRI NG( r e t ur n_va l ue )

slide-38
SLIDE 38

PHP Extension Writing 38 Börger, Schlüter

Example 1

  • Inverting a single boolean parameter

/ * {{{ pr ot o bool y our e x t _i nve r t ( bool b) I nve r t a bool e a n pa r a m e t e r */ PHP_FUNCTI ON( y our e x t _i nve r t ) { z e nd_bool b; i f ( z e nd_pa r s e _pa r a m e t e r s ( ZEND_NUM _ARGS( ) TSRM LS_CC, " b" , & b) == FAI LURE) { r e t ur n; } b = b ? 0 : 1; RETURN_BOOL( b) ; } / * }}} */

slide-39
SLIDE 39

PHP Extension Writing 39 Börger, Schlüter

Example 2

  • Incrementing a value with an optional maximum

/ * {{{ pr ot o i nt y our e x t _i nc r e m e nt ( i nt v [ , i nt m a x] ) I nc r e m e nt a va l ue wi t h opt i ona l m a xi m um */ PHP_FUNCTI ON( y our e x t _i nc r e m e nt ) { l ong n, nm a x = LONG_M AX; i f ( z e nd_pa r s e _pa r a m e t e r s ( ZEND_NUM _ARGS( ) TSRM LS_CC, " l | l " , & n, & nm a x) == FAI LURE) { RETURN_FALSE( ) ; } n = ( n+1) % nm a x; RETURN_LONG( n) ; } / * }}} */ Initialize

  • ptional

values Use brackets for optional values A vertical bar separates

  • ptional and required

parameters

slide-40
SLIDE 40

PHP Extension Writing 40 Börger, Schlüter

#de f i ne YOUREXT_VERSI ON_M AJ OR #de f i ne YOUREXT_VERSI ON_M I NOR 1 / * {{{ pr ot o s t r i ng y our e x t _ve r s i on( ) Re t r i e ve y our e x t ve r s i on */ PHP_FUNCTI ON( y our e x t _ve r s i on) { c ha r * ve r ; i nt l e n; l e n = s ppr i nt f ( & ve r , 0, " %

  • d. %

d ( % s ) " , YOUREXT_VERSI ON_M AJ OR, YOUREXT_VERSI ON_M I NOR, " $I d: $" ) ; RETURN_STRI NGL( ve r , l e n, 0) ; } / * }}} */

Example 3

  • Returning some generated string

Never use sprintf, use either snprintf or spprintf No need to copy the string

slide-41
SLIDE 41

PHP Extension Writing 41 Börger, Schlüter

i nt a dd_a s s oc _l ong( z va l *a r g, c ha r *ke y, l ong n) ; i nt a dd_a s s oc _nul l ( z va l *a r g, c ha r *ke y) ; i nt a dd_a s s oc _bool ( z va l *a r g, c ha r *ke y, i nt b) ; i nt a dd_a s s oc _r e s our c e ( z va l *a r g, c ha r *ke y, i nt r ) ; i nt a dd_a s s oc _doubl e ( z va l *a r g, c ha r *ke y, doubl e d) ; i nt a dd_a s s oc _s t r i ng( z va l *a r g, c ha r *ke y, c ha r *s t r , i nt dup) ; i nt a dd_a s s oc _s t r i ngl ( z va l *a r g, c ha r *ke y, c ha r *s t r , ui nt l e n, i nt dup) ; i nt a dd_a s s oc _z va l ( z va l *a r g, c ha r *ke y, z va l *va l ue ) ;

Dealing with arrays

  • To initialize a zval as an array: a r r a y_i ni t ( pz v)
  • To return an array use: a r r a y_i ni t ( r e t ur n_va l ue )
  • To add elements use the following
  • a dd_a s s oc _<t ype >( a r , ke y, . . . )
  • a dd_a s s oc _<t ype >_e x( a r , ke y, ke y_l e n, . . . )
slide-42
SLIDE 42

PHP Extension Writing 42 Börger, Schlüter

i nt a dd_i nde x_l ong( z va l *a r g, ui nt i dx, l ong n) ; i nt a dd_i nde x_nul l ( z va l *a r g, ui nt i dx) ; i nt a dd_i nde x_bool ( z va l *a r g, ui nt i dx, i nt b) ; i nt a dd_i nde x_r e s our c e ( z va l *a r g, ui nt i dx, i nt r ) ; i nt a dd_i nde x_doubl e ( z va l *a r g, ui nt i dx, doubl e d) ; i nt a dd_i nde x_s t r i ng( z va l *a r g, ui nt i dx, c ha r *s t r , i nt dupl i c a t e ) ; i nt a dd_i nde x_s t r i ngl ( z va l *a r g, ui nt i dx, c ha r *s t r , ui nt l e ngt h, i nt dupl i c a t e ) ; i nt a dd_i nde x_z va l ( z va l *a r g, ui nt i dx, z va l *va l ue ) ;

Dealing with arrays

  • To convert a zval into an array: a r r a y_i ni t ( pz v)
  • To return an array use: a r r a y_i ni t ( r e t ur n_va l ue )
  • To add elements use the following
  • a dd_a s s oc _<t ype >( a r , ke y, . . . )
  • a dd_i nde x_<t ype >( a r , i nde x, . . . )
slide-43
SLIDE 43

PHP Extension Writing 43 Börger, Schlüter

i nt a dd_ne xt _i nde x_l ong( z va l *a r g, l ong n) ; i nt a dd_ne xt _i nde x_nul l ( z va l *a r g) ; i nt a dd_ne xt _i nde x_bool ( z va l *a r g, i nt b) ; i nt a dd_ne xt _i nde x_r e s our c e ( z va l *a r g, i nt r ) ; i nt a dd_ne xt _i nde x_doubl e ( z va l *a r g, doubl e d) ; i nt a dd_ne xt _i nde x_s t r i ng( z va l *a r g, c ha r *s t r , i nt dupl i c a t e ) ; i nt a dd_ne xt _i nde x_s t r i ngl ( z va l *a r g, c ha r *s t r , ui nt l e ngt h, i nt dupl i c a t e ) ; i nt a dd_ne xt _i nde x_z va l ( z va l *a r g, z va l *va l ue ) ;

Dealing with arrays

  • To convert a zval into an array: a r r a y_i ni t ( pz v)
  • To return an array use: a r r a y_i ni t ( r e t ur n_va l ue )
  • To add elements use the following
  • a dd_a s s oc _<t ype >( a r , ke y, . . . )
  • a dd_i nde x_<t ype >( a r , i nde x, . . . )
  • a dd_ne xt _i nde x_<t ype >( a r , . . . )
slide-44
SLIDE 44

PHP Extension Writing 44 Börger, Schlüter

/ * {{{ pr ot o a r r a y y our e x t _ve r s i on_a r r a y( ) Re t r i e ve y our e x t ve r s i on a s a r r a y */ PHP_FUNCTI ON( y our e x t _ve r s i on_a r r a y) { c ha r *ve r ; i nt l e n = s ppr i nt f ( & ve r , 0, " %

  • d. %

d" , YOUREXT_VERSI ON_M AJ OR, YOUREXT_VERSI ON_M I NOR) ; a r r a y_i ni t ( r e t ur n_va l ue ) ; a dd_a s s oc _l ong( r e t ur n_va l ue , " m a j or " , YOUREXT_VERSI ON_M AJ OR) ; a dd_a s s oc _l ong( r e t ur n_va l ue , " m i nor " , YOUREXT_VERI SON_M I NOR) ; a dd_a s s oc _s t r i ng( r e t ur n_va l ue , " c vs " , " $I d: $" , 1) ; a dd_a s s oc _s t r i ngl ( r e t ur n_va l ue , " ve r " , ve r , l e n, 0) ; } / * }}} */

Example 4

  • Returning an array

make return_value an array

slide-45
SLIDE 45

PHP Extension Writing 45 Börger, Schlüter

/ * a r Ke y ha s he d us i ng DJ BX33A */ ul ong z e nd_ge t _ha s h_va l ue ( c ha r *a r Ke y, ui nt nKe yLe ngt h) ; / * c ount ( $ht ) */ i nt z e nd_ha s h_num _e l e m e nt s ( Ha s hTa bl e *ht ) ; / * Re m

  • ve s a l l e l e m

e nt s f r om t he Ha s hTa bl e */ i nt z e nd_ha s h_c l e a n( Ha s hTa bl e *ht ) ;

Dealing with a HashTable

  • Multiple values stored in key/ value pairs
  • Arrays are special HashTables (Symbol tables)
  • Numeric keys get converted to strings
  • All values are zval* pointers.
slide-46
SLIDE 46

PHP Extension Writing 46 Börger, Schlüter

a dd_a s s oc _z va l ( a r r , " f oo" , va l ) ; a dd_a s s oc _z va l _e x( a r r , " f oo" , s i z e of ( " f oo" ) , va l ) ; z e nd_s ym t a bl e _upda t e ( Z_ARRVAL_P( a r r ) , " f oo" , s i z e of ( " f oo" ) , & va l , s i z e of ( z va l *) , NULL) ;

Adding to HashTables

  • add_assoc/ index_* () functions wrap

zend_symtable_update()

  • Symbol table keys include terminating NULL byte

sizeof(key) vs. strlen(key)

slide-47
SLIDE 47

PHP Extension Writing 47 Börger, Schlüter

i nt z e nd_ha s h_de l ( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe n) ; i nt z e nd_ha s h_i nde x_de l ( Ha s hTa bl e *ht , ul ong h) ; i nt z e nd_s ym t a bl e _de l ( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe ngt h) ;

Deleting from HashTables

  • You can delete elements (SUCCESS/ FAI LURE)
  • by key
  • by hash index
  • by symbol
slide-48
SLIDE 48

PHP Extension Writing 48 Börger, Schlüter

i nt z e nd_ha s h_e xi s t s ( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe ngt h) ; i nt z e nd_ha s h_qui c k_e xi s t s ( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe ngt h, ul ong h) ; i nt z e nd_ha s h_i nde x_e xi s t s ( Ha s hTa bl e *ht , ul ong h) ; i nt z e nd_s ym t a bl e _e xi s t s ( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe ngt h) ;

Searching HashTables

  • You can check for existance of elements (0/ 1)
  • by key
  • by hash index
  • by automatic preference of hash index over key (len= 0)
  • by symbol
slide-49
SLIDE 49

PHP Extension Writing 49 Börger, Schlüter

i nt z e nd_ha s h_f i nd( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe ngt h, voi d **pDa t a ) ; i nt z e nd_ha s h_qui c k_f i nd( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe ngt h, ul ong h, voi d **pDa t a ) ; i nt z e nd_ha s h_i nde x_f i nd( Ha s hTa bl e *ht , ul ong h, voi d **pDa t a ) ; i nt z e nd_s ym t a bl e _f i nd( Ha s hTa bl e *ht , c ha r *a r Ke y, ui nt nKe yLe ngt h, voi d **pDa t a ) ;

Searching HashTables

  • You can lookup elements (SUCCESS/ FAILURE)
  • by key
  • by hash index
  • by automatic preference of hash index over key (len= 0)
  • by symbol
slide-50
SLIDE 50

PHP Extension Writing 50 Börger, Schlüter

z va l **t m p; i f ( z e nd_s ym t a bl e _f i nd( ht , " ke y" , s i z e of ( " ke y" ) , ( voi d**) & t m p) == SUCCESS) { / * Do s om e t hi ng wi t h t m p */ i f ( Z_TYPE_PP( t m p) == I S_STRI NG) { PHPW RI TE( Z_STRVAL_PP( t m p) , Z_STRLEN_PP( t m p) ) ; } }

Searching HashTables

  • Symbol Tables store zval* pointers
  • When fetching, a reference to a zval* * is passed
slide-51
SLIDE 51

PHP Extension Writing 51 Börger, Schlüter

Accessing a zval

Z_LVAL( zva l ) l ong va l ue Z_BVAL( zva l ) z e nd_bool va l ue Z_DVAL( zva l ) doubl e va l ue Z_STRVAL( z val ) c ha r * va l ue Z_STRLEN( z val ) i nt l e ngt h Z_ARRVAL( z val ) Ha s hTa bl e *

  • nl y a r r a y

Z_OBJ _HANDLE( z va l ) i nt

  • bj i d

Z_OBJ _HT( z val ) z e nd_obj e c t _ha ndl er s *

  • bj ha ndl e r s

Z_OBJ CE( z va l ) z e nd_c l as s _ent r y*

  • bj cl a s s

Z_OBJ PROP( z va l ) Ha s hTa bl e * pr oper t i e s Z_OBJ _HANDLER( zva l , hf ) Z_OBJ _HT( ( z va l ) ) - >hf

  • bj ha ndl e r

Z_RESVAL( z val ) i nt r e s our c e i d Z_TYPE( zva l ) i nt I S_* HASH_OF( z va l ) Ha s hTa bl e * a r r a y+pr ops Z_*_P( z p) Z_*( *z p) Z_*_PP( zpp) Z_*( **z pp)

slide-52
SLIDE 52

PHP Extension Writing 52 Börger, Schlüter

Reference count and is-ref

Z_REFCOUNT( zva l ) Re t r i e ve r e f e r enc e c ount Z_SET_REFCOUNT( z val , r c) Se t r e f er e nce count t o <r c > Z_ADDREF( z val ) I nc r em e nt r ef e r e nce c ount Z_DELREF( z val ) De c r em e nt r ef e r e nce c ount Z_I SREF( z va l ) W he t he r z va l i s a r e f er e nc e Z_SET_I SREF( z val ) M a ke s z va l a r ef e r e nc e va r i abl e Z_UNSET_I SREF( zva l ) Re s e t s t he i s - r e f er e nce f l a g Z_SET_I SREF_TO( z val , i s ) M a ke z val a r e f e r enc e i s <i s > ! = 0 Z_*_P( z p) Z_*( *z p) Z_*_PP( zpp) Z_*( **z pp)

slide-53
SLIDE 53

PHP Extension Writing 53 Börger, Schlüter

Setting types and values

ZVAL_NULL( z p) I S_NULL J us t s e t t he t ype ZVAL_RESOURCE( zp, l ) I S_RESOURCE Se t t o r e s our c e <l > ZVAL_BOOL( z p, b) I S_BOOL Se t t o bool ea n <b> ZVAL_FALSE( zp) I S_BOOL Se t t o f a l s e ZVAL_TRUE( z p) I S_BOOL Se t t o t r ue ZVAL_LONG( z p, l ) I S_LONG Se t t o l ong <l > ZVAL_DOUBLE( z p, d) I S_DOUBLE Se t t o doubl e <d> ZVAL_STRI NG( z p, s , dup) I S_STRI NG Se t s t r i ng ZVAL_STRI NGL( z p, s , l , dup) I S_STRI NG Se t s t r i ng and l e ngt h ZVAL_EM PTY_STRI NG( z p) I S_STRI NG Se t as em pt y s t r i ng ZVAL_ZVAL( z p, z v, c opy, dt or ) Copy t he z val and i t s t ype . Al l ows t o c al l c opyi ng, ne c es s ar y f or s t r i ngs e t c . Al l ows t o des t r uc t ( del r e f ) t he or i gi na l z va l .

slide-54
SLIDE 54

PHP Extension Writing 54 Börger, Schlüter

Allocate and Initialize a zval

ALLOC_ZVAL( zp) Al l oca t e a zva l us i ng em a l l oc ( ) I NI T_PZVAL( zp) Se t r e f er e nce count a nd i s r ef 0 I NI T_ZVAL( z va l ) I ni t i a l i z e and s e t NULL, no poi nt e r ALLOC_I NI T_ZVAL( z p) Al l oca t e a nd i ni t i a l i ze a z va l M AKE_STD_ZVAL( zp) Al l oca t e, i ni t i a l i z e and s e t NULL Exa m pl e : z va l *val ; ALLOC_I NI T_ZVAL( val ) ; ZVAL_STRI NGL( val , “ M yval ” , s i z eof ( “m yva l ”) - 1, 1)

slide-55
SLIDE 55

PHP Extension Writing 55 Börger, Schlüter

Dealing with a HashTable

  • Hash tables have builtin "foreach" functions

/ * a r r a y_wa l k( $ht , $a ppl y_f unc ) */ voi d z e nd_has h_a ppl y( Has hTa bl e *ht , a ppl y_f unc _t a ppl y_f unc TSRM LS_DC) ; / * a r r a y_wa l k( $ht , $a ppl y_f unc , $dat a ) */ voi d z e nd_has h_a ppl y_wi t h_a r gum e nt ( Ha s hTabl e *ht , a ppl y_f unc _ar g_t appl y_f unc , voi d * TSRM LS_DC) ; / * M ul t i pl e a r gum ent ver s i on, * Thi s i s al s o t he onl y va r i a nt whi c h pr ovi des * t he ke y t o t he c a l l ba c k */ voi d z e nd_has h_a ppl y_wi t h_a r gum e nt s ( Has hTa bl e *ht , a ppl y_f unc _ar gs _t a ppl y_f unc, i nt , . . . ) ;

slide-56
SLIDE 56

PHP Extension Writing 56 Börger, Schlüter

Dealing with a HashTable

  • Hash tables have builtin "foreach" functions
  • Each function requires a different type of callback

/ * pDe s t c ont a i ns a poi nt e r t o * wha t ' s s t or ed i n t he Ha s hTa bl e * Si nc e t her e i s a z val * i n Sym bol Ta bl e s * we wi nd up wi t h a zva l ** be i ng pa s s e d a s pDe s t * t ype de f i nt ( *appl y_f unc _t ) ( voi d *pDe s t TSRM LS_DC) ; t ype de f i nt ( *appl y_f unc _a r g_t ) ( voi d *pDes t , voi d *a r gum ent TSRM LS_DC) ; t ype de f i nt ( *appl y_f unc _a r gs _t ) ( voi d *pDe s t , i nt num _a r gs , va _l i s t a r gs , z e nd_ha s h_key *ha s h_key) ;

slide-57
SLIDE 57

PHP Extension Writing 57 Börger, Schlüter

Dealing with a HashTable

  • Hash tables have builtin "foreach" functions
  • Each function requires a different type of callback
  • Callbacks return one of three status values
  • Prior to 5.2.1 all non zero return values result in deletion

/ * Cont i nue i t t e r at i ng t he Ha s hTa bl e */ #de f i ne ZEND_HASH_APPLY_KEEP / * Rem

  • ve t hi s e l em

e nt , but c ont i nue pr oce s s i ng */ #de f i ne ZEND_HASH_APPLY_REM OVE 1<<0 / * Ter m i na t e t he l oop ( br e a k; ) */ #de f i ne ZEND_HASH_APPLY_STOP 1<<1

slide-58
SLIDE 58

PHP Extension Writing 58 Börger, Schlüter

Example 5 a

  • Using zend_hash_apply_with_arguments()

/ * {{{ pr ot o voi d y our ex t _f or e ac h( a r r a y nam e s , s t r i ng gr e e t i ng) Sa y he l l o t o e ac h pe r s on */ PHP_FUNCTI ON( y our ex t _f or e a c h) { z va l *nam e s ; c ha r *gr e e t ; i nt gr e et _l en; i f ( ze nd_pa r s e _pa r a m e t er s ( ZEND_NUM _ARGS( ) TSRM LS_CC, " a s " , & na m e s , & gr ee t , & gr e e t _l en) == FAI LURE) { r e t ur n; } z e nd_ha s h_a ppl y_wi t h_ar gum e nt ( Z_ARRVAL_P( na m es ) , ( a ppl y_f unc _a r g_t ) y our ex t _f or e ac h, gr ee t TSRM LS_CC) ; } / * }}} */

slide-59
SLIDE 59

PHP Extension Writing 59 Börger, Schlüter

/ * {{{ your ex t _f or e a c h Ca l l bac k f or out put t i ng a gr ee t i ng f or e ac h na m e i n a us e r - pr ovi de d a r r a y */ i nt your e x t _f or e a ch( z val **pa r am , cha r *gr e e t i ng TSRM LS_DC) { i f ( Z_TYPE_PP( pa r am ) == I S_STRI NG) { php_pr i nt f ( " % s % s \ n" , gr e e t i ng, Z_STRVAL_PP( par a m ) ) ; r e t ur n ZEND_HASH_APPLY_KEEP; } e l s e { php_er r or _doc r ef ( NULL TSRM LS_CC, E_W ARNI NG, " Non- s t r i ng va l ue pa s s ed i n $nam e s a r r a y" ) ; r e t ur n ZEND_HASH_APPLY_STOP; } } / * }}} */

Example 5 b

  • Calling a function for each element
slide-60
SLIDE 60

PHP Extension Writing 60 Börger, Schlüter

Part II PHP Lifecycle

  • The PHP Lifecycle
  • Memory Allocation and Garbage Collection
  • Globals
  • Constants
slide-61
SLIDE 61

PHP Extension Writing 61 Börger, Schlüter

STARTUP

  • Initial startup of a PHP process space
  • Initialize engine and core components
  • Parse php.ini
  • Initialize (MINIT) staticly built modules
  • Initialize (MINIT) shared modules

(loaded by php.ini)

  • Finalize Initialization
slide-62
SLIDE 62

PHP Extension Writing 62 Börger, Schlüter

ACTIVATION

  • Triggered upon receiving a new request (page hit)
  • Initialize environment and variables

(symbol_table, EGPCS)

  • Activate (RINIT) static built modules
  • Activate (RINIT) shared modules
slide-63
SLIDE 63

PHP Extension Writing 63 Börger, Schlüter

RUNTIME

  • Actual execution of scripts happens here.
  • Compile and execute auto_prepend_file.
  • Compile and execute main_file.
  • Compile and execute auto_append_file.
slide-64
SLIDE 64

PHP Extension Writing 64 Börger, Schlüter

DEACTIVATION

  • Upon exit(), die(), E_ERROR,
  • r end of last script execution.
  • Call user-defined shutdown functions.
  • Destroy object instances.
  • Flush output.
  • Deactivate (RSHUTDOWN) modules

(in reverse of activation order)

  • Clean up environment
  • Implicitly free remaining non-persistent memory.
slide-65
SLIDE 65

PHP Extension Writing 65 Börger, Schlüter

SHUTDOWN

  • Final good-night. Called as process space is

terminating (apache child termination).

  • Shutdown (MSHUTDOWN) all modules

(rev. startup order)

  • Shutdown the engine

MINIT RUNTIME RINIT RSHUTDOWN MSHUTDOWN RUNTIME RINIT RSHUTDOWN

Request 1 Request n

slide-66
SLIDE 66

PHP Extension Writing 66 Börger, Schlüter

Memory Allocation

  • Traditionall malloc() family may be used

voi d * m a l l oc ( s i ze _t s i z e ) ; voi d * c a l l oc ( s i ze _t nm e m b, s i z e _t s i z e ) ; voi d * r e a l l oc( voi d *pt r , s i z e_t s i z e) ; voi d * s t r dup( c har *s t r ) ; voi d * s t r ndup( c ha r *s t r , s i z e_t l e n) ; voi d f r e e ( voi d *pt r ) ;

slide-67
SLIDE 67

PHP Extension Writing 67 Börger, Schlüter

Memory Allocation

  • Traditionall malloc() family may be used
  • Non-persistent allocators prefixed with e
  • Additional helpers provided by engine
  • Automatically freed by engine during DEACTIVATION

voi d * em a l l oc ( s i ze _t s i z e ) ; voi d * ec a l l oc ( s i ze _t nm e m b, s i z e _t s i z e ) ; voi d * er e a l l oc( voi d *pt r , s i z e_t s i z e) ; voi d * es t r dup( c har *s t r ) ; voi d * es t r ndup( c ha r *s t r , s i z e_t l e n) ; voi d e f r e e ( voi d *pt r ) ; voi d *s af e _em a l l oc( s i ze_t nm e m b, s i z e _t s i z e , s i z e _t adt l ) ; void *STR_EMPTY_ALLOC(void);

slide-68
SLIDE 68

PHP Extension Writing 68 Börger, Schlüter

Memory Allocation

  • Traditionall malloc() family may be used
  • Non-persistent allocators prefixed with e
  • Selective allocators prefixed with pe
  • pestrndup() not available
  • safe_pemalloc() requires PHP > = 5.1

voi d *pem a l l oc ( s i ze _t s i z e , i nt pe r s i s t ) ; voi d *pec a l l oc ( s i ze _t nm e m b, s i z e _t s i z e , i nt pe r s i s t ) ; voi d *per e a l l oc( voi d *pt r , s i z e_t s i z e, i nt per s i s t ) ; voi d *pes t r dup( c har *s t r , i nt pe r s i s t ) ; voi d pe f r e e ( voi d *pt r , i nt pe r s i s t ) ; voi d *s af e _pe m al l oc ( s i ze _t nm e m b, s i z e_t s i z e, s i z e _t addt l , i nt pe r s i s t ) ;

slide-69
SLIDE 69

PHP Extension Writing 69 Börger, Schlüter

Storing Global Values

  • Do NOT store transient data in the global scope!
  • Threaded SAPIs will break

s t a t i c c ha r *e r r or m s g = NULL; PHP_FUNCTI ON( y our e x t _unt hr e a ds a f e ) { l ong r e t ; r e t = do_s om e t hi ng( " va l ue " , & e r r or m s g) ; i f ( e r r or m s g) { php_e r r or _doc r e f ( NULL TSRM LS_CC, E_W ARNI NG, " do_s om e t hi ng( ) f a i l e d wi t h: % s " , e r r or m s g) ; f r e e ( e r r or m s g) ; e r r or m s g = NULL; } }

slide-70
SLIDE 70

PHP Extension Writing 70 Börger, Schlüter

ZEND_BEGI N_M ODULE_GLOBALS( y our e x t ) c ha r *s t r ; i nt s t r l e n; l ong c ount e r ; ZEND_END_M ODULE_GLOBALS( y our e x t ) #i f de f ZTS # de f i ne YOUREXT_G( v) \ TSRM G( y our e x t _gl oba l s _i d, z e nd_y our e x t _gl oba l s *, v) e xt e r n i nt y our e x t _gl oba l s _i d; #e l s e # de f i ne YOUREXT_G( v) ( y our e x t _gl oba l s . v) e xt e r n z e nd_y our e x t _gl oba l s y our e x t _gl oba l s ; #e ndi f

Global struct in .h

  • Provide a structure and access macros
slide-71
SLIDE 71

PHP Extension Writing 71 Börger, Schlüter

ZEND_DECLARE_M ODULE_GLOBALS( y our e x t ) s t a t i c voi d y our e xt _gl oba l s _c t or ( z e nd_y our e x t _gl obal s *gl oba l s ) { / * I ni t i al i z e your gl obal s t r uct */ gl obal s - >s t r = NULL; gl obal s - >s t r l e n = 0; gl obal s - >c ount er = 0; } s t a t i c voi d y our e xt _gl oba l s _dt or ( z e nd_y our e x t _gl obal s *gl oba l s ) { / * Cl e a n up a ny a l l oc at e d gl obal s */ }

Global Handling in .c

  • Provide the storage/ id and ctor/ dtor functions
  • Initializer called once at (thread) startup
  • Destructor called once at (thread) shutdown
  • Allocations made here must be persistent (malloc’d)
slide-72
SLIDE 72

PHP Extension Writing 72 Börger, Schlüter

MINIT/ MSHUTDOWN

  • Allocate local storage for globals in ZTS mode
  • Call globals initialization and destruction as needed

PHP_M I NI T_FUNCTI ON( your e xt ) { ZEND_I NI T_M ODULE_GLOBALS( y our e xt , y our ex t _gl oba l s _c t or , your e xt _gl obal s _dt or ) ; r e t ur n SUCCESS; } PHP_M SHUTDOW N_FUNCTI ON( your ext ) { #i f nde f ZTS y our ex t _gl oba l s _dt or ( & your e xt _gl obal s TSRM LS_CC) ; #e ndi f r e t ur n SUCCESS; }

slide-73
SLIDE 73

PHP Extension Writing 73 Börger, Schlüter

RINIT/ RSHUTDOWN

  • Initialize request specific settings at RINIT
  • Clean up their values at RSHUTDOWN

PHP_RI NI T_FUNCTI ON( your e xt ) { / * Tr a c k num be r of t i m es t hi s t hr e ad/ pr oce s s * has s e r vi c e d r eque s t s */ YOUREXT_G( c ount e r ) ++; r e t ur n SUCCESS; } PHP_RSHUTDOW N_FUNCTI ON( your ext ) { i f ( YOUREXT_G( s t r ) ) { e f r e e( YOUREXT_G( s t r ) ) ; YOUREXT_G( s t r ) = NULL; } r e t ur n SUCCESS; }

slide-74
SLIDE 74

PHP Extension Writing 74 Börger, Schlüter

Globals Access

  • Access global values using YOUREXT_G(v) macro

PHP_FUNCTI ON( y our ex t _s et _s t r i ng) { c ha r *s t r ; i nt s t r _l e n; i f ( ze nd_pa r s e _pa r a m e t er s ( ZEND_NUM _ARGS( ) , " s " , & s t r , & s t r _l e n) == FAI LURE) { r e t ur n; } i f ( YOUREXT_G( s t r ) ) { e f r e e( YOUREXT_G( s t r ) ) ; } YOUREXT_G( s t r ) = es t r ndup( s t r , s t r _l e n) ; YOUREXT_G( s t r l en) = s t r _l e n; RETURN_TRUE; }

slide-75
SLIDE 75

PHP Extension Writing 75 Börger, Schlüter

Globals Access

  • Access global values using YOUREXT_G(v) macro

PHP_FUNCTI ON( y our ex t _get _s t r i ng) { i f ( YOUREXT_G( s t r ) ) { RETURN_STRI NGL( YOUREXT_G( s t r ) , YOUREXT_G( s t r l e n) , 1) ; } e l s e { RETURN_EM PTY_STRI NG( ) ; } }

slide-76
SLIDE 76

PHP Extension Writing 76 Börger, Schlüter

Registering consts

  • Register constants during MINIT (usually)
  • name_len here is sizeof()
  • Thus name must be a real string

Do not use string variables!

i nt ze nd_ge t _c ons t a nt ( cha r *na m e , ui nt nam e _l en, z va l *r es ul t TSRM LS_DC) ; REGI STER_LONG_CONSTANT( na m e , l va l , f l ags ) REGI STER_DOUBLE_CONSTANT( na m e , dva l , f l a gs ) REGI STER_STRI NG_CONSTANT( na m e , s t r , f l a gs ) REGI STER_STRI NGL_CONSTANT( nam e , s t r , l e n, f l ags ) i nt ze nd_r e gi s t e r _c ons t a nt ( ze nd_c ons t ant *c TSRM LS_DC) ; / * Cas e - s e ns i t i ve */ #de f i ne CONST_CS ( 1<<0) / * Per s i s t e nt */ #de f i ne CONST_PERSI STENT ( 1<<1)

slide-77
SLIDE 77

PHP Extension Writing 77 Börger, Schlüter

Registering consts

  • Persistent constants require CONST_PERSISTENT
  • Non-persistent string constants must be estrdup'd

PHP_M I NI T_FUNCTI ON( y our e x t ) { REGI STER_LONG_CONSTANT( " YOUREXT_CONSTNAM E" , 42, CONST_CS | CONST_PERSI STENT) ; REGI STER_STRI NG_CONSTANT( " YOUREXT_VERSI ON" , " $I D: $" , CONST_CS | CONST_PERSI STENT) ; r e t ur n SUCCESS; } PHP_RI NI T_FUNCTI ON( y our e x t ) { REGI STER_LONG_CONSTANT( " YOUREXT_COUNTER" , YOUREXT_G( c ount e r ) , CONST_CS) ; r e t ur n SUCCESS; }

slide-78
SLIDE 78

PHP Extension Writing 78 Börger, Schlüter

PHP_M I NFO_FUNCTI ON( y our e x t ) { php_i nf o_pr i nt _t a bl e _s t a r t ( ) ; php_i nf o_pr i nt _t a bl e _he a de r ( 2, " Your Ex t " , " e nabl e d" ) ; php_i nf o_pr i nt _t a bl e _r ow( 2, " Ve r s i on" , " $I D: $" ) ; php_i nf o_pr i nt _t a bl e _r ow( 2, " Some s t r i ng" , YOUREXT_G( s t r ) ) ; php_i nf o_pr i nt _t a bl e _e nd( ) ; }

MINFO

  • Provide some information about your extension
  • MINFO has no return value
slide-79
SLIDE 79

PHP Extension Writing 79 Börger, Schlüter

What else ?

  • INI Handling
  • Dealing with resources and streams
  • Object support
slide-80
SLIDE 80

PHP Extension Writing 80 Börger, Schlüter

Part III Adding objects

  • How to create your own classes
  • How to create interfaces
  • How to create methods
  • What can be overloaded
slide-81
SLIDE 81

PHP Extension Writing 81 Börger, Schlüter

What is needed?

  • Providing methods
  • Providing a zend_class_entry pointer
  • Providing object handlers
  • Registering the class
slide-82
SLIDE 82

PHP Extension Writing 82 Börger, Schlüter

General class layout

zval ref_count is_ref handle handlers zend_object_store_get()

  • bject_handlers()
  • bjects

zend_object_handlers tables zvals zend_class_entry

slide-83
SLIDE 83

PHP Extension Writing 83 Börger, Schlüter

General class layout

zend_class_entry function_table iterator_funcs create_object() get_iterator() interface_gets_implemented() int (*serialize)(…) int (*unserialize)(…) // function caches zend_object_handlers zend_object_iterator PHP_METHOD

slide-84
SLIDE 84

PHP Extension Writing 84 Börger, Schlüter z e nd_c l a s s _e nt r y *ut i l _ce _di r ; PHP_M I NI T_FUNCTI ON( ut i l ) / * {{{ */ { z e nd_c l a s s _e nt r y c e ; I NI T_CLASS_ENTRY( c e , " di r s " , ut i l _di r _c l a s s _f unc t i ons ) ; ut i l _c e _di r = z e nd_r e gi s t e r _i nt e r na l _c l a s s ( & c e TSRM LS_CC) ; ut i l _c e _di r - >cr e a t e _obj ec t = ut i l _di r _obj e ct _ne w; m e m c py( & ut i l _di r _ha ndl e r s , z end_ge t _s t d_obj e c t _ha ndl er s ( ) , s i z e of ( z e nd_obj e c t _ha ndl e r s ) ) ; ut i l _di r _ha ndl e r s . c l one _obj = ut i l _di r _obj ec t _c l one ; z e nd_c l a s s _i m pl e m e nt s ( ut i l _c e_di r TSRM LS_CC, 1, z e nd_c e _i t e r a t or ) ; ut i l _c e _di r - >ce _f l a gs | = ZEND_ACC_FI NAL_CLASS; ut i l _c e _di r - >ge t _i t e r a t or = ut i l _di r _ge t _i t e r a t or ; r e t ur n SUCCESS; } / * }}} */

Registering

  • Obviously you have to register your class
  • A temporary zend_class_entry is necessary first
  • After basic registering you have a dedicated pointer
  • Now you have to specify the c-level constructor function
  • Provide your own handler funcs or copy and modify defaults
  • Finally implement interfaces, set class flags, specify iterator
slide-85
SLIDE 85

PHP Extension Writing 85 Börger, Schlüter i nt z e nd_de c l ar e _c l a s s _cons t ant ( z e nd_c l a s s _e nt r y *c e , c ha r *na m e , s i z e _t na m e _l e n, z va l *va l ue TSRM LS_DC) ; i nt z e nd_de c l ar e _c l a s s _cons t ant _l ong( z e nd_cl a s s _e nt r y *c e , c ha r *na m e , s i z e _t na m e _l e n, l ong va l ue TSRM LS_DC) ; i nt z e nd_de c l ar e _c l a s s _cons t ant _bool ( z e nd_cl a s s _e nt r y *c e , c ha r *na m e , s i z e _t na m e _l e n, z e nd_bool va l ue TSRM LS_DC) ; i nt z e nd_de c l ar e _c l a s s _cons t ant _doubl e ( z e nd_c l a s s _e nt r y *ce , c ha r *na m e , s i z e _t na m e _l e n, doubl e va l ue TSRM LS_DC) ; i nt z e nd_de c l ar e _c l a s s _cons t ant _s t r i ngl ( z e nd_c l a s s _e nt r y *c e , c ha r *na m e , s i z e _t na m e _l e n, c ha r *va l , s i ze _t va l _l en TSRM LS_DC) ; i nt z e nd_de c l ar e _c l a s s _cons t ant _s t r i ng( z e nd_c l a s s _e nt r y *ce , c ha r *na m e , s i z e _t na m e _l e n, c ha r *va l ue TSRM LS_DC) ;

Declaring class constants

  • You can register class constants
  • Use target zend_class_entry pointer
  • Use sizeof() not strlen() for const name
slide-86
SLIDE 86

PHP Extension Writing 86 Börger, Schlüter / * de c l a r e m e t hod pa r a m et e r s , */ s t a t i c ZEND_BEGI N_ARG_I NFO( a r gi nf o_di r ___c ons t r uc t , 0) ZEND_ARG_I NFO( 0, pa t h) / * par a m e t e r na m e */ ZEND_END_ARG_I NFO( ) ; / * e a c h m e t hod c a n ha ve i t s own pa r a m e t e r s a nd vi s i bi l i t y */ s t a t i c z e nd_f unc t i on_e nt r y ut i l _di r _c l a s s _f unc t i ons [ ] = { PHP_M E( di r , __c ons t r uc t , a r gi nf o_di r ___c ons t r uc t , ZEND_ACC_CTOR | ZEND_ACC_PUBLI C) PHP_M E( di r , r ewi nd, NULL, ZEND_ACC_PUBLI C) PHP_M E( di r , has M

  • r e , NULL, ZEND_ACC_PUBLI C)

PHP_M E( di r , key, NULL, ZEND_ACC_PUBLI C) PHP_M E( di r , c ur r e nt , NULL, ZEND_ACC_PUBLI C) PHP_M E( di r , next , NULL, ZEND_ACC_PUBLI C) PHP_M E( di r , get Pa t h, NULL, ZEND_ACC_PUBLI C) {NULL, NULL, NULL} };

Declaring methods

slide-87
SLIDE 87

PHP Extension Writing 87 Börger, Schlüter / * de c l a r e t he c l a s s ha ndl e r s */ s t a t i c z e nd_obj e c t _ha ndl e r s ut i l _di r _ha ndl er s ; / * de c a l r e t he c l a s s e nt r y */ s t a t i c z e nd_c l a s s _e nt r y *ut i l _c e _di r ; / * t he ove r l oade d c l a s s s t r uct ur e */ / * ove r l oa di ng t he s t r uct ur e r e s ul t s i n t he ne e d of ha vi ng de di c a t e d cr e a t i n/ c l oni ng/ de s t r uc t i on f unc t i ons */ t ype de f s t r uc t _ut i l _di r _obj ec t { z e nd_obj e c t s t d; php_s t r e a m *di r p; php_s t r e a m _di r e nt e nt r y; c ha r *pa t h; i nt i nde x; } ut i l _di r _obj e c t ;

class/ object structs

  • It is a good practice to 'inherit' zend_object
  • That allows your class to support normal properties
  • Thus you do not need to overwrite all handlers

Inherit zend_object by placing it as first member of your object struct

slide-88
SLIDE 88

PHP Extension Writing 88 Börger, Schlüter

z e nd_obj e c t _va l ue ut i l _di r _obj ec t _ne w( ze nd_cl a s s _e nt r y *c e TSRM LS_DC) { z e nd_obj e c t _va l ue r e t va l ; ut i l _di r _obj ec t *i nt e r n; i nt e r n = e c a l l oc ( 1, s i z eof ( ut i l _di r _obj e c t ) ) ; z e nd_obj e c t _s t d_i ni t ( & ( i nt e r n- >s t d) , c e TSRM LS_CC) ; z e nd_ha s h_c opy( i nt e r n- >s t d. pr ope r t i e s , & c e - >de f a ul t _pr oper t i e s , ( c opy_c t or _f unc _t ) z va l _a dd_r e f , NULL, s i z e of ( z va l *) ) ; r e t va l . ha ndl e = z end_obj e c t s _s t or e _put ( i nt e r n, ut i l _di r _obj ec t _dt or , NULL TSRM LS_CC) ; r e t va l . ha ndl er s = & ut i l _di r _ha ndl e r s ; r e t ur n r e t va l ; }

Object creation/ cloning

  • Allcate memory for your struct

Initialize the whole struct (probably by using ecalloc())

  • Initialize the base Zend object
  • Copy default properties
  • Store the object
  • Assign the handlers
slide-89
SLIDE 89

PHP Extension Writing 89 Börger, Schlüter / * {{{ ut i l _di r _obj e c t _dt or */ / * c l os e a l l r e s our c e s and t he m e m

  • r y a l l oca t e d f or t he obj e c t */

s t a t i c voi d ut i l _di r _obj e ct _dt or ( voi d *obj e c t , z e nd_obj e c t _ha ndl e ha ndl e TSRM LS_DC) { ut i l _di r _obj e ct *i nt e r n = ( ut i l _di r _obj e c t *) obj e c t ; z e nd_obj e c t _s t d_dt or ( & ( i nt e r n- >s t d) TSRM LS_CC) ; i f ( i nt e r n- >pat h) { e f r e e ( i nt e r n- >pa t h) ; } i f ( i nt e r n- >di r p) { php_s t r e a m _c l os e ( i nt e r n- >di r p) ; } e f r e e ( obj e c t ) ; } / * }}} */

Object destruction

  • Free properties
  • Free all resources and free all allocated mem ory
  • Free mem ory for object itself
slide-90
SLIDE 90

PHP Extension Writing 90 Börger, Schlüter / * {{{ pr ot o s t r i ng di r : : ke y( ) Re t ur n c ur r e nt di r e nt r y */ PHP_M ETHOD( di r , ke y) { z va l *obj e c t = ge t Thi s ( ) ; ut i l _di r _obj e ct *i nt e r n = ( ut i l _di r _obj e c t *) z e nd_obj e c t _s t or e _ge t _obj e c t ( obj e c t TSRM LS_CC) ; i f ( i nt e r n- >di r p) { RETURN_LONG( i nt e r n- >i ndex) ; } e l s e { RETURN_FALSE; } } / * }}} */

A simple method

  • Macro getThis() gives you access to $this as zval
  • The returned zval is used to get your struct
slide-91
SLIDE 91

PHP Extension Writing 91 Börger, Schlüter / * {{{ pr ot o voi d di r : : __c ons t r uc t ( s t r i ng pa t h) Cons t r uc t s a ne w di r i t e r a t or f r om a pa t h. */ PHP_M ETHOD( di r , __c ons t r uc t ) { ut i l _di r _obj e ct *i nt e r n; c ha r *pa t h; i nt l e n; i f ( z e nd_pa r s e_pa r a m e t e r s ( ZEND_NUM _ARGS( ) TSRM LS_CC, " s " , & pa t h, & l e n) == SUCCESS) { i nt e r n = ( ut i l _di r _obj e ct *) z e nd_obj e c t _s t or e _ge t _obj e c t ( ge t Thi s ( ) TSRM LS_CC) ; ut i l _di r _ope n( i nt e r n, pat h TSRM LS_CC) ; } } / * }}} */

The constructor

  • Remember that your object is already fully initialized

In this case we chose to either finish initialization in the constructor or throw an exception.

slide-92
SLIDE 92

PHP Extension Writing 92 Börger, Schlüter / * {{{ pr ot o voi d di r : : __c ons t r uc t ( s t r i ng pa t h) Cons t r uc t s a ne w di r i t e r a t or f r om a pa t h. */ PHP_M ETHOD( di r , __c ons t r uc t ) { ut i l _di r _obj e ct *i nt e r n; c ha r *pa t h; i nt l e n; php_s e t _e r r or _ha ndl i ng( EH_THROW , z e nd_e xc e pt i on_ge t _de f a ul t ( ) TSRM LS_CC) ; i f ( z e nd_pa r s e_pa r a m e t e r s ( ZEND_NUM _ARGS( ) TSRM LS_CC, " s " , & pa t h, & l e n) == SUCCESS) { i nt e r n = ( ut i l _di r _obj e ct *) z e nd_obj e c t _s t or e _ge t _obj e c t ( ge t Thi s ( ) TSRM LS_CC) ; ut i l _di r _ope n( i nt e r n, pat h TSRM LS_CC) ; } php_s e t _e r r or _ha ndl i ng( EH_NORM AL, NULL TSRM LS_CC) ; } / * }}} */

The constructor

  • Remember that your object is already fully initialized

In this case we chose to either finish initialization in the constructor or throw an exception.

  • Change errors to exceptions to support constructor failure
slide-93
SLIDE 93

PHP Extension Writing 93 Börger, Schlüter / * {{{ */ s t a t i c i nt z e nd_s t d_c a s t _obj ec t _t os t r i ng( z va l *r e a dobj , z va l *wr i t e obj , i nt t ype TSRM LS_DC) { z va l *r e t va l == NULL; i f ( t ype == I S_STRI NG) { z e nd_c a l l _m e t hod_wi t h_0_pa r a m s ( & r e a dobj , NULL, NULL, " __t os t r i ng" , & r e t va l ) ; i f ( r e t va l ) { i f ( Z_TYPE_P( r e t va l ) ! = I S_STRI NG) { z e nd_e r r or ( E_ERROR, " M e t hod % s : : __t oSt r i ng( ) m us t " " r e t ur n a s t r i ng va l ue " , Z_OBJ CE_P( r e a dobj ) - >na m e ) ; } } e l s e { M AKE_STD_ZVAL( r e t va l ) ; ZVAL_EM PTY_STRI NG( r e t va l ) ; } ZVAL_ZVAL( wr i t e obj , r e t va l , 1, 1) ; I NI T_PZVAL( wr i t e obj ) ; } r e t ur n r e t va l ? SUCCESS : FAI LURE; } / * }}} */

Object casting

slide-94
SLIDE 94

PHP Extension Writing 94 Börger, Schlüter

Other handlers to overload

  • Objects can overload several handlers
  • Array access
  • Property access
  • Serializing
slide-95
SLIDE 95

PHP Extension Writing 95 Börger, Schlüter t ype de f s t r uc t _z e nd_obj e c t _ha ndl e r s { / * ge ne r a l obj e c t f unc t i ons */ z e nd_obj e c t _a dd_r e f _t a dd_r e f ; z e nd_obj e c t _del _r e f _t de l _r e f ; z e nd_obj e c t _del e t e _obj _t de l e t e _obj ; / * i ndi vi dua l obj e c t f unc t i ons */ z e nd_obj e c t _c l one _obj _t c l one _obj ; z e nd_obj e c t _r ea d_pr ope r t y_t r e a d_pr ope r t y; z e nd_obj e c t _wr i t e _pr ope r t y_t wr i t e _pr ope r t y; z e nd_obj e c t _r ea d_di m e ns i on_t r e a d_di m e ns i on; z e nd_obj e c t _wr i t e _di m e ns i on_t wr i t e _di m e ns i on; z e nd_obj e c t _get _pr ope r t y_pt r _pt r _t ge t _pr ope r t y_pt r _pt r ; z e nd_obj e c t _get _t ge t ; z e nd_obj e c t _s et _t s e t ; z e nd_obj e c t _has _pr ope r t y_t ha s _pr ope r t y; z e nd_obj e c t _uns e t _pr ope r t y_t uns e t _pr ope r t y; z e nd_obj e c t _uns e t _di m e ns i on_t uns e t _di m e ns i on; z e nd_obj e c t _get _pr ope r t i e s _t ge t _pr ope r t i e s ; z e nd_obj e c t _get _m e t hod_t ge t _m e t hod; z e nd_obj e c t _c al l _m e t hod_t c a l l _m e t hod; z e nd_obj e c t _get _c ons t r uct or _t ge t _c ons t r uc t or ; z e nd_obj e c t _get _c l a s s _e nt r y_t ge t _c l a s s _e nt r y; z e nd_obj e c t _get _c l a s s _nam e _t ge t _c l a s s _na m e; z e nd_obj e c t _c om pa r e _t c om pa r e _obj e c t s ; z e nd_obj e c t _c as t _t c a s t _obj e c t ; z e nd_obj e c t _c ount _e l e m e nt s _t c ount _e l e m e nt s ; } z e nd_obj e c t _ha ndl e r s ;

Don't touch these Keep or inherit

zend_object_handlers

slide-96
SLIDE 96

PHP Extension Writing 96 Börger, Schlüter

What else ?

  • Iterator support
slide-97
SLIDE 97

PHP Extension Writing 97 Börger, Schlüter

Part IV Adding Iterators to objects

  • Provide an iterator structure
  • Provide the handlers
  • Provide an iterator creation function
slide-98
SLIDE 98

PHP Extension Writing 98 Börger, Schlüter / * de f i ne a n ove r l oa de d i t e r at or s t r uc t ur e */ t ype de f s t r uc t { z e nd_obj e c t _i t e r a t or i nt e r n; z va l *cur r e nt ; } ut i l _di r _i t ; s t a t i c voi d ut i l _di r _i t _dt or ( z e nd_obj e c t _i t e r a t or *i t e r TSRM LS_DC) ; s t a t i c i nt ut i l _di r _i t _va l i d( z e nd_obj e c t _i t e r a t or *i t e r TSRM LS_DC) ; s t a t i c voi d ut i l _di r _i t _c ur r ent _da t a ( z e nd_obj e c t _i t e r a t or *i t e r , z va l ***da t a TSRM LS_DC) ; s t a t i c i nt ut i l _di r _i t _cur r e nt _ke y( z e nd_obj e c t _i t e r a t or *i t e r , c ha r **s t r _ke y, ui nt *s t r _ke y_l e n, ul ong *i nt _ke y TSRM LS_DC) ; s t a t i c voi d ut i l _di r _i t _m

  • ve _f or wa r d( z e nd_obj e c t _i t e r a t or *i t e r

TSRM LS_DC) ; s t a t i c voi d ut i l _di r _i t _r e wi nd( z e nd_obj e c t _i t e r a t or *i t e r TSRM LS_DC) ; / * i t e r a t or handl e r t a bl e */ z e nd_obj e c t _i t e r a t or _f unc s ut i l _di r _i t _f uncs = { ut i l _di r _i t _dt or , ut i l _di r _i t _val i d, ut i l _di r _i t _c ur r e nt _da t a, ut i l _di r _i t _c ur r e nt _ke y, ut i l _di r _i t _m

  • ve _f or wa r d,

ut i l _di r _i t _r ewi nd, NULL / * i nva l i da t e c ur r ent */ }; / * }}} */

Iterators

slide-99
SLIDE 99

PHP Extension Writing 99 Börger, Schlüter / * {{{ ut i l _di r _ge t _i t e r a t or */ z e nd_obj e c t _i t e r a t or *ut i l _di r _ge t _i t e r a t or ( z e nd_c l a s s _e nt r y *c e , z va l *obj e c t , i nt by_r e f TSRM LS_DC) { ut i l _di r _i t *i t e r a t or = e m a l l oc ( s i z e of ( ut i l _di r _i t ) ) ; i f ( by_r e f ) { z e nd_e r r or ( E_ERROR, “ I t er a t or i nva l i d i n f or e a c h by r e f " ) ; } Z_ADDREF_P( obj e c t ) ; i t e r a t or - >i nt er n. da t a = ( voi d*) obj e c t ; i t e r a t or - >i nt er n. f unc s = & ut i l _di r _i t _f unc s ; i t e r a t or - >c ur r e nt = NULL; r e t ur n ( z e nd_obj e c t _i t e r a t or *) i t e r a t or ; } / * }}} */

Creating the iterator

  • Allocate and initialize the iterator structure
  • It is a good idea to increase the original zvals refcount
slide-100
SLIDE 100

PHP Extension Writing 100 Börger, Schlüter / * {{{ ut i l _di r _i t _dt or */ s t a t i c voi d ut i l _di r _i t _dt or ( z e nd_obj e c t _i t e r a t or *i t e r TSRM LS_DC) { ut i l _di r _i t *i t e r a t or = ( ut i l _di r _i t *) i t e r ; z va l *i nt e r n = ( zva l *) i t e r a t or - >i nt er n. da t a ; i f ( i t e r a t or - >c ur r e nt ) { z va l _pt r _dt or ( & i t e r a t or - >c ur r e nt ) ; } z va l _pt r _dt or ( & i nt e r n) ; e f r e e ( i t e r a t or ) ; } / * }}} */

Destructing the iterator

  • Free allocated memory and resources
  • Don't forget to reduce refcount of referenced object
slide-101
SLIDE 101

PHP Extension Writing 101 Börger, Schlüter / * {{{ ut i l _di r _i t _c ur r ent */ s t a t i c voi d ut i l _di r _i t _c ur r e nt ( ut i l _di r _i t *i t e r a t or , ut i l _di r _obj e c t *obj e c t TSRM LS_DC) { i f ( i t e r a t or - >c ur r e nt ) { z va l _pt r _dt or ( & i t e r a t or - >c ur r e nt ) ; } M AKE_STD_ZVAL( i t e r a t or - >c ur r ent ) ; i f ( obj e c t - >di r p) { ZVAL_STRI NG( i t e r a t or - >c ur r e nt , obj e c t - >e nt r y. d_na m e , 1) ; } e l s e { ZVAL_FALSE( i t er a t or - >c ur r e nt ) ; } } / * }}} */

Getting the data

  • Data is read on rewind() and next() calls
  • A zval* is stored inside the iterator
  • Release current zval
  • Create a new zval and assign the value
slide-102
SLIDE 102

PHP Extension Writing 102 Börger, Schlüter / * {{{ ut i l _di r _i t _va l i d */ s t a t i c i nt ut i l _di r _i t _val i d( z e nd_obj e c t _i t e r a t or *i t er TSRM LS_DC) { ut i l _di r _i t *i t e r a t or = ( ut i l _di r _i t *) i t e r ; ut i l _di r _obj e ct *obj e c t = ( ut i l _di r _obj e c t *) z e nd_obj e c t _s t or e _ge t _obj e c t ( ( z va l *) i t e r a t or - >i nt e r n. da t a TSRM LS_CC) ; r e t ur n obj e c t - >di r p & &

  • bj e c t - >e nt r y. d_na m

e [ 0] ! = ' \ 0' ? SUCCESS : FAI LURE; } / * }}} */

Iterator valid()

  • Check whether data is available

Note: Return SUCCESS or FAI LURE not typical boolean

slide-103
SLIDE 103

PHP Extension Writing 103 Börger, Schlüter / * {{{ ut i l _di r _i t _c ur r ent _key */ s t a t i c i nt ut i l _di r _i t _cur r e nt _ke y( z e nd_obj e c t _i t e r a t or *i t e r , c ha r **s t r _ke y, ui nt *s t r _ke y_l e n, ul ong *i nt _key TSRM LS_DC) { ut i l _di r _i t *i t e r a t or = ( ut i l _di r _i t *) i t e r ; z va l *i nt e r n = ( z va l *) i t e r a t or - >i nt e r n. da t a ; ut i l _di r _obj e ct *obj e ct = ( ut i l _di r _obj e ct *) z e nd_obj e c t _s t or e _ge t _obj e c t ( i nt e r n TSRM LS_CC) ; *i nt _ke y = obj e c t - >i nde x; r e t ur n HASH_KEY_I S_LONG; } / * }}} */

Iterator key()

  • The key may be one of:

Integer: H ASH _K EY_I S_LO NG Set ul ong * to the integer value String: H ASH _K EY_I S_STRI NG Set ui nt * to string length + 1 Set c har ** to copy of string (e s t r [ n] dup)

slide-104
SLIDE 104

PHP Extension Writing 104 Börger, Schlüter / * {{{ ut i l _di r _i t _c ur r ent _dat a */ s t a t i c voi d ut i l _di r _i t _c ur r ent _da t a ( z e nd_obj e c t _i t e r a t or *i t e r , z va l ***da t a TSRM LS_DC) { ut i l _di r _i t *i t e r a t or = ( ut i l _di r _i t *) i t e r ; *da t a = & i t e r at or - >c ur r ent ; } / * }}} */

Iterator current()

  • The data was already fetched on rewind() / next()
slide-105
SLIDE 105

PHP Extension Writing 105 Börger, Schlüter / * {{{ ut i l _di r _i t _c ur r ent _dat a */ s t a t i c voi d ut i l _di r _i t _c ur r ent _da t a ( z e nd_obj e c t _i t e r a t or *i t e r , z va l ***da t a TSRM LS_DC) { ut i l _di r _i t *i t e r a t or = ( ut i l _di r _i t *) i t e r ; ut i l _di r _obj e ct *obj e c t ; i f ( ! i t e r a t or - >c ur r e nt ) {

  • bj e c t = ( ut i l _di r _obj e ct *) z end_obj e c t _s t or e _ge t _obj ec t (

( z va l *) i t e r a t or - >i nt e r n. da t a TSRM LS_CC) ; ut i l _di r _i t _c ur r e nt ( i t e r a t or , obj e c t TSRM LS_CC) ; } *da t a = & i t e r at or - >c ur r ent ; } / * }}} */

Iterator current()

  • The data was already fetched on rewind() / next()
  • Alternatively
  • Reset the cached current/ key value in rewind() / next()
  • Check the cache on access and read if not yet done
slide-106
SLIDE 106

PHP Extension Writing 106 Börger, Schlüter / * {{{ ut i l _di r _i t _m

  • ve _f or war d */

s t a t i c voi d ut i l _di r _i t _m

  • ve _f or wa r d( z e nd_obj e c t _i t e r a t or *i t e r TSRM

LS_DC) { ut i l _di r _i t *i t e r at or = ( ut i l _di r _i t *) i t e r ; z va l *i nt e r n = ( z va l *) i t e r a t or - >i nt e r n. da t a ; ut i l _di r _obj e ct *obj e ct = ( ut i l _di r _obj e ct *) z e nd_obj e c t _s t or e _ge t _obj e c t ( i nt e r n TSRM LS_CC) ;

  • bj e c t - >i nde x++;

i f ( ! obj e c t - >di r p | | ! php_s t r e a m _r e a ddi r ( obj e c t - >di r p, &

  • bj e ct - >e nt r y) )

{

  • bj e c t - >e nt r y. d_na m

e [ 0] = ' \ 0' ; } ut i l _di r _i t _c ur r e nt ( i t e r a t or , obj e c t TSRM LS_CC) ; } / * }}} */

Iterator next()

  • Move to next elem ent
  • Fetch new current data
slide-107
SLIDE 107

PHP Extension Writing 107 Börger, Schlüter / * {{{ ut i l _di r _i t _r e wi nd */ s t a t i c voi d ut i l _di r _i t _r ewi nd( z e nd_obj e ct _i t e r a t or *i t e r TSRM LS_DC) { ut i l _di r _i t *i t e r a t or = ( ut i l _di r _i t *) i t e r ; z va l *i nt e r n = ( z va l *) i t e r a t or - >i nt e r n. da t a ; ut i l _di r _obj e ct *obj e c t = ( ut i l _di r _obj e c t *) z e nd_obj e c t _s t or e _ge t _obj e c t ( i nt e r n TSRM LS_CC) ;

  • bj e c t - >i nde x = 0;

i f ( obj e c t - >di r p) { php_s t r e a m _r e wi nddi r ( obj e c t - >di r p) ; } i f ( ! obj e c t - >di r p | | ! php_s t r e a m _r e a ddi r ( obj e c t - >di r p, &

  • bj e ct - >e nt r y) )

{

  • bj e c t - >e nt r y. d_na m

e [ 0] = ' \ 0' ; } ut i l _di r _i t _c ur r e nt ( i t e r a t or , obj e c t TSRM LS_CC) ; } / * }}} */

Iterator rewind()

  • Rewind to first element
  • Fetch first current data
slide-108
SLIDE 108

PHP Extension Writing 108 Börger, Schlüter

Iterator drawbacks

  • Either implement native iterators at c-level
  • Or provide iterator methods and inherit Iterator
  • If you want both
  • Your PHP methods call a specialized C-Level handler
  • Provide a cache for your method pointers
  • C-Level iterator functions check this cache
  • On a match call C-Level handler
  • Else call the method
  • Have the iterator struct part of your object struct
  • Use offset_of() for pointer conversion
slide-109
SLIDE 109

PHP Extension Writing 109 Börger, Schlüter

References

  • This presentation

http: / / talks.somabo.de

  • Documentation and Sources to PHP5

http: / / php.net

  • http: / / www.zend.com/ php/ internals
  • Advanced PHP Programming

by George Schlossnagle

  • Extending and Embedding PHP

by Sara Golemon ISBN# 0-6723-2704-X