SlideShare uma empresa Scribd logo
1 de 105
PHP Extension writing

             Marcus Börger
              Wez Furlong
             Sara Golemon


OSCON 2007
Creating PHP 5 Extension

    PHP Lifecycle

    Adding objects

    Adding iterators to objects





                       PHP Extension Writing   2
How the slides work
    Upper part contains some helpful hints

    Lower part shows c code on blue background



    Text in yellow   Text you should use as presented

    Text in green    Text that you have to replace

    yourext          Extension name in lowercase
    YOUREXT          Extension name in uppercase
    YourExt          Extension name in mixed case (camelCaps)


                     Some special explanation
                       use red text boxes


                            PHP Extension Writing               3
Part I
    Creating PHP 5 Extensions

    How PHP handles data


    How to create your own extension skeleton


    How to create your own functions


    How to work with arrays and hash tables



                      PHP Extension Writing     4
In PHP all values are zval's
typedef struct _zval_struct {
        zvalue_value value;
        zend_uint refcount;
        zend_uchar type;
        zend_uchar is_ref;
} zval;
                                               typedef union _zvalue_value {
                                                      long lval;
                                                      double dval;
                                                      struct {
   IS_NULL
                                                               char *val;
   IS_LONG
                                                               int len;
   IS_DOUBLE
                                                      } str;
   IS_BOOL
                                                      HashTable *ht;
   IS_ARRAY
                                                      zend_object_value obj;
   IS_OBJECT
                                               } zvalue_value;
   IS_STRING
   IS_RESOURCE



                                PHP Extension Writing                          5
In PHP all values are zval's
typedef struct _zval_struct {                Userspace notion of quot;Referencequot;
        zvalue_value value;
                                                  0 == Not a reference
        zend_uint refcount;
        zend_uchar type;                          1 == Is a reference
        zend_uchar is_ref;
} zval;


   How many quot;labelsquot; are
   associated with this zval?




                                PHP Extension Writing                          6
Copy On Write
            typedef struct _zval_struct {                • Has a value of 0 (zero)
                    zvalue_value value;
                                                         • zval shared by 1 or more labels
                    zend_uint refcount;
                    zend_uchar type;                     • If one label wants to make a
                    zend_uchar is_ref;                   change, it must leave other
            } zval;                                      labels with the original value.



                          $a           $b
$a = 123;
$b = $a;
                    value.lval = 123
$b = 456;           refcount = 2
                    type = IS_LONG
                    is_ref = 0


                                            PHP Extension Writing                            7
Copy On Write
            typedef struct _zval_struct {                • Has a value of 0 (zero)
                    zvalue_value value;
                                                         • zval shared by 1 or more labels
                    zend_uint refcount;
                    zend_uchar type;                     • If one label wants to make a
                    zend_uchar is_ref;                   change, it must leave other
            } zval;                                      labels with the original value.



                                 $a                                        $b
$a = 123;
$b = $a;
                    value.lval = 123                          value.lval = 456
$b = 456;           refcount = 1                              refcount = 1
                    type = IS_LONG                            type = IS_LONG
                    is_ref = 0                                is_ref = 0


                                            PHP Extension Writing                            8
Full Reference
            typedef struct _zval_struct {                • Has a value of 1 (one)
                    zvalue_value value;
                                                         • zval shared by 1 or more labels
                    zend_uint refcount;
                    zend_uchar type;                     • If one label wants to make a
                    zend_uchar is_ref;                   change, it does so, causing other
            } zval;                                      labels to see the new value.



                          $a           $b
$a = 123;
$b = &$a;
                    value.lval = 123
$b = 456;           refcount = 2
                    type = IS_LONG
                    is_ref = 1


                                            PHP Extension Writing                            9
Full Reference
            typedef struct _zval_struct {                • Has a value of 1 (one)
                    zvalue_value value;
                                                         • zval shared by 1 or more labels
                    zend_uint refcount;
                    zend_uchar type;                     • If one label wants to make a
                    zend_uchar is_ref;                   change, it does so, causing other
            } zval;                                      labels to see the new value.



                          $a           $b
$a = 123;
$b = &$a;
                    value.lval = 456
$b = 456;           refcount = 2
                    type = IS_LONG
                    is_ref = 1


                                            PHP Extension Writing                            10
Creating PHP 5 Extensions
    Most PHP 4 exts will build in PHP5 w/o Changes

    ext_skel can be used to generate a basic skeleton

    marcus@zaphod src/php5/ext $ ./ext_skel --extname=util
    Creating directory util
    Creating basic files: config.m4 .cvsignore util.c php_util.h CREDITS
    EXPERIMENTAL tests/001.phpt util.php [done].

    To use your new extension, you will have to execute the following steps:

    1.   $   cd ..                                Necessary for non cvs source
    2.   $   vi ext/util/config.m4
                                                    (e.g. release packages)
    3.   $   ./buildconf --force
    4.   $   ./configure --[with|enable]-util
    5.   $   make
    6.   $   ./php -f ext/util/util.php
    7.   $   vi ext/util/util.c
    8.   $   make

    Repeat steps 3-6 until you are satisfied with ext/util/config.m4 and
    step 6 confirms that your module is compiled into PHP. Then, start
    writing code and repeat the last two steps as often as necessary.

                                  PHP Extension Writing                          11
Files in your extension
    You need at least two code files

      php_yourext.h    The header needed by php
      php_yourext.c    The main extension code
                        ('php_' prefix for .c is not necessary)
    You need two configuration files

      config.m4        Used under *nix
      config.w32       Used under windows
    Optional files

         .cvsignore     List of files to be ignored by CVS
     
         CREDITS        First line ext name 2nd line all authors
     
         EXPERIMENTAL   If available the API is not yet stable
     
         package2.xml   Required for PECL extensions
     
         README         Probably good to provide some lines
     


                         PHP Extension Writing                    12
config.m4
    PHP Dev is picky about coding style

       Read CODING_STANDARDS in php­src
       Watch your whitespace
       Align your PHP_ARG_ENABLE output
    Make your extension default disabled

       'phpize' or 'pear install' will enable it automatically

    dnl $Id: $
    dnl config.m4 for extension YOUREXT
    PHP_ARG_ENABLE(yourext, enable YourExt suppport,
                                Enable YourExt], no)
     [ --enable-yourext
    if test quot;$PHP_YOUREXTquot; != quot;noquot;; then
     AC_DEFINE(HAVE_YOUREXT, 1,[Whether YourExt is present])
     PHP_NEW_EXTENSION(yourext, php_yourext.c, $ext_shared)
    fi



                              PHP Extension Writing               13
config.m4
    You can prevent the ext from becoming shared





    dnl $Id: $
    dnl config.m4 for extension YOUREXT
    PHP_ARG_ENABLE(yourext, enable YourExt suppport,
                                 Enable YourExt], no)
     [ --enable-yourext
    if test quot;$PHP_YOUREXTquot; != quot;noquot;;then
     if test quot;$ext_sharedquot; = quot;yesquot;; then
       AC_MSG_ERROR(Cannot build YOUREXT as a shared module)
     fi
     AC_DEFINE(HAVE_YOUREXT,1,[Whether YourExt is present])
     PHP_NEW_EXTENSION(yourext, php_yourext.c, $ext_shared)
    fi
                         PHP Extension Writing             14
config.w32
    Windows configuration uses JScript


    // $Id: $
    // vim:ft=javascript
    ARG_ENABLE(quot;yourextquot;, quot;YourExt supportquot;, quot;yesquot;);

    if (PHP_YOUREXT == quot;yesquot;) {

        if (PHP_YOUREXT_SHARED) {
          ERROR(quot;YOUREXT cannot be compiled as a shared extquot;);
        }

        AC_DEFINE(quot;HAVE_YOUREXTquot;, 1, quot;YourExt supportquot;);
        EXTENSION(quot;yourextquot;, quot;php_yourext.cquot;);
    }



                            PHP Extension Writing                15
Extension .h file
    Declares data for static linking and 

    symbol exports

    /* License, Author, CVS-Tag, Etc... */

    #ifndef PHP_YOUREXT_H
    #define PHP_YOUREXT_H
    #include quot;php.hquot;

    extern zend_module_entry yourext_module_entry;
    #define phpext_yourext_ptr &yourext_module_entry

    /* Only needed if you'll be exporting symbols */
    #ifdef PHP_WIN32
    # define YOUREXT_API __declspec(dllexport)
    #else
    # define YOUREXT_API
    #endif

    /* Place for globals definition */
    #endif /* PHP_YOUREXT_H */


                                 PHP Extension Writing   16
Layout of the .c file
    Header: License, Authors, CVS­Tag, ...

    Includes

    Structures and defines not in header

    Helper Functions

    PHP Functions

    Globals Handling

    MINFO

    MINIT, MSHUTDOWN

    RINIT, RSHUTDOWN

    Function table

    Module Entry



                      PHP Extension Writing   17
Includes
    Include path: 

         <PHP Root>/
     
         <PHP Root>/Zend
     
         <PHP Root>/main
     
         <PHP Root>/ext/<Your Extension>
     

    #ifdef HAVE_CONFIG_H
    #include quot;config.hquot;
    #endif

    #include   quot;php.hquot;
    #include   quot;php_ini.hquot;
    #include   quot;ext/standard/info.hquot;
    #include   quot;ext/standard/php_string.hquot;
    #include   quot;php_yourext.hquot;



                           PHP Extension Writing   18
Structures and defines 
               not in header
    What ever you want

       Local storage structures?
       Constants?
       Macros?
    typedef struct _php_yourext_data {
         int type;

        char *name;
        int name_len;

         php_stream *stream;
    } php_yourext_data;

    #define PHP_YOUREXT_MEANING             42
    #define PHP_YOUREXT_COLOR               quot;purplequot;

    #define PHP_YOUREXT_STRLEN(v)           (v ? strlen(v) : 0)
                          PHP Extension Writing                   19
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




                             PHP Extension Writing          20
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



    static void my_helper(TSRMLS_D);

    static void some_function(TSRMLS_D) {
          my_helper(TSRMLS_C);
    }




                               PHP Extension Writing     21
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


    static void my_helper(void * p TSRMLS_DC);

    static void some_function(void * p TSRMLS_DC) {
          my_helper(p TSRMLS_CC);
    }




                               PHP Extension Writing                   22
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

    static void my_helper(char *p, int p_len TSRMLS_DC);

    static void some_function(char *p) {
          int p_len;
          TSRMLS_FETCH();

          p_len = strlen(p);
          my_helper(p, p_len TSRMLS_CC);
    }




                                PHP Extension Writing                    23
Module Entry
    Keeps everything together

    Tells PHP how to (de)initialize the extension

    zend_module_entry yourext_module_entry = { /* {{{ */
         STANDARD_MODULE_HEADER,
         quot;YourExtquot;,
        yourext_functions,
         PHP_MINIT(yourext),
         PHP_MSHUTDOWN(yourext),
         PHP_RINIT(yourext),
         PHP_RSHUTDOWN(yourext),
                                                 or NULL
         PHP_MINFO(yourext),
         quot;0.1quot;,
         STANDARD_MODULE_PROPERTIES
    }; /* }}} */

    #if COMPILE_DL_YOUREXT
    ZEND_GET_MODULE(yourext)
    #endif
                         PHP Extension Writing             24
Function List
    Exports your functions to userspace

      Must be terminated by NULL tripplet
    zend_function_entry yourext_functions[] = { /* {{{ */
                                     yourext_args_func1)
         PHP_FE(yourext_func1,
         PHP_FE(yourext_func2,                      NULL)
                                     yourext_func2, NULL)
         PHP_FALIAS(yourext_func3,
         PHP_NAMED_FE(yourext_func4, _yourext_func4_impl,
                                                    NULL)
         {NULL, NULL, NULL}
    };




                         PHP Extension Writing              25
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
    static ZEND_BEGIN_ARG_INFO_EX(yourext_args_func1,0,0,2)
         ZEND_ARG_INFO(0, param_name1)
         ZEND_ARG_ARRAY_INFO(1, param_name2)
    ZEND_END_ARG_INFO();
                         PHP Extension Writing                26
PHP Functions
    Namespace your functions with your ext's name

    Documentation is your friend

       Avoid // style C++ comments
       Avoid declarations inline with code
    /* {{{ proto type yourext_name(params)
     Short description */
    PHP_FUNCTION(yourext_name)
    {
        /* Local declarations */

        /* Parameter parsing */

        /* Actual code */

        /* Return value */
    }
    /* }}} */
                            PHP Extension Writing   27
Outputting Content
    Do not send content to stdout

    use PHP's output buffering mechanisms

      php_printf() works just like printf()
      PHPWRITE() respects binary safety

    /* {{{ proto null yourext_hello_world()
      Say Hello */
    PHP_FUNCTION(yourext_hello_world)
    {
         char *greeting = quot;Hello Worldquot;;

        php_printf(quot;%s!nquot;, greeting);

        PHPWRITE(greeting, strlen(greeting));
        php_printf(quot;!nquot;);
    }
    /* }}} */

                           PHP Extension Writing   28
Parsing parameters
    zend_parse_parameters is the easy way of parsing


    int zend_parse_parameters(
         int num_args TSRMLS_DC, char *type_spec, ...);

    int zend_parse_parameters_ex(int flags,
         int num_args TSRMLS_DC, char *type_spec, ...);

    flags       0 or ZEND_PARSE_PARAMS_QUIET
    num_args    use ZEND_NUM_ARGS()
    type_spec   sscanf like typelist (though no %)
    ...         References to the types given in type_spec
    returns     SUCCESS or FAILURE
                in case of failure an error is already issued
                so no need for ZEND_WRONG_PARAM_COUNT()
                unless using ZEND_PARSE_PARAMS_QUIET
                         PHP Extension Writing             29
Parsing parameters
type_spec   sscanf like typelist (though no %)
     l      long      long *
     d      double    double *
     b      boolean   zend_bool *
     a      array     zval **
     o      object    zval **
     O      object    zval **, zend_class_entry *
              Object must be derived from given class
    s       string    char **, int *
              You receive string and length
    r       resource zval **
    z       zval      zval **
    Z       zval-ref zval ***

    |       right part is optional
    /       next param gets separated if not reference
    !       Next param returns NULL if param type IS_NULL
                     PHP Extension Writing              30
Parsing Parameters

/* {{{ proto null yourext_hello(string name)
  Greet by name */
PHP_FUNCTION(yourext_hello)
{
     char *name;
     int name_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), quot;squot;,
                     &name, &name_len) == FAILURE) {
           return;
    }

    php_printf(quot;Hello %s!nquot;, name);
}
/* }}} */


                     PHP Extension Writing             31
