php extension w riting
play

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


  1. 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 Börger, Schlüter PHP Extension Writing 20

  2. 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 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) ; } Börger, Schlüter PHP Extension Writing 21

  3. 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 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) ; } Börger, Schlüter PHP Extension Writing 22

  4. 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 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) ; } Börger, Schlüter PHP Extension Writing 23

  5. Module Entry � Keeps everything together � Tells PHP how to (de)initialize the extension z e nd_m odul e _e nt r y y our e x t _m odul 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 ) , or NULL 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 Börger, Schlüter PHP Extension Writing 24

  6. 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} }; Börger, Schlüter PHP Extension Writing 25

  7. 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 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( ) ; Börger, Schlüter PHP Extension Writing 26

  8. PHP Functions � Namespace your functions with your ext's name � Documentation is your friend � Avoid / / style C+ + com ments � Avoid declarations inline with code / * {{{ 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 */ } / * }}} */ Börger, Schlüter PHP Extension Writing 27

  9. 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 or 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" ) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 28

  10. Parsing parameters � zend_parse_parameters is the easy way of parsing 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 Börger, Schlüter PHP Extension Writing 29

  11. Parsing parameters 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 ** o obj e c t z va l ** O obj 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 Börger, Schlüter PHP Extension Writing 30

  12. 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 ) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 31

  13. 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; Makes the return } value NULL php_pr i nt f ( " He l l o % s ! \ n" , na m e ) ; RETURN_TRUE; } / * }}} */ Börger, Schlüter PHP Extension Writing 32

  14. 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 Börger, Schlüter PHP Extension Writing 33

  15. 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 ( dup licate) 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 or l d" , 1) ; RETURN_STRI NG( es t r dup( " He l l o W or l d" ) , 0) ; RETURN_EM PTY_STRI NG( ) ; Börger, Schlüter PHP Extension Writing 34

  16. 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; } Börger, Schlüter PHP Extension Writing 35

  17. 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 ) Börger, Schlüter PHP Extension Writing 36

  18. 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 ) Börger, Schlüter PHP Extension Writing 37

  19. 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) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 38

  20. 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 ) Initialize Use brackets { optional for optional l ong n, nm a x = LONG_M AX; values values 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( ) ; } A vertical bar separates n = ( n+1) % nm a x; optional and required parameters RETURN_LONG( n) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 39

  21. Example 3 � Returning some generated string #de f i ne YOUREXT _VERSI ON_M AJ OR 0 #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) { Never use sprintf, c ha r * ve r ; use either snprintf or spprintf 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) ; No need to } copy the string / * }}} */ Börger, Schlüter PHP Extension Writing 40

  22. 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, . . . ) 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 ) ; Börger, Schlüter PHP Extension Writing 41

  23. 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, . . . ) 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 ) ; Börger, Schlüter PHP Extension Writing 42

  24. 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 , . . . ) 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 ) ; Börger, Schlüter PHP Extension Writing 43

  25. Example 4 � Returning an array / * {{{ 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) ; make return_value an array 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) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 44

  26. 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. / * 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 ove 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 ) ; Börger, Schlüter PHP Extension Writing 45

  27. Adding to HashTables � add_assoc/ index_* () functions wrap zend_symtable_update() � Symbol table keys include terminating NULL byte sizeof(key) vs. strlen(key) 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) ; Börger, Schlüter PHP Extension Writing 46

  28. Deleting from HashTables � You can delete elements (SUCCESS/ FAI LURE) � by key � by hash index � by symbol 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) ; Börger, Schlüter PHP Extension Writing 47

  29. 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 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) ; Börger, Schlüter PHP Extension Writing 48

  30. 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 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 ) ; Börger, Schlüter PHP Extension Writing 49

  31. Searching HashTables � Symbol Tables store zval* pointers � When fetching, a reference to a zval* * is passed 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) ) ; } } Börger, Schlüter PHP Extension Writing 50

  32. 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 * onl y a r r a y Z_OBJ _HANDLE( z va l ) i nt obj i d Z_OBJ _HT( z val ) z e nd_obj e c t _ha ndl er s * obj ha ndl e r s Z_OBJ CE( z va l ) z e nd_c l as s _ent r y* obj 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 obj 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) Börger, Schlüter PHP Extension Writing 51

  33. 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) Börger, Schlüter PHP Extension Writing 52

  34. 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 . Börger, Schlüter PHP Extension Writing 53

  35. 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) Börger, Schlüter PHP Extension Writing 54

  36. 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 , . . . ) ; Börger, Schlüter PHP Extension Writing 55

  37. 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) ; Börger, Schlüter PHP Extension Writing 56

  38. 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 0 / * Rem ove 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 Börger, Schlüter PHP Extension Writing 57

  39. 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) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 58

  40. Example 5 b � Calling a function for each element / * {{{ 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; } } / * }}} */ Börger, Schlüter PHP Extension Writing 59

  41. Part II PHP Lifecycle � The PHP Lifecycle � Memory Allocation and Garbage Collection � Globals � Constants Börger, Schlüter PHP Extension Writing 60

  42. 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 Börger, Schlüter PHP Extension Writing 61

  43. 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 Börger, Schlüter PHP Extension Writing 62

  44. RUNTIME � Actual execution of scripts happens here. � Compile and execute auto_prepend_file. � Compile and execute main_file. � Compile and execute auto_append_file. Börger, Schlüter PHP Extension Writing 63

  45. DEACTIVATION � Upon exit(), die(), E_ERROR, or 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. Börger, Schlüter PHP Extension Writing 64

  46. SHUTDOWN � Final good-night. Called as process space is terminating (apache child termination). � Shutdown (MSHUTDOWN) all modules (rev. startup order) � Shutdown the engine Request n MINIT RINIT RUNTIME RSHUTDOWN RINIT RUNTIME RSHUTDOWN MSHUTDOWN Request 1 Börger, Schlüter PHP Extension Writing 65

  47. 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 ) ; Börger, Schlüter PHP Extension Writing 66

  48. 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); Börger, Schlüter PHP Extension Writing 67

  49. 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 ) ; Börger, Schlüter PHP Extension Writing 68

  50. 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; } } Börger, Schlüter PHP Extension Writing 69

  51. Global struct in .h � Provide a structure and access macros 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 Börger, Schlüter PHP Extension Writing 70

  52. 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) 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 */ } Börger, Schlüter PHP Extension Writing 71

  53. 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; } Börger, Schlüter PHP Extension Writing 72

  54. 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; } Börger, Schlüter PHP Extension Writing 73

  55. 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; } Börger, Schlüter PHP Extension Writing 74

  56. 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( ) ; } } Börger, Schlüter PHP Extension Writing 75

  57. 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) Börger, Schlüter PHP Extension Writing 76

  58. 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; } Börger, Schlüter PHP Extension Writing 77

  59. MINFO � Provide some information about your extension � MINFO has no return value 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( ) ; } Börger, Schlüter PHP Extension Writing 78

  60. What else ? � INI Handling � Dealing with resources and streams � Object support Börger, Schlüter PHP Extension Writing 79

  61. Part III Adding objects � How to create your own classes � How to create interfaces � How to create methods � What can be overloaded Börger, Schlüter PHP Extension Writing 80

  62. What is needed? � Providing methods � Providing a zend_class_entry pointer � Providing object handlers � Registering the class Börger, Schlüter PHP Extension Writing 81

  63. General class layout zend_object_store_get() zval objects ref_count is_ref handle handlers tables zvals zend_object_handlers object_handlers() zend_class_entry Börger, Schlüter PHP Extension Writing 82

  64. General class layout PHP_METHOD zend_class_entry function_table zend_object_handlers iterator_funcs create_object() get_iterator() interface_gets_implemented() int (*serialize)(…) int (*unserialize)(…) zend_object_iterator // function caches Börger, Schlüter PHP Extension Writing 83

  65. 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 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; } / * }}} */ Börger, Schlüter PHP Extension Writing 84

  66. Declaring class constants � You can register class constants � Use target zend_class_entry pointer � Use sizeof() not strlen() for const name 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) ; Börger, Schlüter PHP Extension Writing 85

  67. Declaring methods / * 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 or 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} }; Börger, Schlüter PHP Extension Writing 86

  68. 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 / * 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 { Inherit zend_object by placing it as z e nd_obj e c t s t d; first member of your object struct 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 ; Börger, Schlüter PHP Extension Writing 87

  69. 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 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 ; } Börger, Schlüter PHP Extension Writing 88

  70. Object destruction � Free properties � Free all resources and free all allocated mem ory � Free mem ory for object itself / * {{{ 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 or 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 ) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 89

  71. A simple method � Macro getThis() gives you access to $this as zval � The returned zval is used to get your struct / * {{{ 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; } } / * }}} */ Börger, Schlüter PHP Extension Writing 90

  72. 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. / * {{{ 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) ; } } / * }}} */ Börger, Schlüter PHP Extension Writing 91

  73. 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 / * {{{ 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) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 92

  74. Object casting / * {{{ */ 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; } / * }}} */ Börger, Schlüter PHP Extension Writing 93

  75. Other handlers to overload � Objects can overload several handlers � Array access � Property access � Serializing Börger, Schlüter PHP Extension Writing 94

  76. zend_object_handlers 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 ; Don't touch these 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; Keep or 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; inherit 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 ; Börger, Schlüter PHP Extension Writing 95

  77. What else ? � Iterator support Börger, Schlüter PHP Extension Writing 96

  78. Part IV Adding Iterators to objects � Provide an iterator structure � Provide the handlers � Provide an iterator creation function Börger, Schlüter PHP Extension Writing 97

  79. Iterators / * 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 ove _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 ove _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 */ }; / * }}} */ Börger, Schlüter PHP Extension Writing 98

  80. Creating the iterator � Allocate and initialize the iterator structure � It is a good idea to increase the original zvals refcount / * {{{ 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 ; } / * }}} */ Börger, Schlüter PHP Extension Writing 99

  81. Destructing the iterator � Free allocated memory and resources � Don't forget to reduce refcount of referenced object / * {{{ 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 ) ; } / * }}} */ Börger, Schlüter PHP Extension Writing 100

Recommend


More recommend