Extending PHP (7.x) How to, when and when not
Pierre Joye @pierrejoye pierre@php.net http://www.slideshare.net/pierrej PHP Core developer Contributors to numerous OSS projects Portability fan
hiring@BK K
When to use custom extensions?
PHP 7 is fast.
PHP will be even faster.
OpCache rocks.
IOs are slow.
Streams are easy.
File Ops are easy.
zval • Integer > zend_long • Booleans > types, IS_TRUE/IS_FALSE • Strings > zend_string • Float > double • Object > zend_object • Resource Hash Tables • Array (zval > array > hash table) • Functions table • Classes, properties, etc. Classes • Classes declaration
Zend/zend_types.h your best friend.
typedef struct _zval_struct zval; struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* call info for EX(This)*/ } v; uint32_t type_info; } u1; .... };
Hash tables
Hash tables are not arrays!
Hash tables elements can contain ANYTHING
Zend/zend_hash.h Your second best buddy
Let get started
Requirements *nix • Common • A shell • editor • Gcc 5+ • php7-dev • Autoconf, autotools and co
Requirements Windows • Common • A shell • php-sdk (http://windows.php.net/downloads/php-sdk/) • vc (14+) for Windows • php binary tools (http://windows.php.net/downloads/php-sdk/) • Setup your sdk structure according to https://wiki.php.net/internals/windows/stepbystepbuild
Extension directory structure myext config.w32 Build script for windows config.m4 Build script for *nix php_myext.c Implementation php_myext.h Interface & meta data Tests myext tests myext.phpt
config.w32 // $Id$ // vim:ft=javascript ARG_ENABLE("myext", "myext support", "yes"); if (PHP_MYEXT == "yes") { EXTENSION("myext", "php_myext.c"); }
config.m4 dnl Tell PHP about the argument to enable the hello extension PHP_ARG_ENABLE(myext, Whether to enable the myext extension, [ --enable-myext Enable myext]) if test "$PHP_MYEXT" != "no"; then PHP_NEW_EXTENSION(myext, php_myext.c, $ext_shared) fi
Our first function function myext_hello() { echo "Hello Manila!"; }
php_myext.h #define PHP_MYEXT_EXTNAME "myext“ #define PHP_MYEXT_VERSION "0.0.1" PHP_FUNCTION(myext_hello);
php_myext.c #include <php.h> #include "php_myext.h" include php common interfaces and types
php_myext.c Define myext_hello functions and commons hooks&data for myext zend_function_entry myext_functions[] = { PHP_FE(myext_hello, NULL) PHP_FE_END }; zend_module_entry myext_module_entry = { STANDARD_MODULE_HEADER, PHP_MYEXT_EXTNAME, myext_functions, NULL, NULL, NULL, NULL, NULL, PHP_MYEXT_VERSION, STANDARD_MODULE_PROPERTIES, };
zend_value Define myext_hello functions and commons hooks&data for myext typedef union _zend_value { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; }ww; } zend_value;
php_myext.c print „Hello Manilla!n“ to php standard output PHP_FUNCTION(myext_hello) { php_printf("Hello Manila!n"); };
First build All platforms: $ phpize $ configure –enable-myext For *nix flavors: $ make For Windows: $ nmake
first function, with a string argument function myext_print(string $mystring) { echo "Hello " . $mystring . "!n"; }
first function, with a string argument PHP_FUNCTION(myext_print) { char *mystring; size_t mystring_len; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &mystring, &mystring_len) == FAILURE) { return; } php_printf("Hello %s!! (%i)n", mystring, mystring_len); return }
first function, with an integer argument function myext_integer(int $myint) { if ($myint > 0) { for ($i = 0; $i < $myint; $i++) { echo "Hello " . $i . "!n"; } } }
first function, with an integer argument PHP_FUNCTION(myext_print_integer) { zend_long lval; int i; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &lval) == FAILURE) { return; } if (lval > 0) { for (i=0; i < lval; i++) { php_printf("Hello %in",i); } } return; }
first function, with an array argument function myext_print_array(array $myarray) { foreach ($myarray as $val) { echo "hello ". $val . "n"; } }
first function, with an array argument PHP_FUNCTION(myext_print_array) { zval *myarray = NULL; zend_string *key; zend_ulong num_key; zval *val; if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &myarray) == FAILURE) { return; } ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(myarray), num_key, key, val) { php_printf("Hello %sn", Z_STRVAL_P(val)); } ZEND_HASH_FOREACH_END(); return; }
home work • First class • Zend Memory Manager • Use tools like valgrind • Use external libraries • Debugging using gdb or vs debugger
resources • https://wiki.php.net/phpng-upgrading • https://nikic.github.io/ • https://wiki.php.net/internals/ • http://www.phpinternalsbook.com/ • http://jpauli.github.io/ • https://github.com/php/php-src

Extending php (7), the basics