Returning Values
    Marking success

    /* {{{ proto bool yourext_hello(string name)
      Greet by name */
    PHP_FUNCTION(yourext_hello)
    {
        char *name;
        int name_len;

       if (zend_parse_parameters(ZEND_NUM_ARGS(), quot;squot;,
               &name, &name_len) == FAILURE) {
           return;
                               Makes the return
       }
                                 value NULL
       php_printf(quot;Hello %s!nquot;, name);

       RETURN_TRUE;
    }
    /* }}} */
                         PHP Extension Writing           32
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: Integer value
    RETURN_DOUBLE(d);          d: Floating point value



                        PHP Extension Writing                 33
Returning Values
    Strings are slightly more complex

    The string value must quot;belongquot; to the engine

      Will not survive the destruction of the zval
      Will be freed using efree()
    Pass 0 (zero) for dup to give it the string

    Pass 1 (one) for dup to make a copy (duplicate)



    RETURN_STRING(str, dup)     str: char* string value
                                dup: 0/1 flag, duplicate string?
    RETURN_STRINGL(str, len, dup)
                                len: Predetermined string length

    RETURN_STRING(quot;Hello Worldquot;, 1);
    RETURN_STRING(estrdup(quot;Hello Worldquot;), 0);
    RETURN_EMPTY_STRING();

                           PHP Extension Writing              34
Setting Returning Values
    RETURN_*() macros automatically exit function

    RETVAL_*() family work the same without exiting




    #define   RETURN_NULL()        {   RETVAL_NULL();      return;   }
    #define   RETURN_TRUE          {   RETVAL_TRUE;        return;   }
    #define   RETURN_FALSE         {   RETVAL_FALSE;       return;   }
    #define   RETURN_BOOL(b)       {   RETVAL_BOOL(b);     return;   }
    #define   RETURN_LONG(l)       {   RETVAL_LONG(l);     return;   }
    #define   RETURN_DOUBLE(d)     {   RETVAL_DOUBLE(d);   return;   }

    #define RETURN_STRING(str, dup)                 
            { RETVAL_STRING(str, dup);                     return; }
    #define RETURN_STRINGL(str, len, dup)           
            { RETVAL_STRINGL(str, len, dup);               return; }
    #define RETURN_EMPTY_STRING()                   
            { RETVAL_EMPTY_STRING();                       return; }

                            PHP Extension Writing                        35
Setting Returning Values
    RETURN_*() macros automatically exit function

    RETVAL_*() family work the same without exiting

    ZVAL_*() family also work the same


    #define   RETVAL_NULL()        ZVAL_NULL(return_value)
    #define   RETVAL_TRUE          ZVAL_TRUE(return_value)
    #define   RETVAL_FALSE         ZVAL_FALSE(return_value)
    #define   RETVAL_BOOL(b)       ZVAL_BOOL(return_value, b)
    #define   RETVAL_LONG(l)       ZVAL_LONG(return_value, l)
    #define   RETVAL_DOUBLE(d)     ZVAL_DOUBLE(return_value, d)

    #define RETVAL_STRING(str, dup)           
            ZVAL_STRING(return_value, str, dup)
    #define RETVAL_STRINGL(str, len, dup)     
            ZVAL_STRINGL(return_value, str, len, dup)
    #define RETVAL_EMPTY_STRING()             
            ZVAL_EMPTY_STRING(return_value)

                            PHP Extension Writing                 36
Example 1
    Inverting a single boolean parameter

    /* {{{ proto bool yourext_invert(bool b)
     Invert a boolean parameter */
    PHP_FUNCTION(yourext_invert)
    {
        zend_bool b;

       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
               quot;bquot;, &b) == FAILURE) {
           return;
       }

       b = b ? 0 : 1;

       RETURN_BOOL(b);
    }
    /* }}} */

                         PHP Extension Writing            37
Example 2
    Incrementing a value with an optional maximum

    /* {{{ proto bool yourext_increment(int v [, int max])
     Increment a value with optional maximum */
    PHP_FUNCTION(yourext_increment)
                                     Initialize Use brackets
    {
                                     optional    for optional
        long n, nmax = LONG_MAX;
                                      values        values
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                quot;l|lquot;, &n, &nmax) == FAILURE) {
            RETURN_FALSE();
        }
                                     A vertical bar separates
                                      optional and required
        n = (n+1) % nmax;
                                            parameters
        RETURN_LONG(n);
    }
    /* }}} */

                          PHP Extension Writing                 38
Example 3
    Returning some generated string

    #define YOUREXT_VERSION_MAJOR              0
    #define YOUREXT_VERSION_MINOR              1

    /* {{{ proto string yourext_version()
     Retrieve yourext version */
    PHP_FUNCTION(yourext_version)
    {
                                    Never use sprintf,
        char * ver;
                               use either snprintf or spprintf
        int len;

        len = spprintf(&ver, 0, quot;%d.%d (%s)quot;,
             YOUREXT_VERSION_MAJOR, YOUREXT_VERSION_MINOR,
             quot;$Id: $quot;);

        RETURN_STRINGL(ver, len, 0);
                                                       No need to
    }
                                                     copy the string
    /* }}} */
                             PHP Extension Writing                     39
Dealing with arrays
    To initialize a zval as an array: array_init(pzv)

       To return an array use: array_init(return_value)
    To add elements use the following

       add_assoc_<type>(ar, key, ...)
       add_assoc_<type>_ex(ar, key, key_len, ...)


    int add_assoc_long(zval *arg, char *key, long n);
    int add_assoc_null(zval *arg, char *key);
    int add_assoc_bool(zval *arg, char *key, int b);
    int add_assoc_resource(zval *arg, char *key, int r);
    int add_assoc_double(zval *arg, char *key, double d);
    int add_assoc_string(zval *arg, char *key, char *str,
                               int dup);
    int add_assoc_stringl(zval *arg, char *key, char *str,
                               uint len, int dup);
    int add_assoc_zval(zval *arg, char *key, zval *value);
                         PHP Extension Writing               40
Dealing with arrays
    To convert a zval into an array: array_init(pzv)

       To return an array use: array_init(return_value)
    To add elements use the following

       add_assoc_<type>(ar, key, ...)
       add_index_<type>(ar, index, ...)


    int add_index_long(zval *arg, uint idx, long n);
    int add_index_null(zval *arg, uint idx);
    int add_index_bool(zval *arg, uint idx, int b);
    int add_index_resource(zval *arg, uint idx, int r);
    int add_index_double(zval *arg, uint idx, double d);
    int add_index_string(zval *arg, uint idx, char *str,
                               int duplicate);
    int add_index_stringl(zval *arg, uint idx, char *str,
                               uint length, int duplicate);
    int add_index_zval(zval *arg, uint idx, zval *value);
                         PHP Extension Writing                41
Dealing with arrays
    To convert a zval into an array: array_init(pzv)

       To return an array use: array_init(return_value)
    To add elements use the following

       add_assoc_<type>(ar, key, ...)
       add_index_<type>(ar, index, ...)
       add_next_index_<type>(ar, ...)
    int add_next_index_long(zval *arg, long n);
    int add_next_index_null(zval *arg);
    int add_next_index_bool(zval *arg, int b);
    int add_next_index_resource(zval *arg, int r);
    int add_next_index_double(zval *arg, double d);
    int add_next_index_string(zval *arg, char *str,
                               int duplicate);
    int add_next_index_stringl(zval *arg, char *str,
                               uint length, int duplicate);
    int add_next_index_zval(zval *arg, zval *value);
                         PHP Extension Writing                42
Example 4
    Returning an array

    /* {{{ proto array yourext_version_array()
     Retrieve yourext version as array */
    PHP_FUNCTION(yourext_version_array)
    {
        char *ver;
        int len = spprintf(&ver, 0, quot;%d.%dquot;,
           YOUREXT_VERSION_MAJOR, YOUREXT_VERSION_MINOR);
                                     make return_value an array
       array_init(return_value);
       add_assoc_long(return_value, quot;majorquot;,
           YOUREXT_VERSION_MAJOR);
       add_assoc_long(return_value, quot;minorquot;,
           YOUREXT_VERISON_MINOR);
       add_assoc_string(return_value, quot;cvsquot;, quot;$Id: $quot;, 1);
       add_assoc_stringl(return_value, quot;verquot;, ver, len, 0);
    }
    /* }}} */
                          PHP Extension Writing                   43
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.



    /* arKey hashed using DJBX33A */
    ulong zend_get_hash_value(char *arKey, uint nKeyLength);

    /* count($ht) */
    int zend_hash_num_elements(HashTable *ht);

    /* Removes all elements from the HashTable */
    int zend_hash_clean(HashTable *ht);



                         PHP Extension Writing            44
Adding to HashTables
    add_assoc/index_*() functions wrap 

    zend_symtable_update()
    Symbol table keys include terminating NULL byte

    sizeof(key) vs. strlen(key)



    add_assoc_zval(arr, quot;fooquot;, val);
    add_assoc_zval_ex(arr, quot;fooquot;, sizeof(quot;fooquot;), val);

    zend_symtable_update(Z_ARRVAL_P(arr),
                        quot;fooquot;, sizeof(quot;fooquot;),
                        &val, sizeof(zval*), NULL);




                           PHP Extension Writing         45
Deleting from HashTables
    You can delete elements (SUCCESS/FAILURE)

       by key
       by hash index
       by symbol



    int zend_hash_del(HashTable *ht, char *arKey,
        uint nKeyLen);

    int zend_hash_index_del(HashTable *ht, ulong h);

    int zend_symtable_del(HashTable *ht, char *arKey,
        uint nKeyLength);




                         PHP Extension Writing          46
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
      

    int zend_hash_exists(HashTable *ht, char *arKey,
        uint nKeyLength);

    int zend_hash_quick_exists(HashTable *ht, char *arKey,
        uint nKeyLength, ulong h);

    int zend_hash_index_exists(HashTable *ht, ulong h);

    int zend_symtable_exists(HashTable *ht, char *arKey,
        uint nKeyLength);

                           PHP Extension Writing              47
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
      

    int zend_hash_find(HashTable *ht,
        char *arKey, uint nKeyLength, void **pData);

    int zend_hash_quick_find(HashTable *ht, char *arKey,
        uint nKeyLength, ulong h, void **pData);

    int zend_hash_index_find(HashTable *ht,
        ulong h, void **pData);

    int zend_symtable_find(HashTable *ht,
        char *arKey, uint nKeyLength, void **pData);
                           PHP Extension Writing              48
Searching HashTables
    Symbol Tables store zval* pointers

    When fetching, a reference to a zval** is passed





    zval **tmp;

    if (zend_symtable_find(ht, quot;keyquot;, sizeof(quot;keyquot;),
                               (void**)&tmp) == SUCCESS) {

        /* Do something with tmp */
        if (Z_TYPE_PP(tmp) == IS_STRING) {
            PHPWRITE(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
        }
    }

                         PHP Extension Writing               49
Accessing a zval
Z_LVAL(zval)               long                    value
Z_BVAL(zval)               zend_bool               value
Z_DVAL(zval)               double                  value
Z_STRVAL(zval)             char*                   value
Z_STRLEN(zval)             int                     length
Z_ARRVAL(zval)             HashTable*              only array
Z_OBJ_HANDLE(zval)         int                     obj id
Z_OBJ_HT(zval)             zend_object_handlers*   obj handlers
Z_OBJCE(zval)              zend_class_entry*       obj class
Z_OBJPROP(zval)            HashTable*              properties
Z_OBJ_HANDLER(zval,hf)     Z_OBJ_HT((zval))->hf    obj handler
Z_RESVAL(zval)             int                     resource id

Z_TYPE(zval)               int                     IS_*

HASH_OF(zval)              HashTable*              array+props

Z_*_P(zp)                  Z_*(*zp)
Z_*_PP(zpp)                Z_*(**zpp)


                         PHP Extension Writing               50
Dealing with a HashTable
    Hash tables have builtin quot;foreachquot; functions





    /* array_walk($ht, $apply_func) */
    void zend_hash_apply(HashTable *ht,
            apply_func_t apply_func TSRMLS_DC);

    /* array_walk($ht, $apply_func, $data) */
    void zend_hash_apply_with_argument(HashTable *ht,
            apply_func_arg_t apply_func, void * TSRMLS_DC);

    /* Multiple argument version,
     * This is also the only variant which provides
     * the key to the callback */
    void zend_hash_apply_with_arguments(HashTable *ht,
            apply_func_args_t apply_func, int, ...);
                          PHP Extension Writing               51
Dealing with a HashTable
    Hash tables have builtin quot;foreachquot; functions

    Each function requires a different type of callback




    /* pDest contains a pointer to
     * what's stored in the HashTable
     * Since there is a zval* in SymbolTables
     * we wind up with a zval** being passed as pDest*
    typedef int (*apply_func_t)(void *pDest TSRMLS_DC);

    typedef int (*apply_func_arg_t)(void *pDest,
                void *argument TSRMLS_DC);

    typedef int (*apply_func_args_t)(void *pDest,
                int num_args,           va_list args,
                zend_hash_key *hash_key);

                          PHP Extension Writing           52
Dealing with a HashTable
    Hash tables have builtin quot;foreachquot; 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

    /* Continue itterating the HashTable */
    #define ZEND_HASH_APPLY_KEEP            0

    /* Remove this element, but continue processing */
    #define ZEND_HASH_APPLY_REMOVE           1<<0

    /* Terminate the loop (break;) */
    #define ZEND_HASH_APPLY_STOP                     1<<1




                             PHP Extension Writing                     53
Example 5 a
    Using zend_hash_apply_with_arguments()

    /* {{{ proto void yourext_foreach( array names,
                                       string greeting)
    Say hello to each person */
    PHP_FUNCTION(yourext_foreach)
    {
       zval *names;
       char *greet;
       int greet_len;

      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
           quot;asquot;, &names, &greet, &greet_len) == FAILURE) {
           return;
      }

       zend_hash_apply_with_argument(Z_ARRVAL_P(names),
            (apply_func_arg_t)yourext_foreach, greet TSRMLS_CC);
    } /* }}} */

                          PHP Extension Writing              54
