Create your own PHP extension, step by step - phpDay 2012 Verona
-
Upload
patrick-allaert -
Category
Technology
-
view
34.712 -
download
1
description
Transcript of Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by stepPatrick Allaert, Derick Rethans, Rasmus Lerdorf
phpDay 2012 Verona, Italy
Patrick Allaert● Founder of Libereco● 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/
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
Workshop overview
● Brief reminders about PHP architecture● Configure your environment● Grab the example extension● Do some exercises while seeing a bit of theory
PHP architecture
Configuring your environment
● Debian-like:
$ sudo apt-get install php5-dev
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_Workshop/downloads
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_MYEXTZEND_GET_MODULE(myext)#endif
Compilation
Prepare build environment:
1. $ phpize
Configure the extension:
2. $ ./configure
Compile it:
3. $ make
Install it (may require root):
4. $ make install
Verify installation
$ php -d extension=myext.so -m
You should see “myext” as part of the loaded extensions.
Minimal config.m4dnl 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
Exercise one: fibonacci (1/7)
● F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1
Exercise one: fibonacci (2/7)
function fibo($n) { switch ($n) { case 0: case 1: return $n; }
return fibo($n-2) + fibo($n-1);}
Exercise one: fibonacci (3/7)
Exercise one: fibonacci (4/7)
Exercise one: fibonacci (5/7)
Exercise one: fibonacci (6/7)
Exercise one: fibonacci (7/7)
Compile:
$ make
Install:
$ make install
Test:
$ php -d extension=myext.so \ -r 'echo fibonacci(35), “\n”;'
9227465
Exercise one: fibonacci solution
The full changes required to implement the fibonacci function are available at:
http://tinyurl.com/PHP-ext-fibonacci
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.
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 Code
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
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)
OpenGrok (1/2)
● Your best friend to browse PHP's source code:http://lxr.php.net/
OpenGrok (2/2)
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;
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
Access macrosZ_TYPE(zval) (zval).typeZ_LVAL(zval) (zval).value.lvalZ_BVAL(zval) ((zend_bool)(zval).value.lval)Z_DVAL(zval) (zval).value.dvalZ_STRVAL(zval) (zval).value.str.valZ_STRLEN(zval) (zval).value.str.lenZ_ARRVAL(zval) (zval).value.htZ_OBJVAL(zval) (zval).value.objZ_OBJ_HANDLE(zval) Z_OBJVAL(zval).handleZ_OBJ_HT(zval) Z_OBJVAL(zval).handlersZ_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
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
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);
Exercise two: solutionPHP_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"); }}
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
PHP life cycles - CLI
● Credits: Extending and Embedding PHP by Sara Golemon (2006 June 9th)
PHP life cycles – Web server(prefork)
● Credits: Extending and Embedding PHP by Sara Golemon (2006 June 9th)
PHP life cycles - Web server(multi thread)
● Credits: Extending and Embedding PHP by Sara Golemon (2006 June 9th)
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
Exercise three: MyClass (2/10)
Exercise three: MyClass (3/10)
● http://tinyurl.com/PHP-ext-MyClass-1
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();
Exercise three: MyClass (5/10)
● http://tinyurl.com/PHP-ext-MyClass-2
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
Exercise three: MyClass (7/10)
● http://tinyurl.com/PHP-ext-MyClass-3
Exercise three: MyClass (8/10)
Exercise three: MyClass (9/10)
Exercise three: MyClass (10/10)
● http://tinyurl.com/PHP-ext-MyClass-4
Questions?
Thanks● Don't forget to rate this workshop on https://joind.in/6386