Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Create your own PHP extension, step by step

Create your own PHP extension, step by step

Workshop given at PHP NorthWest 2012 in Manchester with Derick Rethans and Anthony Ferrara

Patrick Allaert

October 05, 2012
Tweet

More Decks by Patrick Allaert

Other Decks in Programming

Transcript

  1. Create your own PHP extension, step by step
    Patrick Allaert, Derick Rethans
    PHPNW 2012 Manchester, United Kingdom

    View Slide

  2. Patrick Allaert

    Founder of Libereco Technologies

    Playing with PHP/Linux for +10 years

    eZ Publish core developer

    Author of the APM PHP extension

    @patrick_allaert

    [email protected]

    http://github.com/patrickallaert/

    http://patrickallaert.blogspot.com/

    View Slide

  3. Derick Rethans

    Dutchman living in London

    PHP Engineer/Evangelist for 10gen (the MongoDB
    people), where I also work on the MongoDB PHP
    driver.

    Author of Xdebug

    Author of the mcrypt, input_filter, dbus, translit
    and date/time extensions

    View Slide

  4. Workshop overview

    Brief reminders about PHP architecture

    Configure your environment

    Grab the example extension

    Do some exercises while seeing a bit of theory

    View Slide

  5. PHP architecture

    View Slide

  6. Configuring your environment

    Debian-like:
    $ sudo apt-get install php5-dev

    View Slide

  7. Download the sample extension
    a) Using git:
    $ git clone
    git://github.com/patrickallaert/
    PHP_Extension_Workshop.git
    b) Download archive at:
    https://github.com/patrickallaert/PHP_Extension_Wo
    rkshop/downloads

    View Slide

  8. Minimal C code (myext.c)
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    #include "php.h"
    #include "php_ini.h"
    #include "ext/standard/info.h"
    #include "php_myext.h"
    zend_module_entry myext_module_entry = {
    STANDARD_MODULE_HEADER,
    "myext",
    NULL, /* Function entries */
    NULL, /* Module init */
    NULL, /* Module shutdown */
    NULL, /* Request init */
    NULL, /* Request shutdown */
    NULL, /* Module information */
    "0.1", /* Replace with version number for your extension */
    STANDARD_MODULE_PROPERTIES
    };
    #ifdef COMPILE_DL_MYEXT
    ZEND_GET_MODULE(myext)
    #endif

    View Slide

  9. Compilation
    Prepare build environment:
    1. $ phpize
    Configure the extension:
    2. $ ./configure
    Compile it:
    3. $ make
    Install it (may require root):
    4. $ make install

    View Slide

  10. Verify installation
    $ php -d extension=myext.so -m
    You should see “myext” as part of the loaded
    extensions.

    View Slide

  11. Minimal config.m4
    dnl config.m4 for myext
    PHP_ARG_ENABLE(myext, whether to enable myext
    support,
    [ --enable-myext Enable myext support])
    if test "$PHP_MYEXT" != "no"; then
    PHP_NEW_EXTENSION(myext, myext.c,
    $ext_shared)
    fi

    View Slide

  12. Exercise one: fibonacci (1/7)

    F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1

    View Slide

  13. Exercise one: fibonacci (2/7)
    function fibo($n) {
    switch ($n)
    {
    case 0:
    case 1:
    return $n;
    }
    return fibo($n-2) + fibo($n-1);
    }

    View Slide

  14. Exercise one: fibonacci (3/7)

    View Slide

  15. Exercise one: fibonacci (4/7)

    View Slide

  16. Exercise one: fibonacci (5/7)

    View Slide

  17. Exercise one: fibonacci (6/7)

    View Slide

  18. Exercise one: fibonacci (7/7)
    Compile:
    $ make
    Install:
    $ make install
    Test:
    $ php -d extension=myext.so \
    -r 'echo fibonacci(35), “\n”;'
    9227465

    View Slide

  19. Exercise one: fibonacci solution
    The full changes required to implement the fibonacci
    function are available at:
    http://tinyurl.com/PHP-ext-fibonacci

    View Slide

  20. zend_parse_parameters

    Handles the conversion of PHP userspace variables
    into C ones.

    Generate errors in the case of missing parameters
    or if the type is wrong.

    View Slide

  21. zend_parse_parameters

    Second parameter describes
    the type of the parameter(s)
    as a string composed of
    characters having all a
    special meaning.

    To mark the start of optional
    parameter(s), a pipe (“|”)
    character is used.
    Type Cod
    e
    Variable type
    Boolean b zend_bool
    Long l long
    Double d double
    String s char *, int (length)
    Path p char *, int (length)
    Class
    name
    C zend_class_entry*
    Resource r zval*
    Array a zval*
    Object o zval*
    zval z zval*
    Zval
    pointer
    Z zval**
    Callback f zend_fcall_info,
    zend_fcall_info_cache

    View Slide

  22. zend_parse_parameters examples

    sleep(), usleep(), func_get_arg():
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
    &long)

    bin2hex(), quotemeta(), ord(), ucfirst():
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
    &str, &str_len)

    str*pos():
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l",
    &haystack, &haystack_len, &needle, &offset)

    var_dump():
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+",
    &args, &argc)

    file_put_contents()
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pz/|
    lr!", &filename, &filename_len, &data, &flags,
    &zcontext)

    View Slide

  23. OpenGrok (1/2)

    Your best friend to browse PHP's source code:
    http://lxr.php.net/

    View Slide

  24. OpenGrok (2/2)

    View Slide

  25. zval (=== _zval_struct)
    struct _zval_struct {
    /* Variable information */
    zvalue_value value; /* value */
    zend_uint refcount__gc;
    zend_uchar type; /* active type */
    zend_uchar is_ref__gc;
    };
    typedef union _zvalue_value {
    long lval; /* long value */
    double dval; /* double value */
    struct {
    char *val;
    int len;
    } str;
    HashTable *ht; /* hash table value */
    zend_object_value obj;
    } zvalue_value;

    View Slide

  26. Types

    IS_NULL

    IS_LONG

    IS_DOUBLE

    IS_BOOL

    IS_ARRAY

    IS_OBJECT

    IS_STRING

    IS_RESOURCE

    IS_CONSTANT

    IS_CONSTANT_ARRAY

    IS_CALLABLE

    http://lxr.php.net/xref/PHP_TRUNK/Zend/zend.h#IS_NULL

    View Slide

  27. Access macros
    Z_TYPE(zval) (zval).type
    Z_LVAL(zval) (zval).value.lval
    Z_BVAL(zval) ((zend_bool)(zval).value.lval)
    Z_DVAL(zval) (zval).value.dval
    Z_STRVAL(zval) (zval).value.str.val
    Z_STRLEN(zval) (zval).value.str.len
    Z_ARRVAL(zval) (zval).value.ht
    Z_OBJVAL(zval) (zval).value.obj
    Z_OBJ_HANDLE(zval) Z_OBJVAL(zval).handle
    Z_OBJ_HT(zval) Z_OBJVAL(zval).handlers
    Z_RESVAL(zval) (zval).value.lval
    Z_TYPE_P(zval_p) Z_TYPE(*zval_p)
    Z_LVAL_P(zval_p) Z_LVAL(*zval_p)
    Z_BVAL_P(zval_p) Z_BVAL(*zval_p)
    Z_DVAL_P(zval_p) Z_DVAL(*zval_p)
    Z_STRVAL_P(zval_p) Z_STRVAL(*zval_p)
    Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p)
    Z_ARRVAL_P(zval_p) Z_ARRVAL(*zval_p)
    Z_RESVAL_P(zval_p) Z_RESVAL(*zval_p)
    Z_OBJVAL_P(zval_p) Z_OBJVAL(*zval_p)
    Z_OBJ_HANDLE_P(zval_p) Z_OBJ_HANDLE(*zval_p)
    Z_OBJ_HT_P(zval_p) Z_OBJ_HT(*zval_p)
    http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_operators.h#Z_LVAL

    View Slide

  28. Exercise two: my_dump($val) (1/2)

    Create a very simple my_dump($val) function:

    my_dump(null); // null value!

    my_dump(42); // Long: 42

    my_dump(123.456); // Double: 123.456

    my_dump(true); // Boolean: true

    my_dump(“hello”); // String: hello

    View Slide

  29. Exercise two: my_dump($val) (2/2)

    Hints:

    Define a pointer to a zval:
    zval *val;

    Use “z” with zend_parse_parameters()

    Switch/case based on the type of val
    (Z_TYPE_P(uservar))

    Use php_printf() to print, except for strings from zval,
    since they may contain NULL characters:
    PHPWRITE(const char *, size_t);

    View Slide

  30. Exercise two: solution
    PHP_FUNCTION(my_dump) {
    zval *val;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", val) ==
    FAILURE) {
    return;
    }
    switch (Z_TYPE_P(val)) {
    case IS_NULL:
    php_printf("NULL");
    break;
    case IS_BOOL:
    php_printf("Boolean: %s", Z_LVAL_P(val) ? "true" : "false");
    break;
    case IS_LONG:
    php_printf("Long: %ld", Z_LVAL_P(val));
    break;
    case IS_DOUBLE:
    php_printf("Double: %f", Z_DVAL_P(val));
    break;
    case IS_STRING:
    php_printf("String: ");
    PHPWRITE(Z_STRVAL_P(val), Z_STRLEN_P(val));
    break;
    default:
    php_printf("Not supported");
    }
    }

    View Slide

  31. PHP life cycles

    4 functions (2 initializations, 2 shutdowns ones) let
    you do stuff at specific moments of the PHP life
    cycles:

    PHP_MINIT_FUNCTION

    PHP_MSHUTDOWN_FUNCTION

    PHP_RINIT_FUNCTION

    PHP_RSHUTDOWN_FUNCTION

    View Slide

  32. PHP life cycles - CLI

    Credits: Extending and Embedding PHP by Sara Golemon (2006 June 9th)

    View Slide

  33. PHP life cycles – Web server
    (prefork)

    Credits: Extending and Embedding PHP by Sara Golemon (2006 June 9th)

    View Slide

  34. PHP life cycles - Web server
    (multi thread)

    Credits: Extending and Embedding PHP by Sara Golemon (2006 June 9th)

    View Slide

  35. Exercise three: MyClass (1/10)

    Steps:

    Create a class named “MyClass”

    Create a class constant

    Add some properties with various visibilities/modifiers

    Add some methods

    View Slide

  36. Exercise three: MyClass (2/10)

    View Slide

  37. Exercise three: MyClass (3/10)

    http://tinyurl.com/PHP-ext-MyClass-1

    View Slide

  38. Exercise three: MyClass (4/10)

    Declaring a class constant can be made from a C type:

    zend_declare_class_constant_null();

    zend_declare_class_constant_long();

    zend_declare_class_constant_bool();

    zend_declare_class_constant_double();

    zend_declare_class_constant_stringl();

    zend_declare_class_constant_string();

    Or from a zval:

    zend_declare_class_constant();

    View Slide

  39. Exercise three: MyClass (5/10)

    http://tinyurl.com/PHP-ext-MyClass-2

    View Slide

  40. Exercise three: MyClass (6/10)

    Creating class properties can be made from a C type:

    zend_declare_property_long();

    zend_declare_property_bool();

    zend_declare_property_double();

    zend_declare_property_stringl();

    zend_declare_property_string();

    Or from a zval:

    zend_declare_property();

    Visibility:

    ZEND_ACC_PUBLIC, ZEND_ACC_PROTECTED, ZEND_ACC_PRIVATE

    Modifiers:

    ZEND_ACC_STATIC, ZEND_ACC_ABSTRACT, ZEND_ACC_FINAL

    View Slide

  41. Exercise three: MyClass (7/10)

    http://tinyurl.com/PHP-ext-MyClass-3

    View Slide

  42. Exercise three: MyClass (8/10)

    View Slide

  43. Exercise three: MyClass (9/10)

    View Slide

  44. Exercise three: MyClass (10/10)

    http://tinyurl.com/PHP-ext-MyClass-4

    View Slide

  45. Questions?

    View Slide

  46. Thanks

    Don't forget to rate this workshop on https://joind.in/7070

    View Slide