Example 5 b
    Calling a function for each element


    /* {{{ yourext_foreach
      Callback for outputting a greeting
      for each name in a user-provided array */
    int yourext_foreach(zval **param, char *greeting TSRMLS_DC)
    {
        if (Z_TYPE_PP(param) == IS_STRING) {
            php_printf(quot;%s %snquot;, greeting, Z_STRVAL_PP(param));

            return ZEND_HASH_APPLY_KEEP;
        } else {
            php_error_docref(NULL TSRMLS_CC, E_WARNING,
                 quot;Non-string value passed in $names arrayquot;);

            return ZEND_HASH_APPLY_STOP;
        }
    } /* }}} */

                          PHP Extension Writing                55
Part II
                PHP Lifecycle

    The PHP Lifecycle


    Memory Allocation and Garbage Collection


    Globals


    Constants



                        PHP Extension Writing   56
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





                           PHP Extension Writing   57
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





                       PHP Extension Writing       58
RUNTIME
    Actual execution of scripts happens here.


    Compile and execute auto_prepend_file.


    Compile and execute main_file.


    Compile and execute auto_append_file.





                       PHP Extension Writing    59
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.



                            PHP Extension Writing   60
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       RSHUTDO                   RINIT   RUNTIME       RSHUTDO
                          WN                                              WN
                                                                      MSHUTDO
          Request 1
                                                                         WN
                                PHP Extension Writing                           61
Memory Allocation
    Traditionall malloc() family may be used





    void   *    malloc(size_t size);
    void   *    calloc(size_t nmemb, size_t size);
    void   *    realloc(void *ptr, size_t size);
    void   *    strdup(char *str);
    void   *    strndup(char *str, size_t len);
    void       free(void *ptr);




                              PHP Extension Writing   62
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



    void   * emalloc(size_t size);
    void   * ecalloc(size_t nmemb, size_t size);
    void   * erealloc(void *ptr, size_t size);
    void   * estrdup(char *str);
    void   * estrndup(char *str, size_t len);
    void    efree(void *ptr);

    void *safe_emalloc(size_t nmemb, size_t size,
                          size_t adtl);
    void *STR_EMPTY_ALLOC(void);


                            PHP Extension Writing          63
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

    void   *pemalloc(size_t size, int persist);
    void   *pecalloc(size_t nmemb, size_t size, int persist);
    void   *perealloc(void *ptr, size_t size, int persist);
    void   *pestrdup(char *str, int persist);

    void pefree(void *ptr, int persist);

    void *safe_pemalloc(size_t nmemb, size_t size,
                         size_t addtl, int persist);



                            PHP Extension Writing               64
Storing Global Values
    Do NOT store transient data in the global scope!

         Threaded SAPIs will break



    static char *errormsg = NULL;

    PHP_FUNCTION(yourext_unthreadsafe) {
        long ret;

          ret = do_something(quot;valuequot;, &errormsg);
          if (errormsg) {
              php_error_docref(NULL TSRMLS_CC, E_WARNING,
                  quot;do_something() failed with: %squot;, errormsg);
              free(errormsg);
              errormsg = NULL;
          }
    }
                            PHP Extension Writing            65
Global struct in .h
    Provide a structure and access macros




    ZEND_BEGIN_MODULE_GLOBALS(yourext)
        char        *str;
        int          strlen;
        long         counter;
    ZEND_END_MODULE_GLOBALS(yourext)
    #ifdef ZTS
    # define YOUREXT_G(v) 
        TSRMG(yourext_globals_id, zend_yourext_globals*, v)
    extern int yourext_globals_id;
    #else
    # define YOUREXT_G(v) (yourext_globals.v)
    extern zend_yourext_globals yourext_globals;
    #endif
                         PHP Extension Writing                66
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
    ZEND_DECLARE_MODULE_GLOBALS(yourext)

    static void yourext_globals_ctor(
         zend_yourext_globals *globals) {
          /* Initialize your global struct */
          globals->str     = NULL;
          globals->strlen = 0;
          globals->counter = 0;
    }

    static void yourext_globals_dtor(
         zend_yourext_globals *globals) {
         /* Clean up any allocated globals */
    }
                            PHP Extension Writing       67
MINIT/MSHUTDOWN
    Allocate local storage for globals in ZTS mode

    Call globals initialization and destruction as needed




    PHP_MINIT_FUNCTION(yourext) {
         ZEND_INIT_MODULE_GLOBALS(yourext,
            yourext_globals_ctor, yourext_globals_dtor);
        return SUCCESS;
    }


    PHP_MSHUTDOWN_FUNCTION(yourext) {
    #ifndef ZTS
        yourext_globals_dtor(&yourext_globals TSRMLS_CC);
    #endif
         return SUCCESS;
    }

                           PHP Extension Writing            68
RINIT/RSHUTDOWN
    Initialize request specific settings at RINIT

    Clean up their values at RSHUTDOWN




    PHP_RINIT_FUNCTION(yourext) {
         /* Track number of times this thread/process
          * has serviced requests */
         YOUREXT_G(counter)++;
         return SUCCESS;
    }

    PHP_RSHUTDOWN_FUNCTION(yourext) {
         if (YOUREXT_G(str)) {
            efree(YOUREXT_G(str));
            YOUREXT_G(str) = NULL;
         }
         return SUCCESS;
    }
                            PHP Extension Writing       69
Globals Access
    Access Global values using YOUREXT_G(v) macro





    PHP_FUNCTION(yourext_set_string) {
         char *str;
         int str_len;
         if (zend_parse_parameters(ZEND_NUM_ARGS(), quot;squot;,
                                &str, &str_len) == FAILURE) {
            return;
         }
         if (YOUREXT_G(str)) {
            efree(YOUREXT_G(str));
         }
         YOUREXT_G(str) = estrndup(str, str_len);
         YOUREXT_G(strlen) = str_len;
         RETURN_TRUE;
    }
                          PHP Extension Writing                 70
Globals Access
    Access Global values using YOUREXT_G(v) macro





    PHP_FUNCTION(yourext_get_string) {
       if (YOUREXT_G(str)) {
          RETURN_STRINGL(YOUREXT_G(str), YOUREXT_G(strlen), 1);
       } else {
          RETURN_EMPTY_STRING();
       }
    }




                          PHP Extension Writing               71
Registering consts
    Register constants during MINIT (usually)

      name_len here is sizeof()
      Thus name must be a real string


    int zend_get_constant(char *name, uint name_len,
         zval *result TSRMLS_DC);

    REGISTER_LONG_CONSTANT(name, lval, flags)
    REGISTER_DOUBLE_CONSTANT(name, dval, flags)
    REGISTER_STRING_CONSTANT(name, str, flags)
    REGISTER_STRINGL_CONSTANT(name, str, len, flags)

    int zend_register_constant(zend_constant *c TSRMLS_DC);

    /* Case-sensitive */
    #define CONST_CS              (1<<0)
    /* Persistent */
    #define CONST_PERSISTENT      (1<<1)
                          PHP Extension Writing               72
Registering consts
    Persistent constants require CONST_PERSISTENT

    Non­persistent string constants must be estrdup'd



    PHP_MINIT_FUNCTION(yourext) {
         REGISTER_LONG_CONSTANT(quot;YOUREXT_CONSTNAMEquot;, 42,
                                CONST_CS | CONST_PERSISTENT);
         REGISTER_STRING_CONSTANT(quot;YOUREXT_VERSIONquot;, quot;$ID: $quot;,
                                CONST_CS | CONST_PERSISTENT);
         return SUCCESS;
    }


    PHP_RINIT_FUNCTION(yourext) {
         REGISTER_LONG_CONSTANT(quot;YOUREXT_COUNTERquot;,
                                  YOUREXT_G(counter), CONST_CS);
        return SUCCESS;
    }
                          PHP Extension Writing                    73
MINFO
    Provide some information about your extension

         MINFO has no return value



    PHP_MINFO_FUNCTION(yourext)
    {
       php_info_print_table_start();
       php_info_print_table_header(2, quot;YourExtquot;,quot;enabledquot;);

        php_info_print_table_row(2,
           quot;Versionquot;, quot;$ID: $quot;);

        php_info_print_table_row(2,
           quot;Somestringquot;, YOUREXT_G(str));

        php_info_print_table_end();
    }
                           PHP Extension Writing              74
What else ?
    INI Handling


    Dealing with resources and streams


    Object support





                     PHP Extension Writing   75
Part III
               Adding objects
    How to create your own classes


    How to create interfaces


    How to create methods


    What can be overloaded





                      PHP Extension Writing   76
What is needed?
    Providing methods


    Providing a zend_class_entry pointer


    Providing object handlers


    Registering the class





                        PHP Extension Writing   77
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

                       PHP Extension Writing                     78
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




                         PHP Extension Writing                79
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
      
    zend_class_entry *util_ce_dir;
    PHP_MINIT_FUNCTION(util) /* {{{ */
    {
         zend_class_entry ce;
         INIT_CLASS_ENTRY(ce, quot;dirsquot;, util_dir_class_functions);
         util_ce_dir = zend_register_internal_class(&ce TSRMLS_CC);
         util_ce_dir->create_object = util_dir_object_new;
         memcpy(&util_dir_handlers, zend_get_std_object_handlers(),
              sizeof(zend_object_handlers));
         util_dir_handlers.clone_obj = util_dir_object_clone;
         zend_class_implements(util_ce_dir TSRMLS_CC, 1, zend_ce_iterator);
         util_ce_dir->ce_flags |= ZEND_ACC_FINAL_CLASS;
         util_ce_dir->get_iterator = util_dir_get_iterator;
         return SUCCESS;
    } /* }}} */
                                PHP Extension Writing                       80
Declaring class constants
    You can register class constants

       Use target zend_class_entry pointer
       Use sizeof() not strlen() for const name
    int zend_declare_class_constant(zend_class_entry *ce,
         char *name, size_t name_len, zval *value TSRMLS_DC);

    int zend_declare_class_constant_long(zend_class_entry *ce,
         char *name, size_t name_len, long value TSRMLS_DC);

    int zend_declare_class_constant_bool(zend_class_entry *ce,
         char *name, size_t name_len, zend_bool value TSRMLS_DC);

    int zend_declare_class_constant_double(zend_class_entry *ce,
         char *name, size_t name_len, double value TSRMLS_DC);

    int zend_declare_class_constant_stringl(zend_class_entry *ce,
         char *name, size_t name_len, char *val, size_t val_len TSRMLS_DC);

    int zend_declare_class_constant_string(zend_class_entry *ce,
         char *name, size_t name_len, char *value TSRMLS_DC);


                               PHP Extension Writing                          81
Declaring methods


/* declare method parameters, */
static ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0)
     ZEND_ARG_INFO(0, path) /* parameter name */
ZEND_END_ARG_INFO();

/* each method can have its own parameters and visibility */
static zend_function_entry util_dir_class_functions[] = {
     PHP_ME(dir, __construct, arginfo_dir___construct,
                                    ZEND_ACC_CTOR | ZEND_ACC_PUBLIC)
     PHP_ME(dir, rewind,      NULL, ZEND_ACC_PUBLIC)
     PHP_ME(dir, hasMore,     NULL, ZEND_ACC_PUBLIC)
     PHP_ME(dir, key,         NULL, ZEND_ACC_PUBLIC)
     PHP_ME(dir, current,     NULL, ZEND_ACC_PUBLIC)
     PHP_ME(dir, next,        NULL, ZEND_ACC_PUBLIC)
     PHP_ME(dir, getPath,     NULL, ZEND_ACC_PUBLIC)
     {NULL, NULL, NULL}
};


                           PHP Extension Writing                       82
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
    /* declare the class handlers */
    static zend_object_handlers util_dir_handlers;

    /* decalre the class entry */
    static zend_class_entry *util_ce_dir;

    /* the overloaded class structure */

    /* overloading the structure results in the need of having
       dedicated creatin/cloning/destruction functions */
    typedef struct _util_dir_object {
                                            Inherit zend_object by placing it as
             zend_object       std;
                                             first member of your object struct
             php_stream        *dirp;
             php_stream_dirent entry;
             char              *path;
             int               index;
    } util_dir_object;


                                 PHP Extension Writing                        83
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

    zend_object_value util_dir_object_new(zend_class_entry *ce TSRMLS_DC) {
         zend_object_value retval;
         util_dir_object *intern;

         intern = ecalloc(1, sizeof(util_dir_object));
         zend_object_std_init(&(intern->std), ce TSRMLS_CC);
         zend_hash_copy(intern->std.properties,
              &ce->default_properties, (copy_ctor_func_t) zval_add_ref,
              NULL, sizeof(zval *));

         retval.handle = zend_objects_store_put(intern,
              util_dir_object_dtor, NULL TSRMLS_CC);
         retval.handlers = &util_dir_handlers;
         return retval;
    }

                                 PHP Extension Writing                        84
Object destruction
    Free properties

    Free all resources and free all allocated memory

    Free memory for object itself

    /* {{{ util_dir_object_dtor */
    /* close all resources and the memory allocated for the object */
    static void
    util_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
    {
         util_dir_object *intern = (util_dir_object *)object;

         zend_object_std_dtor(&(intern->std) TSRMLS_CC);

         if (intern->path) {
              efree(intern->path);
         }
         if (intern->dirp) {
              php_stream_close(intern->dirp);
         }

         efree(object);
    } /* }}} */

                               PHP Extension Writing                          85
A simple method
    Macro getThis() gives you access to $this as zval

    The returned zval is used to get your struct





    /* {{{ proto string dir::key()
       Return current dir entry */
    PHP_METHOD(dir, key)
    {
         zval *object = getThis();
         util_dir_object *intern = (util_dir_object*)
              zend_object_store_get_object(object TSRMLS_CC);

         if (intern->dirp) {
              RETURN_LONG(intern->index);
         } else {
              RETURN_FALSE;
         }
    } /* }}} */


                               PHP Extension Writing            86
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.

    /* {{{ proto void dir::__construct(string path)
     Constructs a new dir iterator from a path. */
    PHP_METHOD(dir, __construct)
    {
         util_dir_object *intern;
         char *path;
         int len;




         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, quot;squot;, &path,
                   &len) == SUCCESS) {
              intern = (util_dir_object*)
                   zend_object_store_get_object(getThis() TSRMLS_CC);
              util_dir_open(intern, path TSRMLS_CC);
         }

    } /* }}} */
                               PHP Extension Writing                        87
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

    /* {{{ proto void dir::__construct(string path)
     Constructs a new dir iterator from a path. */
    PHP_METHOD(dir, __construct)
    {
         util_dir_object *intern;
         char *path;
         int len;

         php_set_error_handling(EH_THROW, zend_exception_get_default()
              TSRMLS_CC);

         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, quot;squot;, &path,
                   &len) == SUCCESS) {
              intern = (util_dir_object*)
                   zend_object_store_get_object(getThis() TSRMLS_CC);
              util_dir_open(intern, path TSRMLS_CC);
         }
         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
    } /* }}} */
                                PHP Extension Writing                       88
Object casting

/* {{{ */
static int zend_std_cast_object_tostring(zval *readobj, zval *writeobj,
     int type TSRMLS_DC)
{
     zval *retval == NULL;
     if (type == IS_STRING) {
        zend_call_method_with_0_params(&readobj, NULL, NULL,
            quot;__tostringquot;, &retval);
        if (retval) {
            if (Z_TYPE_P(retval) != IS_STRING) {
               zend_error(E_ERROR, quot;Method %s::__toString() mustquot;
                   quot; return a string valuequot;, Z_OBJCE_P(readobj)->name);
            }
        } else {
            MAKE_STD_ZVAL(retval);
            ZVAL_EMPTY_STRING(retval);
        }
        ZVAL_ZVAL(writeobj, retval, 1, 1);
        INIT_PZVAL(writeobj);
     }
     return retval ? SUCCESS : FAILURE;
} /* }}} */
                            PHP Extension Writing                         89
Other handlers to overload
    Objects can overload several handlers

      Array access
      Property access
      Serializing




                         PHP Extension Writing   90
zend_object_handlers
typedef struct _zend_object_handlers {
     /* general object functions */
     zend_object_add_ref_t                 add_ref;    Don't touch these
     zend_object_del_ref_t                 del_ref;
     zend_object_delete_obj_t              delete_obj;
     /* individual object functions */
     zend_object_clone_obj_t               clone_obj;
     zend_object_read_property_t           read_property;
     zend_object_write_property_t          write_property;
     zend_object_read_dimension_t          read_dimension;
     zend_object_write_dimension_t         write_dimension;
     zend_object_get_property_ptr_ptr_t get_property_ptr_ptr;
     zend_object_get_t                     get;
     zend_object_set_t                     set;
     zend_object_has_property_t            has_property;
                                                               Keep or
     zend_object_unset_property_t          unset_property;
     zend_object_unset_dimension_t         unset_dimension;     inherit
     zend_object_get_properties_t          get_properties;
     zend_object_get_method_t              get_method;
     zend_object_call_method_t             call_method;
     zend_object_get_constructor_t         get_constructor;
     zend_object_get_class_entry_t         get_class_entry;
     zend_object_get_class_name_t          get_class_name;
     zend_object_compare_t                 compare_objects;
     zend_object_cast_t                    cast_object;
     zend_object_count_elements_t          count_elements;
                            PHP Extension Writing                        91
} zend_object_handlers;
What else ?
    Iterator support





                       PHP Extension Writing   92
Part IV
    Adding Iterators to objects
    Provide an iterator structure


    Provide the handlers


    Provide an iterator creator function





                       PHP Extension Writing   93
Iterators
/* define an overloaded iterator structure */
typedef struct {
     zend_object_iterator intern;
     zval                  *current;
} util_dir_it;

static void util_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC);
static int util_dir_it_valid(zend_object_iterator *iter TSRMLS_DC);
static void util_dir_it_current_data(zend_object_iterator *iter,
          zval ***data TSRMLS_DC);
static int util_dir_it_current_key(zend_object_iterator *iter,
          char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
static void util_dir_it_move_forward(zend_object_iterator *iter
          TSRMLS_DC);
static void util_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC);

/* iterator handler table */
zend_object_iterator_funcs util_dir_it_funcs = {
     util_dir_it_dtor,
     util_dir_it_valid,
     util_dir_it_current_data,
     util_dir_it_current_key,
     util_dir_it_move_forward,
     util_dir_it_rewind,
     NULL /* invalidate current */
}; /* }}} */
                           PHP Extension Writing                          94
Creating the iterator
    Allocate and initialize the iterator structure

    It is a good idea to increase the original zvals refcount


    /* {{{ util_dir_get_iterator */
    zend_object_iterator *util_dir_get_iterator(zend_class_entry *ce, zval
    *object TSRMLS_DC)
    {
         util_dir_it *iterator = emalloc(sizeof(util_dir_it));

         object->refcount++;
         iterator->intern.data = (void*)object;
         iterator->intern.funcs = &util_dir_it_funcs;
         iterator->current = NULL;

         return (zend_object_iterator*)iterator;
    } /* }}} */




                               PHP Extension Writing                         95
Destructing the iterator
    Free allocated memory and resources

    Don't forget to reduce refcount of referenced object


    /* {{{ util_dir_it_dtor */
    static void util_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC)
    {
         util_dir_it *iterator = (util_dir_it *)iter;
         zval        *intern = (zval*)iterator->intern.data;

         if (iterator->current) {
              zval_ptr_dtor(&iterator->current);
         }
         zval_ptr_dtor(&intern);

         efree(iterator);
    } /* }}} */




                               PHP Extension Writing                     96
Getting the data
    Data is read on rewind() and next() calls

    A zval* is stored inside the iterator

    Release current zval

    Create a new zval and assign the value



    /* {{{ util_dir_it_current */
    static void
    util_dir_it_current(util_dir_it *iterator, util_dir_object *object
              TSRMLS_DC)
    {
          if (iterator->current) {
              zval_ptr_dtor(&iterator->current);
          }
          MAKE_STD_ZVAL(iterator->current);
          if (object->dirp) {
              ZVAL_STRING(iterator->current, object->entry.d_name, 1);
          } else {
              ZVAL_FALSE(iterator->current);
          }
    } /* }}} */

                               PHP Extension Writing                     97
Iterator valid()
    Check whether more data is available

      Note: Return SUCCESS or FAILURE not typical boolean

    /* {{{ util_dir_it_valid */
    static int
    util_dir_it_valid(zend_object_iterator *iter TSRMLS_DC)
    {
         util_dir_it     *iterator = (util_dir_it *)iter;
         util_dir_object *object = (util_dir_object*)
                             zend_object_store_get_object(
                                  (zval*)iterator->intern.data TSRMLS_CC);

         return object->dirp
              && object->entry.d_name[0] != '0' ? SUCCESS : FAILURE;
    } /* }}} */




                               PHP Extension Writing                         98
Iterator key()
    The key may be one of:

       Integer: HASH_KEY_IS_LONG
                 Set ulong * to the integer value
       String: HASH_KEY_IS_STRING
                 Set uint * to string length + 1 
                 Set char ** to copy of string (estr[n]dup)


    /* {{{ util_dir_it_current_key */
    static int util_dir_it_current_key(zend_object_iterator *iter, char
    **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
    {
         util_dir_it *iterator = (util_dir_it *)iter;
         zval              *intern = (zval*)iterator->intern.data;
         util_dir_object   *object = (util_dir_object*)
                             zend_object_store_get_object(intern TSRMLS_CC);

         *int_key = object->index;
         return HASH_KEY_IS_LONG;
    } /* }}} */

                               PHP Extension Writing                      99
Iterator current()
    The data was already fetched on rewind() / next()





    /* {{{ util_dir_it_current_data */
    static void util_dir_it_current_data(zend_object_iterator *iter, zval
         ***data TSRMLS_DC)
    {
         util_dir_it *iterator = (util_dir_it *)iter;

         *data = &iterator->current;
    } /* }}} */




                               PHP Extension Writing                        100
Iterator current()
    The data was already fetched on rewind() / next()

    Alternatively

       Reset the cached current/key value in rewind() / next()
       Check the cache on access and read if not yet done

    /* {{{ util_dir_it_current_data */
    static void util_dir_it_current_data(zend_object_iterator *iter, zval
         ***data TSRMLS_DC)
    {
         util_dir_it *iterator = (util_dir_it *)iter;
         util_dir_object *object;

         if (!iterator->current) {
              object = (util_dir_object*)zend_object_store_get_object(
                                   (zval*)iterator->intern.data TSRMLS_CC);
              util_dir_it_current(iterator, object TSRMLS_CC);
         }
         *data = &iterator->current;
    } /* }}} */




                                PHP Extension Writing                       101
Iterator next()
    Move to next element

    Fetch new current data



    /* {{{ util_dir_it_move_forward */
    static void
    util_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
    {
         util_dir_it       *iterator = (util_dir_it *)iter;
         zval              *intern = (zval*)iterator->intern.data;
         util_dir_object   *object = (util_dir_object*)
                         zend_object_store_get_object(intern TSRMLS_CC);

         object->index++;
         if (!object->dirp
         || !php_stream_readdir(object->dirp, &object->entry))
         {
              object->entry.d_name[0] = '0';
         }

         util_dir_it_current(iterator, object TSRMLS_CC);
    } /* }}} */

                               PHP Extension Writing                       102
Iterator rewind()
    Rewind to first element

    Fetch first current data

    /* {{{ util_dir_it_rewind */
    static void
    util_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC)
    {
         util_dir_it     *iterator = (util_dir_it *)iter;
         zval            *intern = (zval*)iterator->intern.data;
         util_dir_object *object = (util_dir_object*)
                             zend_object_store_get_object(intern TSRMLS_CC);

         object->index = 0;
         if (object->dirp) {
              php_stream_rewinddir(object->dirp);
         }
         if (!object->dirp
         || !php_stream_readdir(object->dirp, &object->entry))
         {
              object->entry.d_name[0] = '0';
         }
         util_dir_it_current(iterator, object TSRMLS_CC);
    } /* }}} */

                               PHP Extension Writing                     103
Iterator drawbacks
    Either implement native iterators at c­level


    Or provide iterator methods and inherit Iterator


    If you want both

      Your PHP methods call a specialized C­Level handler
      Provide a cache for your method pointers
      C­Level iterator functions check this cache
          On a match call C­Level handler
          Else call the method
      Have the iterator struct part of your object struct
          Use offset_of() for pointer conversion



                            PHP Extension Writing            104
References
    This presentation

          http://talks.somabo.de

    Documentation and Sources to PHP5

         http://php.net

    http://www.zend.com/php/internals


    Advanced PHP Programming 

         by George Schlossnagle

    Extending and Embedding PHP

         by Sara Golemon
         ISBN#0­6723­2704­X


                     PHP Extension Writing   105

Mais conteúdo relacionado

Mais procurados

P H P Part I, By Kian
P H P  Part  I,  By  KianP H P  Part  I,  By  Kian
P H P Part I, By Kianphelios
 
Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13Rafael Dohms
 
Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Heiko Behrens
 
Docco.coffee
Docco.coffeeDocco.coffee
Docco.coffeetimourian
 
Intro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATXIntro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATXCindy Royal
 
Fnt Software Solutions Pvt Ltd Placement Papers - PHP Technology
Fnt Software Solutions Pvt Ltd Placement Papers - PHP TechnologyFnt Software Solutions Pvt Ltd Placement Papers - PHP Technology
Fnt Software Solutions Pvt Ltd Placement Papers - PHP Technologyfntsofttech
 
Decaf language specification
Decaf language specificationDecaf language specification
Decaf language specificationSami Said
 
Intro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATXIntro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATXCindy Royal
 

Mais procurados (20)

P H P Part I, By Kian
P H P  Part  I,  By  KianP H P  Part  I,  By  Kian
P H P Part I, By Kian
 
Phpquick
PhpquickPhpquick
Phpquick
 
Ruby cheat sheet
Ruby cheat sheetRuby cheat sheet
Ruby cheat sheet
 
Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13
 
Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009
 
Ruby quick ref
Ruby quick refRuby quick ref
Ruby quick ref
 
Cfphp Zce 01 Basics
Cfphp Zce 01 BasicsCfphp Zce 01 Basics
Cfphp Zce 01 Basics
 
Docco.coffee
Docco.coffeeDocco.coffee
Docco.coffee
 
Perl Introduction
Perl IntroductionPerl Introduction
Perl Introduction
 
Intro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATXIntro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATX
 
Fnt Software Solutions Pvt Ltd Placement Papers - PHP Technology
Fnt Software Solutions Pvt Ltd Placement Papers - PHP TechnologyFnt Software Solutions Pvt Ltd Placement Papers - PHP Technology
Fnt Software Solutions Pvt Ltd Placement Papers - PHP Technology
 
Decaf language specification
Decaf language specificationDecaf language specification
Decaf language specification
 
Perl tutorial
Perl tutorialPerl tutorial
Perl tutorial
 
Intro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATXIntro to Programming for Communicators - Hacks/Hackers ATX
Intro to Programming for Communicators - Hacks/Hackers ATX
 
00 ruby tutorial
00 ruby tutorial00 ruby tutorial
00 ruby tutorial
 
Perl Presentation
Perl PresentationPerl Presentation
Perl Presentation
 
Dsl
DslDsl
Dsl
 
Zend Framework 2 Patterns
Zend Framework 2 PatternsZend Framework 2 Patterns
Zend Framework 2 Patterns
 
Php Learning show
Php Learning showPhp Learning show
Php Learning show
 
Final exam
Final examFinal exam
Final exam
 

Destaque

