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
  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/
  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
  4. Workshop overview • Brief reminders about PHP architecture • Configure

    your environment • Grab the example extension • Do some exercises while seeing a bit of theory
  5. 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
  6. 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
  7. Compilation Prepare build environment: 1. $ phpize Configure the extension:

    2. $ ./configure Compile it: 3. $ make Install it (may require root): 4. $ make install
  8. Verify installation $ php -d extension=myext.so -m You should see

    “myext” as part of the loaded extensions.
  9. 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
  10. Exercise one: fibonacci (2/7) function fibo($n) { switch ($n) {

    case 0: case 1: return $n; } return fibo($n-2) + fibo($n-1); }
  11. Exercise one: fibonacci (7/7) Compile: $ make Install: $ make

    install Test: $ php -d extension=myext.so \ -r 'echo fibonacci(35), “\n”;' 9227465
  12. Exercise one: fibonacci solution The full changes required to implement

    the fibonacci function are available at: http://tinyurl.com/PHP-ext-fibonacci
  13. 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.
  14. 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
  15. 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)
  16. 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;
  17. 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
  18. 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
  19. 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
  20. 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);
  21. 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"); } }
  22. 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
  23. PHP life cycles – Web server (prefork) • Credits: Extending

    and Embedding PHP by Sara Golemon (2006 June 9th)
  24. PHP life cycles - Web server (multi thread) • Credits:

    Extending and Embedding PHP by Sara Golemon (2006 June 9th)
  25. 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
  26. 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();
  27. 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