1. Building Custom PHP
Extensions
International PHP Conference 2012 Tbilisi, Georgia
Wednesday, December 12, 12
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. 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
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 8
Wednesday, December 12, 12
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. 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
8. Why it is important?
‣ Possibility to achieve outstanding performance
‣ Possibility to learn PHP from inside out
Wednesday, December 12, 12
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. 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
12. Tools for creating extensions
‣ Create extension manually
‣ Use ext_skel to generate extension
‣ Use pecl-gen to generate extension
Wednesday, December 12, 12
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.xml
Wednesday, December 12, 12
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
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. 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. 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
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 Rocks
Wednesday, December 12, 12
20. Cleaning extension folder
‣ Get rid off compilation output
$ make clean
‣ Get rid off build environment stuff
$ phpize --clean
Wednesday, December 12, 12
22. PHP_FUNCTION expansion
PHP_FUNCTION(hello_world)
{
// rest of code removed for brevity
}
expands to
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
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. 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
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. 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. Zval - Graphical Representation
value
long lval
double dval
str char *val int len
HashTable *ht
zend_object_value obj
refcount__gc
type
is_ref__gc
Wednesday, December 12, 12
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. 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