35
Building Custom PHP Extensions International PHP Conference 2012 Tbilisi, Georgia Wednesday, December 12, 12

Building Custom PHP Extensions

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Building Custom PHP Extensions

Building Custom PHPExtensions

International PHP Conference 2012 Tbilisi, GeorgiaWednesday, December 12, 12

Page 2: Building Custom PHP Extensions

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

Page 3: Building Custom PHP Extensions

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

‣ Variables

Wednesday, December 12, 12

Page 4: Building Custom PHP Extensions

This talk doesn’t cover

‣Thread safety topics

‣Networking

‣Object oriented programming

‣Stream wrappers

‣Memory

Wednesday, December 12, 12

Page 5: Building Custom PHP Extensions

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 8

Wednesday, December 12, 12

Page 6: Building Custom PHP Extensions

What it does?

‣ Implementation of RFC6570(URI Template)

‣100% compatibility with RFC3986 (Uniform Resource Identifier - URI)

‣100% compatibility with RFC3629 (UTF-8)

Wednesday, December 12, 12

Page 7: Building Custom PHP Extensions

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=12345

Wednesday, December 12, 12

Page 8: Building Custom PHP Extensions

Why it is important?

‣ Possibility to achieve outstanding performance

‣ Possibility to learn PHP from inside out

Wednesday, December 12, 12

Page 9: Building Custom PHP Extensions

Preparing development environment

Wednesday, December 12, 12

Page 10: Building Custom PHP Extensions

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

Page 11: Building Custom PHP Extensions

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 files

Wednesday, December 12, 12

Page 12: Building Custom PHP Extensions

Tools for creating extensions

‣Create extension manually

‣Use ext_skel to generate extension

‣Use pecl-gen to generate extension

Wednesday, December 12, 12

Page 13: Building Custom PHP Extensions

Generating extension with pecl-gen

‣ Install codegen_pecl

$ pear install codegen_pecl

‣Create XML descriptor for extension

‣Generate extension skeleton

$ pecl-gen hello-world.xml

Wednesday, December 12, 12

Page 14: Building Custom PHP Extensions

<?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>[email protected]</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>

XML descriptor (hello-world.xml)

Wednesday, December 12, 12

Page 15: Building Custom PHP Extensions

!"" 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.phpt

Generated extension structure$ tree hello_world

Wednesday, December 12, 12

Page 16: Building Custom PHP Extensions

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);}

Generated hello_world() function

Wednesday, December 12, 12

Page 17: Building Custom PHP Extensions

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);}

Modifying hello_world() function

Wednesday, December 12, 12

Page 18: Building Custom PHP Extensions

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 -m

Wednesday, December 12, 12

Page 19: Building Custom PHP Extensions

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 Rocks

Wednesday, December 12, 12

Page 20: Building Custom PHP Extensions

Cleaning extension folder

‣ Get rid off compilation output

$ make clean

‣ Get rid off build environment stuff

$ phpize --clean

Wednesday, December 12, 12

Page 21: Building Custom PHP Extensions

PHP_FUNCTION

Wednesday, December 12, 12

Page 22: Building Custom PHP Extensions

PHP_FUNCTION(hello_world){ // rest of code removed for brevity}

expands to

PHP_FUNCTION expansion

void 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 object's internal state)

Wednesday, December 12, 12

Page 23: Building Custom PHP Extensions

function_entry hello_world_functions[] = {

PHP_FE(hello_world, hello_world_arg_info) { NULL, NULL, NULL }

};

Exposing internal function

expands to

function_entry hello_world_functions[] = { {"hello_world", zif_hello_world, hello_world_arg_info}, { NULL, NULL, NULL }};

Wednesday, December 12, 12

Page 24: Building Custom PHP Extensions

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

Page 25: Building Custom PHP Extensions

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 zval

Wednesday, December 12, 12

Page 26: Building Custom PHP Extensions

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 typezend_parse_parameters(..., "ls|lz", ...)

// menas that function expects:// a) required array parameter// b) required array parameter// c) required string parameter// d) optional long parameterzend_parse_parameters(..., "aas|l", ...)

Wednesday, December 12, 12

Page 27: Building Custom PHP Extensions

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

Page 28: Building Custom PHP Extensions

Zval - Graphical Representation

value

refcount__gc

type

is_ref__gc

long lval

double dval

str

HashTable *ht

zend_object_value obj

char *val int len

Wednesday, December 12, 12

Page 29: Building Custom PHP Extensions

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

Page 30: Building Custom PHP Extensions

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; }}

Zval Reader Example

Wednesday, December 12, 12

Page 31: Building Custom PHP Extensions

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

Page 32: Building Custom PHP Extensions

PHP_FUNCTION(test_function){ ZVAL_NULL(return_value)}

Returning Values

Wednesday, December 12, 12

Page 33: Building Custom PHP Extensions

Books

Wednesday, December 12, 12

Page 34: Building Custom PHP Extensions

Questions?

Wednesday, December 12, 12

Page 35: Building Custom PHP Extensions

Thank You!

Wednesday, December 12, 12