Building Custom PHP Extensions

4,986 views

Published on

Published in: Technology

Building Custom PHP Extensions

  1. 1. Building Custom PHP Extensions International PHP Conference 2012 Tbilisi, GeorgiaWednesday, December 12, 12
  2. 2. About me ‣ Ioseb Dzmanashvili ‣ Software Architect at AzRy LLC ‣ Teacher at Caucasus School of Technology ‣ V8 JavaScript engine contributor ‣ Author of uri_template PHP extension ‣ Author of Create-Form and Edit-Form link relation types (being RFCed now).Wednesday, December 12, 12
  3. 3. This talk covers ‣ Setting up development environment ‣ Creating extension skeletons with automated tools ‣ Building and installing extensions ‣ Internals such as: ‣ Implementing and exposing C functions ‣ PHP parameter parsing ‣ VariablesWednesday, December 12, 12
  4. 4. This talk doesn’t cover ‣ Thread safety topics ‣ Networking ‣ Object oriented programming ‣ Stream wrappers ‣ MemoryWednesday, December 12, 12
  5. 5. My Experience ‣ URI Template Pecl extension ‣ https://github.com/ioseb/uri-template ‣ Available from Pecl channel ‣ http://pecl.php.net/package/uri_template ‣ Used by Guzzle HTTP client library and Drupal 8Wednesday, December 12, 12
  6. 6. What it does? ‣ Implementation of RFC6570(URI Template) ‣ Resource Identifier - URI) 100% compatibility with RFC3986 (Uniform ‣ 100% compatibility with RFC3629 (UTF-8)Wednesday, December 12, 12
  7. 7. How to use it? // URI Template Data $data = array( "id" => array("person","albums"), "token" => "12345", "fields" => array("id", "name", "picture"), ); // URI Template $template = "{/id*}{?fields,token}"; // Transformation $result = uri_template($template, $data); //Produces: /person/albums?fields=id,name,picture&token=12345Wednesday, December 12, 12
  8. 8. Why it is important? ‣ Possibility to achieve outstanding performance ‣ Possibility to learn PHP from inside outWednesday, December 12, 12
  9. 9. Preparing development environmentWednesday, December 12, 12
  10. 10. Installing PHP dev package ‣ Linux(Debian) $ sudo apt-get install php5-dev ‣ Installing with Mac Ports on Mac OS X $ sudo port install php5-devel ‣ Use XAMPP developer package as an alternative for Mac OS X (painless solution)Wednesday, December 12, 12
  11. 11. Creating extension ‣ Creating the configuration and build files ‣ Creating the header and basic C files, which includes: ‣ Creating initialization and destruction functions ‣ Including the correct headers ‣ Creating functions for use by PHP info tools ‣ Creating test filesWednesday, December 12, 12
  12. 12. Tools for creating extensions ‣ Create extension manually ‣ Use ext_skel to generate extension ‣ Use pecl-gen to generate extensionWednesday, December 12, 12
  13. 13. Generating extension with pecl-gen ‣ Install codegen_pecl $ pear install codegen_pecl ‣ Create XML descriptor for extension ‣ Generate extension skeleton $ pecl-gen hello-world.xmlWednesday, December 12, 12
  14. 14. XML descriptor (hello-world.xml) <?xml version="1.0" ?> <extension name="hello_world" version="0.1.0"> <summary>Yet another hello world PHP Extension</summary> <description> This is a sample "hello world" extension for demonstration purposes only. </description> <maintainers> <maintainer> <user>ioseb</user> <name>Ioseb Dzmanashvili</name> <email>ioseb.dzmanashvili@gmail.com</email> <role>lead</role> </maintainer> </maintainers> <license>PHP</license> <function name="hello_world" role="public"> <proto>void hello_world( string input )</proto> <summary>Prints a hello world message</summary> <code><![CDATA[ // C code goes here ]]></code> </function> </extension>Wednesday, December 12, 12
  15. 15. Generated extension structure $ tree hello_world !"" config.m4 !"" config.w32 !"" hello-world.xml !"" hello_world.c !"" manual #   !"" Makefile #   !"" file-entities.ent #   !"" functions.xml #   !"" hello-world #   #   !"" ... #   #   !"" functions #   #   #   $"" hello-world.xml #   #   !"" ini.xml #   #   $"" reference.xml #   $"" manual.xml.in !"" ... !"" php_hello_world.h $"" tests $"" hello_world.phptWednesday, December 12, 12
  16. 16. Generated hello_world() function PHP_FUNCTION(hello_world) { const char * input = NULL; int input_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &input, &input_len) == FAILURE) { return; } do { // C code goes here } while (0); }Wednesday, December 12, 12
  17. 17. Modifying hello_world() function PHP_FUNCTION(hello_world) { const char * input = NULL; int input_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &input, &input_len) == FAILURE) { return; } // our implementation php_printf("Hello world %s", input); }Wednesday, December 12, 12
  18. 18. Installing extension ‣ Prepare build environment for PHP extension $ phpize ‣ Configure it $ ./configure ‣ Compile & Install $ make && sudo make install ‣ Enable extension $ php -d extension=hello_world.so -mWednesday, December 12, 12
  19. 19. Testing hello_world() function ‣ Create test.php file ‣ Write test code <?php echo hello_world("PHP Rocks"); echo "n"; ‣ Run script $ php test.php ‣ If you see following line everything is OK $ Hello world PHP RocksWednesday, December 12, 12
  20. 20. Cleaning extension folder ‣ Get rid off compilation output $ make clean ‣ Get rid off build environment stuff $ phpize --cleanWednesday, December 12, 12
  21. 21. PHP_FUNCTIONWednesday, December 12, 12
  22. 22. PHP_FUNCTION expansion PHP_FUNCTION(hello_world) { // rest of code removed for brevity } expands tovoid zif_hello_world( zval *return_value, // 1) variable to store return value char return_value_used, // 2) if returned value was used zval *this_ptr TSRMLS_DC // 3) pointer to objects internal state)Wednesday, December 12, 12
  23. 23. Exposing internal function function_entry hello_world_functions[] = { PHP_FE(hello_world, hello_world_arg_info) { NULL, NULL, NULL } }; expands to function_entry hello_world_functions[] = { {"hello_world", zif_hello_world, hello_world_arg_info}, { NULL, NULL, NULL } };Wednesday, December 12, 12
  24. 24. Parsing Function Parameters PHP_FUNCTION(hello_world) { const char *input = NULL; // variable to store parameter value int input_len = 0; // variable to store value length if (zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, // 1) number of arguments "s", // 2) format string &input, // 3) address of *input variable &input_len // 4) address of input_len variable ) == FAILURE) { return; // just return if something goes wrong } // actual implementation php_printf("Hello world %s", input); }Wednesday, December 12, 12
  25. 25. Available Parameter Types Type Specifier C datatype PHP Type b zend_bool Boolean l long Integer d double Floating point s char*, int String r zval* Resource a zval* Array o zval* Object instance O zval*, zend_class_entry* Object of a specified type z zval* Non-specific zval Z zval** Dereferenced zvalWednesday, December 12, 12
  26. 26. Examples of parameter formats // means that function expects: // a) required long parameter // b) required string parameter // c) optional long parameter // d) optional zval of non-specific type zend_parse_parameters(..., "ls|lz", ...) // menas that function expects: // a) required array parameter // b) required array parameter // c) required string parameter // d) optional long parameter zend_parse_parameters(..., "aas|l", ...)Wednesday, December 12, 12
  27. 27. Zval _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; typedef struct _zval_struct zval;Wednesday, December 12, 12
  28. 28. Zval - Graphical Representation value long lval double dval str char *val int len HashTable *ht zend_object_value obj refcount__gc type is_ref__gcWednesday, December 12, 12
  29. 29. Internal Data Types Type Value Access Macros IS_NULL N/A IS_BOOL Z_BVAL_P(value) IS_LONG Z_LVAL_P(value) IS_DOUBLE Z_DVAL_P(value) IS_STRING Z_STRVAL_P(value), Z_STRLEN_P(value) IS_ARRAY Z_ARRVAL_P(value) IS_OBJECT Z_OBJVAL_P(value) IS_RESOURCE Z_RESVAL_P(value)Wednesday, December 12, 12
  30. 30. Zval Reader Example void display_zval(zval *value) { switch(Z_TYPE_P(value)) { case IS_NULL: php_printf("NULL"); break; case IS_BOOL: php_printf("BOOL %d", Z_BVAL_P(value) ? 1 : 0); break; case IS_LONG: php_printf("LONG %ld", Z_LVAL_P(value)); break; case IS_DOUBLE: php_printf("DOUBLE %f", Z_DVAL_P(value)); break; case IS_STRING: php_printf("STRING %s", Z_STRVAL_P(value)); break; case IS_RESOURCE: php_printf("RES #%ld", Z_RESVAL_P(value)); break; case IS_ARRAY: php_printf("ARRAY"); break; case IS_OBJECT: php_printf("OBJECT"); break; } }Wednesday, December 12, 12
  31. 31. Returning Values Type Value Access Macros ZVAL_NULL(return_value) RETVAL_NULL() ZVAL_BOOL(return_value) RETVAL_BOOL(bval) ZVAL_TRUE(return_value) RETVAL_TRUE ZVAL_FALSE(return_value) RETVAL_FALSE ZVAL_LONG(return_value, lval) RETVAL_LONG(lval) ZVAL_DOUBLE(return_value, dval) RETVAL_DOUBLE(dval) ZVAL_STRING(return_value, str, dup) RETVAL_STRING(str, dup) ZVAL_RESOURCE(return_value, rval) RETVAL_RESOURCE(rval)Wednesday, December 12, 12
  32. 32. Returning Values PHP_FUNCTION(test_function) { ZVAL_NULL(return_value) }Wednesday, December 12, 12
  33. 33. BooksWednesday, December 12, 12
  34. 34. Questions?Wednesday, December 12, 12
  35. 35. Thank You!Wednesday, December 12, 12

×