Solr Presentation5
Solr Presentation5Solr Presentation5
Solr Presentation5oscon2007
 
Os Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman WiifmOs Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman Wiifmoscon2007
 
J Ruby Whirlwind Tour
J Ruby Whirlwind TourJ Ruby Whirlwind Tour
J Ruby Whirlwind Touroscon2007
 
Dynamic nested clustering for parallel phy layer processing in cloud-ra ns
Dynamic nested clustering for parallel phy layer processing in cloud-ra nsDynamic nested clustering for parallel phy layer processing in cloud-ra ns
Dynamic nested clustering for parallel phy layer processing in cloud-ra nsieeepondy
 
Performance Whack A Mole
Performance Whack A MolePerformance Whack A Mole
Performance Whack A Moleoscon2007
 
[Russia] MySQL OOB injections
[Russia] MySQL OOB injections[Russia] MySQL OOB injections
[Russia] MySQL OOB injectionsOWASP EEE
 
Las Mejores Cosas De La Vida Estela Lugli
Las Mejores Cosas De La Vida  Estela LugliLas Mejores Cosas De La Vida  Estela Lugli
Las Mejores Cosas De La Vida Estela LugliCristina Dino
 
理財課程
理財課程理財課程
理財課程miscat
 
Os Ellistutorial
Os EllistutorialOs Ellistutorial
Os Ellistutorialoscon2007
 
A.R.MARK (STANDS EM FEIRAS)
A.R.MARK (STANDS EM FEIRAS)A.R.MARK (STANDS EM FEIRAS)
A.R.MARK (STANDS EM FEIRAS)marcellopollara
 
Multicore programmingandtpl
Multicore programmingandtplMulticore programmingandtpl
Multicore programmingandtplYan Drugalya
 

Destaque (20)

Os Harkins
Os HarkinsOs Harkins
Os Harkins
 
Solr Presentation5
Solr Presentation5Solr Presentation5
Solr Presentation5
 
Os Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman WiifmOs Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman Wiifm
 
Os Bunce
Os BunceOs Bunce
Os Bunce
 
Ndp Slides
Ndp SlidesNdp Slides
Ndp Slides
 
J Ruby Whirlwind Tour
J Ruby Whirlwind TourJ Ruby Whirlwind Tour
J Ruby Whirlwind Tour
 
Dynamic nested clustering for parallel phy layer processing in cloud-ra ns
Dynamic nested clustering for parallel phy layer processing in cloud-ra nsDynamic nested clustering for parallel phy layer processing in cloud-ra ns
Dynamic nested clustering for parallel phy layer processing in cloud-ra ns
 
Performance Whack A Mole
Performance Whack A MolePerformance Whack A Mole
Performance Whack A Mole
 
Drupal and Solr
Drupal and SolrDrupal and Solr
Drupal and Solr
 
[Russia] MySQL OOB injections
[Russia] MySQL OOB injections[Russia] MySQL OOB injections
[Russia] MySQL OOB injections
 
Las Mejores Cosas De La Vida Estela Lugli
Las Mejores Cosas De La Vida  Estela LugliLas Mejores Cosas De La Vida  Estela Lugli
Las Mejores Cosas De La Vida Estela Lugli
 
Os Whitaker
Os WhitakerOs Whitaker
Os Whitaker
 
理財課程
理財課程理財課程
理財課程
 
ApresentaçãO11
ApresentaçãO11ApresentaçãO11
ApresentaçãO11
 
Tarea
TareaTarea
Tarea
 
Os Zaitsev
Os ZaitsevOs Zaitsev
Os Zaitsev
 
Os Ellistutorial
Os EllistutorialOs Ellistutorial
Os Ellistutorial
 
A.R.MARK (STANDS EM FEIRAS)
A.R.MARK (STANDS EM FEIRAS)A.R.MARK (STANDS EM FEIRAS)
A.R.MARK (STANDS EM FEIRAS)
 
Os Kimsal
Os KimsalOs Kimsal
Os Kimsal
 
Multicore programmingandtpl
Multicore programmingandtplMulticore programmingandtpl
Multicore programmingandtpl
 

Semelhante a Os Borger

Lecture4 php by okello erick
Lecture4 php by okello erickLecture4 php by okello erick
Lecture4 php by okello erickokelloerick
 
PHP Introduction and Training Material
PHP Introduction and Training MaterialPHP Introduction and Training Material
PHP Introduction and Training MaterialManoj kumar
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objectsjulien pauli
 
Lecture 2 php basics (1)
Lecture 2  php basics (1)Lecture 2  php basics (1)
Lecture 2 php basics (1)Core Lee
 
Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaCreate your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaPatrick Allaert
 
Php Crash Course - Macq Electronique 2010
Php Crash Course - Macq Electronique 2010Php Crash Course - Macq Electronique 2010
Php Crash Course - Macq Electronique 2010Michelangelo van Dam
 
php app development 1
php app development 1php app development 1
php app development 1barryavery
 
Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)
Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)
Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)Muhamad Al Imran
 
PHP Unit 3 functions_in_php_2
PHP Unit 3 functions_in_php_2PHP Unit 3 functions_in_php_2
PHP Unit 3 functions_in_php_2Kumar
 
Php basics
Php basicsPhp basics
Php basicshamfu
 
PHP-03-Functions.ppt
PHP-03-Functions.pptPHP-03-Functions.ppt
PHP-03-Functions.pptJamers2
 

Semelhante a Os Borger (20)

unit 1.pptx
unit 1.pptxunit 1.pptx
unit 1.pptx
 
Lecture4 php by okello erick
Lecture4 php by okello erickLecture4 php by okello erick
Lecture4 php by okello erick
 
Introduction to php basics
Introduction to php   basicsIntroduction to php   basics
Introduction to php basics
 
Php variables (english)
Php variables (english)Php variables (english)
Php variables (english)
 
PHP Introduction and Training Material
PHP Introduction and Training MaterialPHP Introduction and Training Material
PHP Introduction and Training Material
 
PHP 2.pptx
PHP 2.pptxPHP 2.pptx
PHP 2.pptx
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objects
 
Lecture 2 php basics (1)
Lecture 2  php basics (1)Lecture 2  php basics (1)
Lecture 2 php basics (1)
 
Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaCreate your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 Verona
 
Php Crash Course - Macq Electronique 2010
Php Crash Course - Macq Electronique 2010Php Crash Course - Macq Electronique 2010
Php Crash Course - Macq Electronique 2010
 
Cs3430 lecture 15
Cs3430 lecture 15Cs3430 lecture 15
Cs3430 lecture 15
 
php AND MYSQL _ppt.pdf
php AND MYSQL _ppt.pdfphp AND MYSQL _ppt.pdf
php AND MYSQL _ppt.pdf
 
Php Tutorials for Beginners
Php Tutorials for BeginnersPhp Tutorials for Beginners
Php Tutorials for Beginners
 
php app development 1
php app development 1php app development 1
php app development 1
 
Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)
Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)
Php i basic chapter 3 (mardhiah kamaludin's conflicted copy 2013-04-23)
 
PHP Unit 3 functions_in_php_2
PHP Unit 3 functions_in_php_2PHP Unit 3 functions_in_php_2
PHP Unit 3 functions_in_php_2
 
Php basics
Php basicsPhp basics
Php basics
 
PHP-01-Overview.ppt
PHP-01-Overview.pptPHP-01-Overview.ppt
PHP-01-Overview.ppt
 
PHP
PHPPHP
PHP
 
PHP-03-Functions.ppt
PHP-03-Functions.pptPHP-03-Functions.ppt
PHP-03-Functions.ppt
 

Mais de oscon2007

Os Lanphier Brashears
Os Lanphier BrashearsOs Lanphier Brashears
Os Lanphier Brashearsoscon2007
 
Os Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman SwpOs Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman Swposcon2007
 
Os Berlin Dispelling Myths
Os Berlin Dispelling MythsOs Berlin Dispelling Myths
Os Berlin Dispelling Mythsoscon2007
 
Os Keysholistic
Os KeysholisticOs Keysholistic
Os Keysholisticoscon2007
 
Os Jonphillips
Os JonphillipsOs Jonphillips
Os Jonphillipsoscon2007
 
Os Urnerupdated
Os UrnerupdatedOs Urnerupdated
Os Urnerupdatedoscon2007
 
Adventures In Copyright Reform
Adventures In Copyright ReformAdventures In Copyright Reform
Adventures In Copyright Reformoscon2007
 
Railsconf2007
Railsconf2007Railsconf2007
Railsconf2007oscon2007
 
Oscon Mitchellbaker
Oscon MitchellbakerOscon Mitchellbaker
Oscon Mitchellbakeroscon2007
 
Os Pruett Sessionnotes
Os Pruett SessionnotesOs Pruett Sessionnotes
Os Pruett Sessionnotesoscon2007
 
Os Keyshacks
Os KeyshacksOs Keyshacks
Os Keyshacksoscon2007
 
Os Buncetutorial
Os BuncetutorialOs Buncetutorial
Os Buncetutorialoscon2007
 

Mais de oscon2007 (20)

Yuicss R7
Yuicss R7Yuicss R7
Yuicss R7
 
Os Fogel
Os FogelOs Fogel
Os Fogel
 
Os Lanphier Brashears
Os Lanphier BrashearsOs Lanphier Brashears
Os Lanphier Brashears
 
Os Tucker
Os TuckerOs Tucker
Os Tucker
 
Os Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman SwpOs Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman Swp
 
Os Furlong
Os FurlongOs Furlong
Os Furlong
 
Os Berlin Dispelling Myths
Os Berlin Dispelling MythsOs Berlin Dispelling Myths
Os Berlin Dispelling Myths
 
Os Pruett
Os PruettOs Pruett
Os Pruett
 
Os Alrubaie
Os AlrubaieOs Alrubaie
Os Alrubaie
 
Os Keysholistic
Os KeysholisticOs Keysholistic
Os Keysholistic
 
Os Jonphillips
Os JonphillipsOs Jonphillips
Os Jonphillips
 
Os Urnerupdated
Os UrnerupdatedOs Urnerupdated
Os Urnerupdated
 
Adventures In Copyright Reform
Adventures In Copyright ReformAdventures In Copyright Reform
Adventures In Copyright Reform
 
Railsconf2007
Railsconf2007Railsconf2007
Railsconf2007
 
Oscon Mitchellbaker
Oscon MitchellbakerOscon Mitchellbaker
Oscon Mitchellbaker
 
Os Sharp
Os SharpOs Sharp
Os Sharp
 
Os Pruett Sessionnotes
Os Pruett SessionnotesOs Pruett Sessionnotes
Os Pruett Sessionnotes
 
Os Keyshacks
Os KeyshacksOs Keyshacks
Os Keyshacks
 
Os Buncetutorial
Os BuncetutorialOs Buncetutorial
Os Buncetutorial
 
Os Napier
Os NapierOs Napier
Os Napier
 

Último

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...AliaaTarek5
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 

Último (20)

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 

Os Borger

  • 1. PHP Extension writing Marcus Börger Wez Furlong Sara Golemon OSCON 2007
  • 2. Creating PHP 5 Extension  PHP Lifecycle  Adding objects  Adding iterators to objects  PHP Extension Writing 2
  • 3. How the slides work Upper part contains some helpful hints  Lower part shows c code on blue background  Text in yellow Text you should use as presented Text in green Text that you have to replace yourext Extension name in lowercase YOUREXT Extension name in uppercase YourExt Extension name in mixed case (camelCaps) Some special explanation use red text boxes PHP Extension Writing 3
  • 4. Part I Creating PHP 5 Extensions How PHP handles data  How to create your own extension skeleton  How to create your own functions  How to work with arrays and hash tables  PHP Extension Writing 4
  • 5. In PHP all values are zval's typedef struct _zval_struct { zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval; typedef union _zvalue_value { long lval; double dval; struct { IS_NULL char *val; IS_LONG int len; IS_DOUBLE } str; IS_BOOL HashTable *ht; IS_ARRAY zend_object_value obj; IS_OBJECT } zvalue_value; IS_STRING IS_RESOURCE PHP Extension Writing 5
  • 6. In PHP all values are zval's typedef struct _zval_struct { Userspace notion of quot;Referencequot; zvalue_value value; 0 == Not a reference zend_uint refcount; zend_uchar type; 1 == Is a reference zend_uchar is_ref; } zval; How many quot;labelsquot; are associated with this zval? PHP Extension Writing 6
  • 7. Copy On Write typedef struct _zval_struct { • Has a value of 0 (zero) zvalue_value value; • zval shared by 1 or more labels zend_uint refcount; zend_uchar type; • If one label wants to make a zend_uchar is_ref; change, it must leave other } zval; labels with the original value. $a $b $a = 123; $b = $a; value.lval = 123 $b = 456; refcount = 2 type = IS_LONG is_ref = 0 PHP Extension Writing 7
  • 8. Copy On Write typedef struct _zval_struct { • Has a value of 0 (zero) zvalue_value value; • zval shared by 1 or more labels zend_uint refcount; zend_uchar type; • If one label wants to make a zend_uchar is_ref; change, it must leave other } zval; labels with the original value. $a $b $a = 123; $b = $a; value.lval = 123 value.lval = 456 $b = 456; refcount = 1 refcount = 1 type = IS_LONG type = IS_LONG is_ref = 0 is_ref = 0 PHP Extension Writing 8
  • 9. Full Reference typedef struct _zval_struct { • Has a value of 1 (one) zvalue_value value; • zval shared by 1 or more labels zend_uint refcount; zend_uchar type; • If one label wants to make a zend_uchar is_ref; change, it does so, causing other } zval; labels to see the new value. $a $b $a = 123; $b = &$a; value.lval = 123 $b = 456; refcount = 2 type = IS_LONG is_ref = 1 PHP Extension Writing 9
  • 10. Full Reference typedef struct _zval_struct { • Has a value of 1 (one) zvalue_value value; • zval shared by 1 or more labels zend_uint refcount; zend_uchar type; • If one label wants to make a zend_uchar is_ref; change, it does so, causing other } zval; labels to see the new value. $a $b $a = 123; $b = &$a; value.lval = 456 $b = 456; refcount = 2 type = IS_LONG is_ref = 1 PHP Extension Writing 10
  • 11. Creating PHP 5 Extensions Most PHP 4 exts will build in PHP5 w/o Changes  ext_skel can be used to generate a basic skeleton  marcus@zaphod src/php5/ext $ ./ext_skel --extname=util Creating directory util Creating basic files: config.m4 .cvsignore util.c php_util.h CREDITS EXPERIMENTAL tests/001.phpt util.php [done]. To use your new extension, you will have to execute the following steps: 1. $ cd .. Necessary for non cvs source 2. $ vi ext/util/config.m4 (e.g. release packages) 3. $ ./buildconf --force 4. $ ./configure --[with|enable]-util 5. $ make 6. $ ./php -f ext/util/util.php 7. $ vi ext/util/util.c 8. $ make Repeat steps 3-6 until you are satisfied with ext/util/config.m4 and step 6 confirms that your module is compiled into PHP. Then, start writing code and repeat the last two steps as often as necessary. PHP Extension Writing 11
  • 12. Files in your extension You need at least two code files   php_yourext.h The header needed by php  php_yourext.c The main extension code ('php_' prefix for .c is not necessary) You need two configuration files   config.m4 Used under *nix  config.w32 Used under windows Optional files  .cvsignore List of files to be ignored by CVS  CREDITS First line ext name 2nd line all authors  EXPERIMENTAL If available the API is not yet stable  package2.xml Required for PECL extensions  README Probably good to provide some lines  PHP Extension Writing 12
  • 13. config.m4 PHP Dev is picky about coding style   Read CODING_STANDARDS in php­src  Watch your whitespace  Align your PHP_ARG_ENABLE output Make your extension default disabled   'phpize' or 'pear install' will enable it automatically dnl $Id: $ dnl config.m4 for extension YOUREXT PHP_ARG_ENABLE(yourext, enable YourExt suppport, Enable YourExt], no) [ --enable-yourext if test quot;$PHP_YOUREXTquot; != quot;noquot;; then AC_DEFINE(HAVE_YOUREXT, 1,[Whether YourExt is present]) PHP_NEW_EXTENSION(yourext, php_yourext.c, $ext_shared) fi PHP Extension Writing 13
  • 14. config.m4 You can prevent the ext from becoming shared  dnl $Id: $ dnl config.m4 for extension YOUREXT PHP_ARG_ENABLE(yourext, enable YourExt suppport, Enable YourExt], no) [ --enable-yourext if test quot;$PHP_YOUREXTquot; != quot;noquot;;then if test quot;$ext_sharedquot; = quot;yesquot;; then AC_MSG_ERROR(Cannot build YOUREXT as a shared module) fi AC_DEFINE(HAVE_YOUREXT,1,[Whether YourExt is present]) PHP_NEW_EXTENSION(yourext, php_yourext.c, $ext_shared) fi PHP Extension Writing 14
  • 15. config.w32 Windows configuration uses JScript  // $Id: $ // vim:ft=javascript ARG_ENABLE(quot;yourextquot;, quot;YourExt supportquot;, quot;yesquot;); if (PHP_YOUREXT == quot;yesquot;) { if (PHP_YOUREXT_SHARED) { ERROR(quot;YOUREXT cannot be compiled as a shared extquot;); } AC_DEFINE(quot;HAVE_YOUREXTquot;, 1, quot;YourExt supportquot;); EXTENSION(quot;yourextquot;, quot;php_yourext.cquot;); } PHP Extension Writing 15
  • 16. Extension .h file Declares data for static linking and   symbol exports /* License, Author, CVS-Tag, Etc... */ #ifndef PHP_YOUREXT_H #define PHP_YOUREXT_H #include quot;php.hquot; extern zend_module_entry yourext_module_entry; #define phpext_yourext_ptr &yourext_module_entry /* Only needed if you'll be exporting symbols */ #ifdef PHP_WIN32 # define YOUREXT_API __declspec(dllexport) #else # define YOUREXT_API #endif /* Place for globals definition */ #endif /* PHP_YOUREXT_H */ PHP Extension Writing 16
  • 17. Layout of the .c file Header: License, Authors, CVS­Tag, ...  Includes  Structures and defines not in header  Helper Functions  PHP Functions  Globals Handling  MINFO  MINIT, MSHUTDOWN  RINIT, RSHUTDOWN  Function table  Module Entry  PHP Extension Writing 17
  • 18. Includes Include path:   <PHP Root>/  <PHP Root>/Zend  <PHP Root>/main  <PHP Root>/ext/<Your Extension>  #ifdef HAVE_CONFIG_H #include quot;config.hquot; #endif #include quot;php.hquot; #include quot;php_ini.hquot; #include quot;ext/standard/info.hquot; #include quot;ext/standard/php_string.hquot; #include quot;php_yourext.hquot; PHP Extension Writing 18
  • 19. Structures and defines  not in header What ever you want   Local storage structures?  Constants?  Macros? typedef struct _php_yourext_data { int type; char *name; int name_len; php_stream *stream; } php_yourext_data; #define PHP_YOUREXT_MEANING 42 #define PHP_YOUREXT_COLOR quot;purplequot; #define PHP_YOUREXT_STRLEN(v) (v ? strlen(v) : 0) PHP Extension Writing 19
  • 20. 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 PHP Extension Writing 20
  • 21. 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 static void my_helper(TSRMLS_D); static void some_function(TSRMLS_D) { my_helper(TSRMLS_C); } PHP Extension Writing 21
  • 22. 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 static void my_helper(void * p TSRMLS_DC); static void some_function(void * p TSRMLS_DC) { my_helper(p TSRMLS_CC); } PHP Extension Writing 22
  • 23. 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 static void my_helper(char *p, int p_len TSRMLS_DC); static void some_function(char *p) { int p_len; TSRMLS_FETCH(); p_len = strlen(p); my_helper(p, p_len TSRMLS_CC); } PHP Extension Writing 23
  • 24. Module Entry Keeps everything together  Tells PHP how to (de)initialize the extension  zend_module_entry yourext_module_entry = { /* {{{ */ STANDARD_MODULE_HEADER, quot;YourExtquot;, yourext_functions, PHP_MINIT(yourext), PHP_MSHUTDOWN(yourext), PHP_RINIT(yourext), PHP_RSHUTDOWN(yourext), or NULL PHP_MINFO(yourext), quot;0.1quot;, STANDARD_MODULE_PROPERTIES }; /* }}} */ #if COMPILE_DL_YOUREXT ZEND_GET_MODULE(yourext) #endif PHP Extension Writing 24
  • 25. Function List Exports your functions to userspace  Must be terminated by NULL tripplet zend_function_entry yourext_functions[] = { /* {{{ */ yourext_args_func1) PHP_FE(yourext_func1, PHP_FE(yourext_func2, NULL) yourext_func2, NULL) PHP_FALIAS(yourext_func3, PHP_NAMED_FE(yourext_func4, _yourext_func4_impl, NULL) {NULL, NULL, NULL} }; PHP Extension Writing 25
  • 26. 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 static ZEND_BEGIN_ARG_INFO_EX(yourext_args_func1,0,0,2) ZEND_ARG_INFO(0, param_name1) ZEND_ARG_ARRAY_INFO(1, param_name2) ZEND_END_ARG_INFO(); PHP Extension Writing 26
  • 27. PHP Functions Namespace your functions with your ext's name  Documentation is your friend   Avoid // style C++ comments  Avoid declarations inline with code /* {{{ proto type yourext_name(params) Short description */ PHP_FUNCTION(yourext_name) { /* Local declarations */ /* Parameter parsing */ /* Actual code */ /* Return value */ } /* }}} */ PHP Extension Writing 27
  • 28. Outputting Content Do not send content to stdout  use PHP's output buffering mechanisms   php_printf() works just like printf()  PHPWRITE() respects binary safety /* {{{ proto null yourext_hello_world() Say Hello */ PHP_FUNCTION(yourext_hello_world) { char *greeting = quot;Hello Worldquot;; php_printf(quot;%s!nquot;, greeting); PHPWRITE(greeting, strlen(greeting)); php_printf(quot;!nquot;); } /* }}} */ PHP Extension Writing 28
  • 29. Parsing parameters zend_parse_parameters is the easy way of parsing  int zend_parse_parameters( int num_args TSRMLS_DC, char *type_spec, ...); int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...); flags 0 or ZEND_PARSE_PARAMS_QUIET num_args use ZEND_NUM_ARGS() type_spec sscanf like typelist (though no %) ... References to the types given in type_spec returns SUCCESS or FAILURE in case of failure an error is already issued so no need for ZEND_WRONG_PARAM_COUNT() unless using ZEND_PARSE_PARAMS_QUIET PHP Extension Writing 29
  • 30. Parsing parameters type_spec sscanf like typelist (though no %) l long long * d double double * b boolean zend_bool * a array zval ** o object zval ** O object zval **, zend_class_entry * Object must be derived from given class s string char **, int * You receive string and length r resource zval ** z zval zval ** Z zval-ref zval *** | right part is optional / next param gets separated if not reference ! Next param returns NULL if param type IS_NULL PHP Extension Writing 30
  • 31. Parsing Parameters /* {{{ proto null yourext_hello(string name) Greet by name */ PHP_FUNCTION(yourext_hello) { char *name; int name_len; if (zend_parse_parameters(ZEND_NUM_ARGS(), quot;squot;, &name, &name_len) == FAILURE) { return; } php_printf(quot;Hello %s!nquot;, name); } /* }}} */ PHP Extension Writing 31
  • 32. Returning Values Marking success  /* {{{ proto bool yourext_hello(string name) Greet by name */ PHP_FUNCTION(yourext_hello) { char *name; int name_len; if (zend_parse_parameters(ZEND_NUM_ARGS(), quot;squot;, &name, &name_len) == FAILURE) { return; Makes the return } value NULL php_printf(quot;Hello %s!nquot;, name); RETURN_TRUE; } /* }}} */ PHP Extension Writing 32
  • 33. 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: Integer value RETURN_DOUBLE(d); d: Floating point value PHP Extension Writing 33
  • 34. Returning Values Strings are slightly more complex  The string value must quot;belongquot; to the engine   Will not survive the destruction of the zval  Will be freed using efree() Pass 0 (zero) for dup to give it the string  Pass 1 (one) for dup to make a copy (duplicate)  RETURN_STRING(str, dup) str: char* string value dup: 0/1 flag, duplicate string? RETURN_STRINGL(str, len, dup) len: Predetermined string length RETURN_STRING(quot;Hello Worldquot;, 1); RETURN_STRING(estrdup(quot;Hello Worldquot;), 0); RETURN_EMPTY_STRING(); PHP Extension Writing 34
  • 35. Setting Returning Values RETURN_*() macros automatically exit function  RETVAL_*() family work the same without exiting  #define RETURN_NULL() { RETVAL_NULL(); return; } #define RETURN_TRUE { RETVAL_TRUE; return; } #define RETURN_FALSE { RETVAL_FALSE; return; } #define RETURN_BOOL(b) { RETVAL_BOOL(b); return; } #define RETURN_LONG(l) { RETVAL_LONG(l); return; } #define RETURN_DOUBLE(d) { RETVAL_DOUBLE(d); return; } #define RETURN_STRING(str, dup) { RETVAL_STRING(str, dup); return; } #define RETURN_STRINGL(str, len, dup) { RETVAL_STRINGL(str, len, dup); return; } #define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; } PHP Extension Writing 35
  • 36. Setting Returning Values RETURN_*() macros automatically exit function  RETVAL_*() family work the same without exiting  ZVAL_*() family also work the same  #define RETVAL_NULL() ZVAL_NULL(return_value) #define RETVAL_TRUE ZVAL_TRUE(return_value) #define RETVAL_FALSE ZVAL_FALSE(return_value) #define RETVAL_BOOL(b) ZVAL_BOOL(return_value, b) #define RETVAL_LONG(l) ZVAL_LONG(return_value, l) #define RETVAL_DOUBLE(d) ZVAL_DOUBLE(return_value, d) #define RETVAL_STRING(str, dup) ZVAL_STRING(return_value, str, dup) #define RETVAL_STRINGL(str, len, dup) ZVAL_STRINGL(return_value, str, len, dup) #define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value) PHP Extension Writing 36
  • 37. Example 1 Inverting a single boolean parameter  /* {{{ proto bool yourext_invert(bool b) Invert a boolean parameter */ PHP_FUNCTION(yourext_invert) { zend_bool b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, quot;bquot;, &b) == FAILURE) { return; } b = b ? 0 : 1; RETURN_BOOL(b); } /* }}} */ PHP Extension Writing 37
  • 38. Example 2 Incrementing a value with an optional maximum  /* {{{ proto bool yourext_increment(int v [, int max]) Increment a value with optional maximum */ PHP_FUNCTION(yourext_increment) Initialize Use brackets { optional for optional long n, nmax = LONG_MAX; values values if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, quot;l|lquot;, &n, &nmax) == FAILURE) { RETURN_FALSE(); } A vertical bar separates optional and required n = (n+1) % nmax; parameters RETURN_LONG(n); } /* }}} */ PHP Extension Writing 38
  • 39. Example 3 Returning some generated string  #define YOUREXT_VERSION_MAJOR 0 #define YOUREXT_VERSION_MINOR 1 /* {{{ proto string yourext_version() Retrieve yourext version */ PHP_FUNCTION(yourext_version) { Never use sprintf, char * ver; use either snprintf or spprintf int len; len = spprintf(&ver, 0, quot;%d.%d (%s)quot;, YOUREXT_VERSION_MAJOR, YOUREXT_VERSION_MINOR, quot;$Id: $quot;); RETURN_STRINGL(ver, len, 0); No need to } copy the string /* }}} */ PHP Extension Writing 39
  • 40. Dealing with arrays To initialize a zval as an array: array_init(pzv)   To return an array use: array_init(return_value) To add elements use the following   add_assoc_<type>(ar, key, ...)  add_assoc_<type>_ex(ar, key, key_len, ...) int add_assoc_long(zval *arg, char *key, long n); int add_assoc_null(zval *arg, char *key); int add_assoc_bool(zval *arg, char *key, int b); int add_assoc_resource(zval *arg, char *key, int r); int add_assoc_double(zval *arg, char *key, double d); int add_assoc_string(zval *arg, char *key, char *str, int dup); int add_assoc_stringl(zval *arg, char *key, char *str, uint len, int dup); int add_assoc_zval(zval *arg, char *key, zval *value); PHP Extension Writing 40
  • 41. Dealing with arrays To convert a zval into an array: array_init(pzv)   To return an array use: array_init(return_value) To add elements use the following   add_assoc_<type>(ar, key, ...)  add_index_<type>(ar, index, ...) int add_index_long(zval *arg, uint idx, long n); int add_index_null(zval *arg, uint idx); int add_index_bool(zval *arg, uint idx, int b); int add_index_resource(zval *arg, uint idx, int r); int add_index_double(zval *arg, uint idx, double d); int add_index_string(zval *arg, uint idx, char *str, int duplicate); int add_index_stringl(zval *arg, uint idx, char *str, uint length, int duplicate); int add_index_zval(zval *arg, uint idx, zval *value); PHP Extension Writing 41
  • 42. Dealing with arrays To convert a zval into an array: array_init(pzv)   To return an array use: array_init(return_value) To add elements use the following   add_assoc_<type>(ar, key, ...)  add_index_<type>(ar, index, ...)  add_next_index_<type>(ar, ...) int add_next_index_long(zval *arg, long n); int add_next_index_null(zval *arg); int add_next_index_bool(zval *arg, int b); int add_next_index_resource(zval *arg, int r); int add_next_index_double(zval *arg, double d); int add_next_index_string(zval *arg, char *str, int duplicate); int add_next_index_stringl(zval *arg, char *str, uint length, int duplicate); int add_next_index_zval(zval *arg, zval *value); PHP Extension Writing 42
  • 43. Example 4 Returning an array  /* {{{ proto array yourext_version_array() Retrieve yourext version as array */ PHP_FUNCTION(yourext_version_array) { char *ver; int len = spprintf(&ver, 0, quot;%d.%dquot;, YOUREXT_VERSION_MAJOR, YOUREXT_VERSION_MINOR); make return_value an array array_init(return_value); add_assoc_long(return_value, quot;majorquot;, YOUREXT_VERSION_MAJOR); add_assoc_long(return_value, quot;minorquot;, YOUREXT_VERISON_MINOR); add_assoc_string(return_value, quot;cvsquot;, quot;$Id: $quot;, 1); add_assoc_stringl(return_value, quot;verquot;, ver, len, 0); } /* }}} */ PHP Extension Writing 43
  • 44. 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. /* arKey hashed using DJBX33A */ ulong zend_get_hash_value(char *arKey, uint nKeyLength); /* count($ht) */ int zend_hash_num_elements(HashTable *ht); /* Removes all elements from the HashTable */ int zend_hash_clean(HashTable *ht); PHP Extension Writing 44
  • 45. Adding to HashTables add_assoc/index_*() functions wrap   zend_symtable_update() Symbol table keys include terminating NULL byte  sizeof(key) vs. strlen(key) add_assoc_zval(arr, quot;fooquot;, val); add_assoc_zval_ex(arr, quot;fooquot;, sizeof(quot;fooquot;), val); zend_symtable_update(Z_ARRVAL_P(arr), quot;fooquot;, sizeof(quot;fooquot;), &val, sizeof(zval*), NULL); PHP Extension Writing 45
  • 46. Deleting from HashTables You can delete elements (SUCCESS/FAILURE)   by key  by hash index  by symbol int zend_hash_del(HashTable *ht, char *arKey, uint nKeyLen); int zend_hash_index_del(HashTable *ht, ulong h); int zend_symtable_del(HashTable *ht, char *arKey, uint nKeyLength); PHP Extension Writing 46
  • 47. 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  int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLength); int zend_hash_quick_exists(HashTable *ht, char *arKey, uint nKeyLength, ulong h); int zend_hash_index_exists(HashTable *ht, ulong h); int zend_symtable_exists(HashTable *ht, char *arKey, uint nKeyLength); PHP Extension Writing 47
  • 48. 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  int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData); int zend_hash_quick_find(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void **pData); int zend_hash_index_find(HashTable *ht, ulong h, void **pData); int zend_symtable_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData); PHP Extension Writing 48
  • 49. Searching HashTables Symbol Tables store zval* pointers  When fetching, a reference to a zval** is passed  zval **tmp; if (zend_symtable_find(ht, quot;keyquot;, sizeof(quot;keyquot;), (void**)&tmp) == SUCCESS) { /* Do something with tmp */ if (Z_TYPE_PP(tmp) == IS_STRING) { PHPWRITE(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); } } PHP Extension Writing 49
  • 50. Accessing a zval Z_LVAL(zval) long value Z_BVAL(zval) zend_bool value Z_DVAL(zval) double value Z_STRVAL(zval) char* value Z_STRLEN(zval) int length Z_ARRVAL(zval) HashTable* only array Z_OBJ_HANDLE(zval) int obj id Z_OBJ_HT(zval) zend_object_handlers* obj handlers Z_OBJCE(zval) zend_class_entry* obj class Z_OBJPROP(zval) HashTable* properties Z_OBJ_HANDLER(zval,hf) Z_OBJ_HT((zval))->hf obj handler Z_RESVAL(zval) int resource id Z_TYPE(zval) int IS_* HASH_OF(zval) HashTable* array+props Z_*_P(zp) Z_*(*zp) Z_*_PP(zpp) Z_*(**zpp) PHP Extension Writing 50
  • 51. Dealing with a HashTable Hash tables have builtin quot;foreachquot; functions  /* array_walk($ht, $apply_func) */ void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC); /* array_walk($ht, $apply_func, $data) */ void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void * TSRMLS_DC); /* Multiple argument version, * This is also the only variant which provides * the key to the callback */ void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int, ...); PHP Extension Writing 51
  • 52. Dealing with a HashTable Hash tables have builtin quot;foreachquot; functions  Each function requires a different type of callback  /* pDest contains a pointer to * what's stored in the HashTable * Since there is a zval* in SymbolTables * we wind up with a zval** being passed as pDest* typedef int (*apply_func_t)(void *pDest TSRMLS_DC); typedef int (*apply_func_arg_t)(void *pDest, void *argument TSRMLS_DC); typedef int (*apply_func_args_t)(void *pDest, int num_args, va_list args, zend_hash_key *hash_key); PHP Extension Writing 52
  • 53. Dealing with a HashTable Hash tables have builtin quot;foreachquot; 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 /* Continue itterating the HashTable */ #define ZEND_HASH_APPLY_KEEP 0 /* Remove this element, but continue processing */ #define ZEND_HASH_APPLY_REMOVE 1<<0 /* Terminate the loop (break;) */ #define ZEND_HASH_APPLY_STOP 1<<1 PHP Extension Writing 53
  • 54. Example 5 a Using zend_hash_apply_with_arguments()  /* {{{ proto void yourext_foreach( array names, string greeting) Say hello to each person */ PHP_FUNCTION(yourext_foreach) { zval *names; char *greet; int greet_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, quot;asquot;, &names, &greet, &greet_len) == FAILURE) { return; } zend_hash_apply_with_argument(Z_ARRVAL_P(names), (apply_func_arg_t)yourext_foreach, greet TSRMLS_CC); } /* }}} */ PHP Extension Writing 54
  • 55. Example 5 b Calling a function for each element  /* {{{ yourext_foreach Callback for outputting a greeting for each name in a user-provided array */ int yourext_foreach(zval **param, char *greeting TSRMLS_DC) { if (Z_TYPE_PP(param) == IS_STRING) { php_printf(quot;%s %snquot;, greeting, Z_STRVAL_PP(param)); return ZEND_HASH_APPLY_KEEP; } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, quot;Non-string value passed in $names arrayquot;); return ZEND_HASH_APPLY_STOP; } } /* }}} */ PHP Extension Writing 55
  • 56. Part II PHP Lifecycle The PHP Lifecycle  Memory Allocation and Garbage Collection  Globals  Constants  PHP Extension Writing 56
  • 57. 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  PHP Extension Writing 57
  • 58. 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  PHP Extension Writing 58
  • 59. RUNTIME Actual execution of scripts happens here.  Compile and execute auto_prepend_file.  Compile and execute main_file.  Compile and execute auto_append_file.  PHP Extension Writing 59
  • 60. 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.  PHP Extension Writing 60
  • 61. 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 RSHUTDO RINIT RUNTIME RSHUTDO WN WN MSHUTDO Request 1 WN PHP Extension Writing 61
  • 62. Memory Allocation Traditionall malloc() family may be used  void * malloc(size_t size); void * calloc(size_t nmemb, size_t size); void * realloc(void *ptr, size_t size); void * strdup(char *str); void * strndup(char *str, size_t len); void free(void *ptr); PHP Extension Writing 62
  • 63. 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 void * emalloc(size_t size); void * ecalloc(size_t nmemb, size_t size); void * erealloc(void *ptr, size_t size); void * estrdup(char *str); void * estrndup(char *str, size_t len); void efree(void *ptr); void *safe_emalloc(size_t nmemb, size_t size, size_t adtl); void *STR_EMPTY_ALLOC(void); PHP Extension Writing 63
  • 64. 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 void *pemalloc(size_t size, int persist); void *pecalloc(size_t nmemb, size_t size, int persist); void *perealloc(void *ptr, size_t size, int persist); void *pestrdup(char *str, int persist); void pefree(void *ptr, int persist); void *safe_pemalloc(size_t nmemb, size_t size, size_t addtl, int persist); PHP Extension Writing 64
  • 65. Storing Global Values Do NOT store transient data in the global scope!   Threaded SAPIs will break static char *errormsg = NULL; PHP_FUNCTION(yourext_unthreadsafe) { long ret; ret = do_something(quot;valuequot;, &errormsg); if (errormsg) { php_error_docref(NULL TSRMLS_CC, E_WARNING, quot;do_something() failed with: %squot;, errormsg); free(errormsg); errormsg = NULL; } } PHP Extension Writing 65
  • 66. Global struct in .h Provide a structure and access macros  ZEND_BEGIN_MODULE_GLOBALS(yourext) char *str; int strlen; long counter; ZEND_END_MODULE_GLOBALS(yourext) #ifdef ZTS # define YOUREXT_G(v) TSRMG(yourext_globals_id, zend_yourext_globals*, v) extern int yourext_globals_id; #else # define YOUREXT_G(v) (yourext_globals.v) extern zend_yourext_globals yourext_globals; #endif PHP Extension Writing 66
  • 67. 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 ZEND_DECLARE_MODULE_GLOBALS(yourext) static void yourext_globals_ctor( zend_yourext_globals *globals) { /* Initialize your global struct */ globals->str = NULL; globals->strlen = 0; globals->counter = 0; } static void yourext_globals_dtor( zend_yourext_globals *globals) { /* Clean up any allocated globals */ } PHP Extension Writing 67
  • 68. MINIT/MSHUTDOWN Allocate local storage for globals in ZTS mode  Call globals initialization and destruction as needed  PHP_MINIT_FUNCTION(yourext) { ZEND_INIT_MODULE_GLOBALS(yourext, yourext_globals_ctor, yourext_globals_dtor); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(yourext) { #ifndef ZTS yourext_globals_dtor(&yourext_globals TSRMLS_CC); #endif return SUCCESS; } PHP Extension Writing 68
  • 69. RINIT/RSHUTDOWN Initialize request specific settings at RINIT  Clean up their values at RSHUTDOWN  PHP_RINIT_FUNCTION(yourext) { /* Track number of times this thread/process * has serviced requests */ YOUREXT_G(counter)++; return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(yourext) { if (YOUREXT_G(str)) { efree(YOUREXT_G(str)); YOUREXT_G(str) = NULL; } return SUCCESS; } PHP Extension Writing 69
  • 70. Globals Access Access Global values using YOUREXT_G(v) macro  PHP_FUNCTION(yourext_set_string) { char *str; int str_len; if (zend_parse_parameters(ZEND_NUM_ARGS(), quot;squot;, &str, &str_len) == FAILURE) { return; } if (YOUREXT_G(str)) { efree(YOUREXT_G(str)); } YOUREXT_G(str) = estrndup(str, str_len); YOUREXT_G(strlen) = str_len; RETURN_TRUE; } PHP Extension Writing 70
  • 71. Globals Access Access Global values using YOUREXT_G(v) macro  PHP_FUNCTION(yourext_get_string) { if (YOUREXT_G(str)) { RETURN_STRINGL(YOUREXT_G(str), YOUREXT_G(strlen), 1); } else { RETURN_EMPTY_STRING(); } } PHP Extension Writing 71
  • 72. Registering consts Register constants during MINIT (usually)   name_len here is sizeof()  Thus name must be a real string int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC); REGISTER_LONG_CONSTANT(name, lval, flags) REGISTER_DOUBLE_CONSTANT(name, dval, flags) REGISTER_STRING_CONSTANT(name, str, flags) REGISTER_STRINGL_CONSTANT(name, str, len, flags) int zend_register_constant(zend_constant *c TSRMLS_DC); /* Case-sensitive */ #define CONST_CS (1<<0) /* Persistent */ #define CONST_PERSISTENT (1<<1) PHP Extension Writing 72
  • 73. Registering consts Persistent constants require CONST_PERSISTENT  Non­persistent string constants must be estrdup'd  PHP_MINIT_FUNCTION(yourext) { REGISTER_LONG_CONSTANT(quot;YOUREXT_CONSTNAMEquot;, 42, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT(quot;YOUREXT_VERSIONquot;, quot;$ID: $quot;, CONST_CS | CONST_PERSISTENT); return SUCCESS; } PHP_RINIT_FUNCTION(yourext) { REGISTER_LONG_CONSTANT(quot;YOUREXT_COUNTERquot;, YOUREXT_G(counter), CONST_CS); return SUCCESS; } PHP Extension Writing 73
  • 74. MINFO Provide some information about your extension   MINFO has no return value PHP_MINFO_FUNCTION(yourext) { php_info_print_table_start(); php_info_print_table_header(2, quot;YourExtquot;,quot;enabledquot;); php_info_print_table_row(2, quot;Versionquot;, quot;$ID: $quot;); php_info_print_table_row(2, quot;Somestringquot;, YOUREXT_G(str)); php_info_print_table_end(); } PHP Extension Writing 74
  • 75. What else ? INI Handling  Dealing with resources and streams  Object support  PHP Extension Writing 75
  • 76. Part III Adding objects How to create your own classes  How to create interfaces  How to create methods  What can be overloaded  PHP Extension Writing 76
  • 77. What is needed? Providing methods  Providing a zend_class_entry pointer  Providing object handlers  Registering the class  PHP Extension Writing 77
  • 78. 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 PHP Extension Writing 78
  • 79. 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 PHP Extension Writing 79
  • 80. 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  zend_class_entry *util_ce_dir; PHP_MINIT_FUNCTION(util) /* {{{ */ { zend_class_entry ce; INIT_CLASS_ENTRY(ce, quot;dirsquot;, util_dir_class_functions); util_ce_dir = zend_register_internal_class(&ce TSRMLS_CC); util_ce_dir->create_object = util_dir_object_new; memcpy(&util_dir_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); util_dir_handlers.clone_obj = util_dir_object_clone; zend_class_implements(util_ce_dir TSRMLS_CC, 1, zend_ce_iterator); util_ce_dir->ce_flags |= ZEND_ACC_FINAL_CLASS; util_ce_dir->get_iterator = util_dir_get_iterator; return SUCCESS; } /* }}} */ PHP Extension Writing 80
  • 81. Declaring class constants You can register class constants   Use target zend_class_entry pointer  Use sizeof() not strlen() for const name int zend_declare_class_constant(zend_class_entry *ce, char *name, size_t name_len, zval *value TSRMLS_DC); int zend_declare_class_constant_long(zend_class_entry *ce, char *name, size_t name_len, long value TSRMLS_DC); int zend_declare_class_constant_bool(zend_class_entry *ce, char *name, size_t name_len, zend_bool value TSRMLS_DC); int zend_declare_class_constant_double(zend_class_entry *ce, char *name, size_t name_len, double value TSRMLS_DC); int zend_declare_class_constant_stringl(zend_class_entry *ce, char *name, size_t name_len, char *val, size_t val_len TSRMLS_DC); int zend_declare_class_constant_string(zend_class_entry *ce, char *name, size_t name_len, char *value TSRMLS_DC); PHP Extension Writing 81
  • 82. Declaring methods /* declare method parameters, */ static ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0) ZEND_ARG_INFO(0, path) /* parameter name */ ZEND_END_ARG_INFO(); /* each method can have its own parameters and visibility */ static zend_function_entry util_dir_class_functions[] = { PHP_ME(dir, __construct, arginfo_dir___construct, ZEND_ACC_CTOR | ZEND_ACC_PUBLIC) PHP_ME(dir, rewind, NULL, ZEND_ACC_PUBLIC) PHP_ME(dir, hasMore, NULL, ZEND_ACC_PUBLIC) PHP_ME(dir, key, NULL, ZEND_ACC_PUBLIC) PHP_ME(dir, current, NULL, ZEND_ACC_PUBLIC) PHP_ME(dir, next, NULL, ZEND_ACC_PUBLIC) PHP_ME(dir, getPath, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; PHP Extension Writing 82
  • 83. 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 /* declare the class handlers */ static zend_object_handlers util_dir_handlers; /* decalre the class entry */ static zend_class_entry *util_ce_dir; /* the overloaded class structure */ /* overloading the structure results in the need of having dedicated creatin/cloning/destruction functions */ typedef struct _util_dir_object { Inherit zend_object by placing it as zend_object std; first member of your object struct php_stream *dirp; php_stream_dirent entry; char *path; int index; } util_dir_object; PHP Extension Writing 83
  • 84. 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  zend_object_value util_dir_object_new(zend_class_entry *ce TSRMLS_DC) { zend_object_value retval; util_dir_object *intern; intern = ecalloc(1, sizeof(util_dir_object)); zend_object_std_init(&(intern->std), ce TSRMLS_CC); zend_hash_copy(intern->std.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, util_dir_object_dtor, NULL TSRMLS_CC); retval.handlers = &util_dir_handlers; return retval; } PHP Extension Writing 84
  • 85. Object destruction Free properties  Free all resources and free all allocated memory  Free memory for object itself  /* {{{ util_dir_object_dtor */ /* close all resources and the memory allocated for the object */ static void util_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) { util_dir_object *intern = (util_dir_object *)object; zend_object_std_dtor(&(intern->std) TSRMLS_CC); if (intern->path) { efree(intern->path); } if (intern->dirp) { php_stream_close(intern->dirp); } efree(object); } /* }}} */ PHP Extension Writing 85
  • 86. A simple method Macro getThis() gives you access to $this as zval  The returned zval is used to get your struct  /* {{{ proto string dir::key() Return current dir entry */ PHP_METHOD(dir, key) { zval *object = getThis(); util_dir_object *intern = (util_dir_object*) zend_object_store_get_object(object TSRMLS_CC); if (intern->dirp) { RETURN_LONG(intern->index); } else { RETURN_FALSE; } } /* }}} */ PHP Extension Writing 86
  • 87. 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. /* {{{ proto void dir::__construct(string path) Constructs a new dir iterator from a path. */ PHP_METHOD(dir, __construct) { util_dir_object *intern; char *path; int len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, quot;squot;, &path, &len) == SUCCESS) { intern = (util_dir_object*) zend_object_store_get_object(getThis() TSRMLS_CC); util_dir_open(intern, path TSRMLS_CC); } } /* }}} */ PHP Extension Writing 87
  • 88. 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  /* {{{ proto void dir::__construct(string path) Constructs a new dir iterator from a path. */ PHP_METHOD(dir, __construct) { util_dir_object *intern; char *path; int len; php_set_error_handling(EH_THROW, zend_exception_get_default() TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, quot;squot;, &path, &len) == SUCCESS) { intern = (util_dir_object*) zend_object_store_get_object(getThis() TSRMLS_CC); util_dir_open(intern, path TSRMLS_CC); } php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ PHP Extension Writing 88
  • 89. Object casting /* {{{ */ static int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) { zval *retval == NULL; if (type == IS_STRING) { zend_call_method_with_0_params(&readobj, NULL, NULL, quot;__tostringquot;, &retval); if (retval) { if (Z_TYPE_P(retval) != IS_STRING) { zend_error(E_ERROR, quot;Method %s::__toString() mustquot; quot; return a string valuequot;, Z_OBJCE_P(readobj)->name); } } else { MAKE_STD_ZVAL(retval); ZVAL_EMPTY_STRING(retval); } ZVAL_ZVAL(writeobj, retval, 1, 1); INIT_PZVAL(writeobj); } return retval ? SUCCESS : FAILURE; } /* }}} */ PHP Extension Writing 89
  • 90. Other handlers to overload Objects can overload several handlers   Array access  Property access  Serializing PHP Extension Writing 90
  • 91. zend_object_handlers typedef struct _zend_object_handlers { /* general object functions */ zend_object_add_ref_t add_ref; Don't touch these zend_object_del_ref_t del_ref; zend_object_delete_obj_t delete_obj; /* individual object functions */ zend_object_clone_obj_t clone_obj; zend_object_read_property_t read_property; zend_object_write_property_t write_property; zend_object_read_dimension_t read_dimension; zend_object_write_dimension_t write_dimension; zend_object_get_property_ptr_ptr_t get_property_ptr_ptr; zend_object_get_t get; zend_object_set_t set; zend_object_has_property_t has_property; Keep or zend_object_unset_property_t unset_property; zend_object_unset_dimension_t unset_dimension; inherit zend_object_get_properties_t get_properties; zend_object_get_method_t get_method; zend_object_call_method_t call_method; zend_object_get_constructor_t get_constructor; zend_object_get_class_entry_t get_class_entry; zend_object_get_class_name_t get_class_name; zend_object_compare_t compare_objects; zend_object_cast_t cast_object; zend_object_count_elements_t count_elements; PHP Extension Writing 91 } zend_object_handlers;
  • 92. What else ? Iterator support  PHP Extension Writing 92
  • 93. Part IV Adding Iterators to objects Provide an iterator structure  Provide the handlers  Provide an iterator creator function  PHP Extension Writing 93
  • 94. Iterators /* define an overloaded iterator structure */ typedef struct { zend_object_iterator intern; zval *current; } util_dir_it; static void util_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC); static int util_dir_it_valid(zend_object_iterator *iter TSRMLS_DC); static void util_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); static int util_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); static void util_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC); static void util_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC); /* iterator handler table */ zend_object_iterator_funcs util_dir_it_funcs = { util_dir_it_dtor, util_dir_it_valid, util_dir_it_current_data, util_dir_it_current_key, util_dir_it_move_forward, util_dir_it_rewind, NULL /* invalidate current */ }; /* }}} */ PHP Extension Writing 94
  • 95. Creating the iterator Allocate and initialize the iterator structure  It is a good idea to increase the original zvals refcount  /* {{{ util_dir_get_iterator */ zend_object_iterator *util_dir_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC) { util_dir_it *iterator = emalloc(sizeof(util_dir_it)); object->refcount++; iterator->intern.data = (void*)object; iterator->intern.funcs = &util_dir_it_funcs; iterator->current = NULL; return (zend_object_iterator*)iterator; } /* }}} */ PHP Extension Writing 95
  • 96. Destructing the iterator Free allocated memory and resources  Don't forget to reduce refcount of referenced object  /* {{{ util_dir_it_dtor */ static void util_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC) { util_dir_it *iterator = (util_dir_it *)iter; zval *intern = (zval*)iterator->intern.data; if (iterator->current) { zval_ptr_dtor(&iterator->current); } zval_ptr_dtor(&intern); efree(iterator); } /* }}} */ PHP Extension Writing 96
  • 97. Getting the data Data is read on rewind() and next() calls  A zval* is stored inside the iterator  Release current zval  Create a new zval and assign the value  /* {{{ util_dir_it_current */ static void util_dir_it_current(util_dir_it *iterator, util_dir_object *object TSRMLS_DC) { if (iterator->current) { zval_ptr_dtor(&iterator->current); } MAKE_STD_ZVAL(iterator->current); if (object->dirp) { ZVAL_STRING(iterator->current, object->entry.d_name, 1); } else { ZVAL_FALSE(iterator->current); } } /* }}} */ PHP Extension Writing 97
  • 98. Iterator valid() Check whether more data is available  Note: Return SUCCESS or FAILURE not typical boolean /* {{{ util_dir_it_valid */ static int util_dir_it_valid(zend_object_iterator *iter TSRMLS_DC) { util_dir_it *iterator = (util_dir_it *)iter; util_dir_object *object = (util_dir_object*) zend_object_store_get_object( (zval*)iterator->intern.data TSRMLS_CC); return object->dirp && object->entry.d_name[0] != '0' ? SUCCESS : FAILURE; } /* }}} */ PHP Extension Writing 98
  • 99. Iterator key() The key may be one of:   Integer: HASH_KEY_IS_LONG Set ulong * to the integer value  String: HASH_KEY_IS_STRING Set uint * to string length + 1  Set char ** to copy of string (estr[n]dup) /* {{{ util_dir_it_current_key */ static int util_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) { util_dir_it *iterator = (util_dir_it *)iter; zval *intern = (zval*)iterator->intern.data; util_dir_object *object = (util_dir_object*) zend_object_store_get_object(intern TSRMLS_CC); *int_key = object->index; return HASH_KEY_IS_LONG; } /* }}} */ PHP Extension Writing 99
  • 100. Iterator current() The data was already fetched on rewind() / next()  /* {{{ util_dir_it_current_data */ static void util_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) { util_dir_it *iterator = (util_dir_it *)iter; *data = &iterator->current; } /* }}} */ PHP Extension Writing 100
  • 101. Iterator current() The data was already fetched on rewind() / next()  Alternatively   Reset the cached current/key value in rewind() / next()  Check the cache on access and read if not yet done /* {{{ util_dir_it_current_data */ static void util_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) { util_dir_it *iterator = (util_dir_it *)iter; util_dir_object *object; if (!iterator->current) { object = (util_dir_object*)zend_object_store_get_object( (zval*)iterator->intern.data TSRMLS_CC); util_dir_it_current(iterator, object TSRMLS_CC); } *data = &iterator->current; } /* }}} */ PHP Extension Writing 101
  • 102. Iterator next() Move to next element  Fetch new current data  /* {{{ util_dir_it_move_forward */ static void util_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC) { util_dir_it *iterator = (util_dir_it *)iter; zval *intern = (zval*)iterator->intern.data; util_dir_object *object = (util_dir_object*) zend_object_store_get_object(intern TSRMLS_CC); object->index++; if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) { object->entry.d_name[0] = '0'; } util_dir_it_current(iterator, object TSRMLS_CC); } /* }}} */ PHP Extension Writing 102
  • 103. Iterator rewind() Rewind to first element  Fetch first current data  /* {{{ util_dir_it_rewind */ static void util_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC) { util_dir_it *iterator = (util_dir_it *)iter; zval *intern = (zval*)iterator->intern.data; util_dir_object *object = (util_dir_object*) zend_object_store_get_object(intern TSRMLS_CC); object->index = 0; if (object->dirp) { php_stream_rewinddir(object->dirp); } if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) { object->entry.d_name[0] = '0'; } util_dir_it_current(iterator, object TSRMLS_CC); } /* }}} */ PHP Extension Writing 103
  • 104. Iterator drawbacks Either implement native iterators at c­level  Or provide iterator methods and inherit Iterator  If you want both   Your PHP methods call a specialized C­Level handler  Provide a cache for your method pointers  C­Level iterator functions check this cache  On a match call C­Level handler  Else call the method  Have the iterator struct part of your object struct  Use offset_of() for pointer conversion PHP Extension Writing 104
  • 105. References This presentation  http://talks.somabo.de Documentation and Sources to PHP5  http://php.net http://www.zend.com/php/internals  Advanced PHP Programming   by George Schlossnagle Extending and Embedding PHP  by Sara Golemon ISBN#0­6723­2704­X PHP Extension Writing 105