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

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend