SlideShare une entreprise Scribd logo
1  sur  118
PHP 7 Extensions
Workshop
Good morning
 Julien PAULI
 PHP programmer for many years
 PHP internals source hacker
 5.5 and 5.6 Release Manager
 Writes tech articles and books
 http://www.phpinternalsbook.com
 http://jpauli.github.io
 Working at SensioLabs in Paris
 Mainly doing cool C stuff on PHP / Symfony2
 @julienpauli - github.com/jpauli - jpauli@php.net
The road
 Compile PHP and use debug mode
 PHP extensions details and lifetime
 PHP extensions globals management
 Memory management
 PHP variables : zvals
 PHP INI settings
 PHP functions, objects and classes
 Overwritting existing behaviors
 Changing deep Zend Engine behaviors
What you should bring
 A laptop under Linux/Unix
 Good C knowledge
 Linux knowledge (your-OS knowledge)
 Any C dev environment
 Those slides will assume a Debian based Linux
Compiling PHP, using debug
 Grab a PHP source code from php.net or git
 Install a C code compiling environment
 You'll probably need some libs to compile PHP
:$> apt-get install build-essential autoconf
:$> apt-get install libxml2-dev
Compiling PHP, using debug
 Compile a debug PHP and install it
 Do not forget debug flag
 Extensions compiled against debug PHP won't load
on "normal" PHP => need recompile
 Always develop extension under debug mode
:$> ./configure --enable-debug --prefix=my/install/dir
:$> make && make install
:$> my/install/dir/bin/php -v
PHP 7.0.7-dev (cli) (built: Apr 15 2016 09:11:24) ( NTS DEBUG )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
Create your first extension
 There exists a skeleton generator, let's use it
:$> cd phpsrc/ext
:$phpsrc/ext> ./ext_skel --extname=extworkshop
Creating directory ext-workshop
Creating basic files: config.m4 config.w32 .svnignore extworkshop.c
php_extworkshop.h CREDITS EXPERIMENTAL
tests/001.phpt extworkshop.php
[done].
:~> cd extworkshop && tree
.
|-- config.m4
|-- config.w32
|-- CREDITS
|-- EXPERIMENTAL
|-- extworkshop.c
|-- extworkshop.php
|-- php_extworkshop.h
`-- tests
`-- 001.phpt
Activate your first extension
 config.m4 tells the build tools about your ext
 Uncomment --enable if your extension is stand
alone
 Uncomment --with if your extension has
dependencies against other libraries
:~/extworkshop> vim config.m4
PHP_ARG_ENABLE(ext-workshop, whether to enable extworkshop support,
[ --enable-extworkshop Enable extworkshop support])
PHP_NEW_EXTENSION(extworkshop, extworkshop.c, $ext_shared)
Compile and install your ext
 phpize tool is under `php-install-dir`/bin
 It's a shell script importing PHP sources into your ext
dir for it to get ready to compile
 It performs some checks
 It imports the configure script
 This will make you compile a shared object
 For static compilation, rebuild main configure using
buildconf script
 Run phpize --clean to clean the env when finished
:~/extworkshop> phpize && ./configure --with-php-config=/path/to/php-config
&& make install
API numbers
 PHP Api Version is the num of the version of the internal
API
 ZendModule API is the API of the extension system
 ZendExtension API is the API of the zend_extension
system
 ZEND_DEBUG and ZTS are about debug mode activation
and thread safety layer activation
 Those 5 criterias need to match your extension's when
you load it
 Different PHP versions have different API numbers
 Extensions may not work cross-PHP versions
Configuring for:
PHP Api Version: 20151012
Zend Module Api No: 20151012
Zend Extension Api No: 320151012
Check your extension install
:~> path/to/php -dextension=extworkshop.so -m
[PHP Modules]
bcmath
bz2
...
extworkshop
...
[Zend Modules]
:~> path/to/php -dextension=extworkshop.so --re extworkshop
Extension [ <persistent> extension #51 extworkshop version 0.1.0 ] {
- Functions {
Function [ <internal:extworkshop> function confirm_extworkshop_compiled ] {
}
}
}
Php7 extensions workshop
What extensions can do
 Extensions can :
 Add new functions, classes, interfaces
 Add and manage php.ini settings and phpinfo() output
 Add new global variables or constants
 Add new stream wrappers/filters, new resource types
 Overwrite what other extensions defined
 Hook by overwriting global function pointers
 Extensions cannot :
 Modify PHP syntax
 Zend extensions :
 Are able to hook into OPArrays (very advanced usage)
Why create an extension ?
 Bundle an external library code into PHP
 redis, curl, gd, zip ... so many of them
 Optimize performances by adding features
 C is way faster than PHP
 C is used everywhere in Unix/Linux, including Kernel
 Create your own C structures and manage them by
providing PHP functions
 Create your own resource intensive algorithms
 Exemple : https://github.com/phadej/igbinary
C vs PHP
 Don't try to turn the world to C
 Why you should use PHP over C :
 C is way more difficult to develop than PHP
 C is less maintainable
 C can be really tricky to debug
 C is platform dependant. CrossPlatform can turn to PITA
 Cross-PHP-Version is a pain
 Why you should use C over PHP :
 Bundle an external lib into PHP (cant be done in PHP)
 Looking for very high speed and fast/efficient algos
 Changing PHP behavior deeply, make it do what you want
PHP and extensions lifetime
Extensions lifetime
Extension lifetime through code
zend_module_entry extworkshop_module_entry = {
STANDARD_MODULE_HEADER,
"extworkshop",
extworkshop_functions,
PHP_MINIT(extworkshop),
PHP_MSHUTDOWN(extworkshop),
PHP_RINIT(extworkshop),
PHP_RSHUTDOWN(extworkshop),
PHP_MINFO(extworkshop),
PHP_EXTWORKSHOP_VERSION,
STANDARD_MODULE_PROPERTIES
};
Memory Management
Reminders
 Memory alloc main pools :
 Stack
 Heap
 Memory alloc classes :
 auto
 static
 dynamic
 Memory check tools :
 Zend Memory Manager
 Valgrind / electric fence
Zend Memory Manager API
 Request-lifetime heap memory should be
reclaimed using ZMM API
 Infinite lifetime memory can be reclaimed using
ZMM "persist" API, or direct libc calls
#define emalloc(size)
#define safe_emalloc(nmemb, size, offset)
#define efree(ptr)
#define ecalloc(nmemb, size)
#define erealloc(ptr, size)
#define safe_erealloc(ptr, nmemb, size, offset)
#define erealloc_recoverable(ptr, size)
#define estrdup(s)
#define estrndup(s, length)
#define zend_mem_block_size(ptr)
ZMM help
 ZMM alloc functions track leaks for you
 They help finding leaks and overwrites
 If PHP is built with --enable-debug
 If report_memleaks is On in php.ini (default)
 Always use ZMM alloc functions
 Don't hesitate to use valgrind to debug memory
 USE_ZEND_ALLOC=0 env var disables ZendMM
PHP Variables : zval
Zval intro struct _zval_struct {
zend_value value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type,
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved)
} v;
uint32_t type_info;
} u1;
union {
uint32_t var_flags;
uint32_t next;
uint32_t cache_slot;
uint32_t lineno;
uint32_t num_args;
uint32_t fe_pos;
uint32_t fe_iter_idx;
} u2;
};
Zval as a container
 The zval is just a container for your data
 You provide the data as zend_value
 Can be anything : double, string, ast, class, function,
custom-type
 You provide some infos about the data (type_info)
 Is your data requiring heap memory management ?
 Like strings, like arrays ...
 What to do when the engine will have to dup() your data ?
 Can your data be part of a GC cycle ?
Zval as a container
struct _zval_struct {
zend_value value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type,
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved)
} v;
uint32_t type_info;
} u1;
... ...
typedef union _zend_value {
zend_long lval;
double dval;
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;
...
} zend_value;
Refcounted values
 Some values need to be refcounted
 a zend_refcounted structure is then used as
header
typedef struct _zend_refcounted_h {
uint32_t refcount;
union {
struct {
ZEND_ENDIAN_LOHI_3(
zend_uchar type,
zend_uchar flags,
uint16_t gc_info)
} v;
uint32_t type_info;
} u;
} zend_refcounted_h;
Zval steps
 There exists tons of macros helping you :
 Store data into zval
 Change zval type
 Change zval real value
 Deal with zval copy
 Return zval from PHP functions
 ...
Zval main macros
Play with refcount/is_ref
ZVAL_MAKE_REF()
Z_REFCOUNT()
Z_ADDREF() / Z_TRY_ADDREF()
Z_DELREF() / Z_TRY_DELREF()
Z_ISREF()
Z_SET_REFCOUNT()
Copy / separate
ZVAL_COPY_VALUE()
ZVAL_COPY()
ZVAL_DUP()
zval_copy_ctor()
SEPARATE_ZVAL()
SEPARATE_ZVAL_IF_NOT_REF()
Type jugling
Z_TYPE()
Z_TYPE_INFO()
Z_TYPE_FLAGS()
ZVAL_STRING()
ZVAL_STRINGL()
ZVAL_EMPTY_STRING()
ZVAL_TRUE()
ZVAL_FALSE()
ZVAL_LONG()
ZVAL_ARR()
ZVAL_DOUBLE()
ZVAL_RESOURCE()
Zval and pointers
 You'll manipulate, basically :
 zval : use MACRO()
 zval* : use MACRO_P()
 Read macros expansions
 Use your IDE
Play with pointers
Z_ADDREF(myzval)
Z_ADDREF_P(myzval *)
Eclipse macro debugger
Zval Types (LP64)
 long = 8 bytes
 double = 8 bytes IEEE754
 strings are zend_string structures
 They are NUL terminated, but may encapsulate NULs
 They embed their size as a size_t
 size = number of ASCII chars without ending NUL
 Many macros to take care of them
 Bools are stored as a long (1 or 0)
 Resources are zend_resource
 Arrays = HashTable type (more later)
 Objects = lots of things involved (more later)
Zval types differences
 Complex types need special handling
 Strings
 Arrays
 Objects
 Resources
 References
 Those are refcounted and will embed a
zend_refcounted as header
 Simple types can be carried, copied, destroyed
more easilly (long/double/bool/null)
Zval Types macros
 When you want to read or write a Zval, you use
once again dedicated macros :
zval myval;
ZVAL_DOUBLE(&myval, 16.3);
ZVAL_TRUE(&myval);
ZVAL_STRINGL(&myval, "foo", sizeof("foo")-1);
ZVAL_EMPTY_STRING(&myval);
printf("%*s", Z_STRLEN(myval), Z_STRVAL(myval));
printf("%ld", Z_LVAL(myval));
...
Zval type switching
 You can ask PHP to switch from a type to
another, using its known internal rules
 Those functions change the zval*, returning void
 Copy the value, if you need to work on a copy
convert_to_array()
convert_to_object()
convert_to_string()
convert_to_boolean()
convert_to_null()
convert_to_long()
Zval gc info
 Some values need GC
 strings, arrays, objects, resources
 some others don't
 longs, floats, bools, null, undef
 Always use ZVAL macros to correctly handle GC
refcount, types and heap memory
 Always think about what's going to happen to
your data once thrown into the zend engine
ZVAL_COPY_VALUE()
Z_TRY_ADDREF()
SEPARATE_ZVAL()
Creating and destroying zvals
 Creation = simply stack allocation (no heap
alloc)
 Destruction = decrement refcount if data is
refcountable, and free it if needed
 Remember zval is just a container over your
data for the engine to carry it
zval myval;
zval_dtor(&myval);
Copying zvals
 You may want to :
 Copy a zval content into another without
incrementing its refcount
 Use ZVAL_COPY_VALUE()
 Copy a zval content into another and increment the
GC refcount if needed (very often)
 Use ZVAL_COPY()
 Duplicate (deep copy) a zval content into another,
and increment GC refcount if needed
 Use ZVAL_DUP()
Using references
 A reference may be used as a IS_REFERENCE
type
 A zval is then stored into your zval together with a
zend_refcounted header
 You can create a reference from a zval using
ZVAL_NEW_REF() :
zval myval, myref;
ZVAL_STRING(&myval, "foo");
ZVAL_NEW_REF(&myref, &myval);
Using references
 You may also need to work with a reference
 Z_REFVAL() to access it through a zval
 Or unwrap the ref to work with it directly
 ZVAL_DEREF()
 Or make a copy of the reference, and work with
the copy (separate)
 ZVAL_DEREF() + ZVAL_DUP()
Strings
 String use zend_string structure and its API.
 Many places in the engine will require you to
manipulate zend_string
 zend_string's are refcounted, they may be shared,
take care
 You may like smart_str fast API for string complex
constructions (concat)
struct _zend_string {
zend_refcounted_h gc;
zend_ulong h; /* hash value */
size_t len;
char val[1]; /* struct hack */
};
Zend_string API
 Create
 Manipulate
 Copy / dup
 Release / destroy
zend_string *str ;
str = zend_string_init("foo", strlen("foo"), 0) ;
char *c_str; size_t len;
str = ZSTR_VAL(str) ;
len = ZSTR_LEN(str) ;
zend_string *str2, *str3;
str2 = zend_string_copy(str);
str3 = zend_string_dup(str);
zend_string_release(str2);
zend_string_destroy(str3);
PHP functions
Welcome PHP function
typedef struct _zend_function_entry {
const char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
const struct _zend_internal_arg_info *arg_info;
uint32_t num_args;
uint32_t flags;
} zend_function_entry;
PHP functions
 Each extension may register a zend_function_entry array
zend_module_entry extworkshop_module_entry = {
STANDARD_MODULE_HEADER,
"extworkshop",
extworkshop_functions,
PHP_MINIT(extworkshop),
PHP_MSHUTDOWN(extworkshop),
PHP_RINIT(extworkshop),
PHP_RSHUTDOWN(extworkshop),
PHP_MINFO(extworkshop),
... ...
static zend_function_entry extworkshop_functions[] =
{
PHP_FE(my_function, NULL)
PHP_FE_END
};
PHP functions declaration
 Two macros :
 PHP_FE() (php function entry)
 PHP_FUNCTION()
static zend_function_entry extworkshop_functions[] = {
PHP_FE(my_function, NULL)
PHP_FE_END
};
PHP_FUNCTION(my_function) { /* do something */ }
PHP_FE(function_name, function_arginfo)
void zif_my_function(zend_execute_data *execute_data, zval *return_value)
PHP_FE_END
{ ((void *)0), ((void *)0), ((void *)0), 0, 0 }
PHP_FUNCTION(my_function)
zif_my_function
Function exercise
 Declare two new functions
 celsius_to_fahrenheit
 fahrenheit_to_celsius
 They should just be empty for the moment
 Confirm all works
Functions: accepting arguments
 A very nice API exists
 Have a look at
phpsrc/README.PARAMETER_PARSING_API
 zend_parse_parameters() converts arguments to
the type you ask
 Follows PHP rules
 zend_parse_parameters() short : "zpp"
zend_parse_parameters(int num_args_to_parse, char* arg_types, (va_arg args...))
Playing with zpp
 zpp returns FAILURE or SUCCESS
 On failure, you usually return, the engine takes care
of the PHP error message
 You always use pointers to data in zpp
PHP_FUNCTION(foo)
{
zend_long mylong;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mylong) == FAILURE) {
return;
}
RETVAL_LONG(mylong);
}
zpp formatsa - array (zval*)
A - array or object (zval *)
b - boolean (zend_bool)
C - class (zend_class_entry*)
d - double (double)
f - function or array containing php method call info (returned as
zend_fcall_info and zend_fcall_info_cache)
h - array (returned as HashTable*)
H - array or HASH_OF(object) (returned as HashTable*)
l - long (zend_long)
L - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (zend_long)
o - object of any type (zval*)
O - object of specific type given by class entry (zval*, zend_class_entry)
p - valid path (string without null bytes in the middle) and its length (char*, int)
P - valid path (string without null bytes in the middle) and its length as zend_string
r - resource (zval*)
S - string (with possible null bytes) as zend_string
s - string (with possible null bytes) and its length (char*, size_t)
z - the actual zval (zval*)
* - variable arguments list (0 or more)
+ - variable arguments list (1 or more)
zpp special formats
| - indicates that the remaining parameters are optional, they
should be initialized to default values by the extension since they
will not be touched by the parsing function if they are not
passed to it.
/ - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows
! - the parameter it follows can be of specified type or NULL. If NULL is
passed and the output for such type is a pointer, then the output
pointer is set to a native NULL pointer.
For 'b', 'l' and 'd', an extra argument of type zend_bool* must be
passed after the corresponding bool*, long* or double* arguments,
respectively. A non-zero value will be written to the zend_bool iif a
PHP NULL is passed.
zpp examples
char *name, *value = NULL, *path = NULL, *domain = NULL;
zend_long expires = 0;
zend_bool secure = 0, httponly = 0;
size_t name_len, value_len = 0, path_len = 0, domain_len = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|slssbb", &name, &name_len, &value,
&value_len, &expires, &path, &path_len, &domain,
&domain_len, &secure, &httponly) == FAILURE) {
return;
}
/* Gets an object or null, and an array.
If null is passed for object, obj will be set to NULL. */
zval *obj;
zval *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a",
&obj, &arr) == FAILURE) {
return;
}
Practice zpp
 make our temperature functions accept
argument and return a true result
 Parse the argument
 Check RETVAL_**() macros, they'll help
°C x 9/5 + 32 = °F
(°F - 32) x 5/9 = °C
Writing a test
 PHP's got a framework for testing itself and its
extensions
 Welcome "PHPT"
 Learn more about it at
http://qa.php.net/write-test.php
make test
Practice
 Write some tests for our temperature functions
Generating errors
 Two kinds :
 Errors
 Exceptions
 For errors :
 php_error_docref() : Sends an error with a docref
 php_error() / zend_error() : Sends an error
 For exceptions :
 zend_throw_exception() : throws an exception
php_error(E_WARNING, "The number %lu is too big", myulong);
zend_throw_exception_ex(zend_exception_get_default(), 0, "%lu too big", myulong);
Practice errors
 Create a function
temperature_converter($value, $convert_type)
 convert_type can only be 1 or 2
 1 = F° to C°
 2 = C° to F°
 It should output an error if $convert_type is wrong
 The function should return a string describing the
scenario run
 Have a look at php_printf() function to help
echo temperature_converter(20, 2);
"20 degrees celsius give 68 degrees fahrenheit"
echo temperature_converter(20, 8);
Warning: convert_type not recognized
A quick word on string formats
 Know your libc's printf() formats
 http://www.cplusplus.com/reference/cstdio/printf/
 Always use right formats with well sized buffers
 Lot's of PHP functions use "extra", internal
implementation of libc's printf()/spprintf()/snprintf()
 Error messages for example
 Read spprintf.c and snprintf.h to know more about
PHP specific formats, such as "%Z"
 Lots of nice comments in those sources
Function argument declaration
 zpp is clever enough to compute needed args
 zpp uses ZEND_NUM_ARGS()
 it may return FAILURE if number is incorrect
PHP_FUNCTION(foo)
{
long mylong;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mylong) == FAILURE) {
return;
}
}
<?php
foo();
Warning: foo() expects exactly 1 parameter, 0 given in /tmp/myext.php on line 3
Function args declaration
 Try to use Reflection on your temperature
functions
$> php -dextension=extworkshop.so --rf temperature_converter
Function args declaration
 You may help reflection knowing about
accepted parameters
 For this, you need to declare them all to the engine
 The engine can't compute them by itself
 Welcome "arginfos"
zend_arg_info
typedef struct _zend_internal_arg_info {
const char *name;
const char *class_name;
zend_uchar type_hint;
zend_uchar pass_by_reference;
zend_bool allow_null;
zend_bool is_variadic;
} zend_arg_info;
typedef struct _zend_function_entry {
const char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
const struct _zend_internal_arg_info *arg_info;
zend_uint num_args;
zend_uint flags;
} zend_function_entry;
Function args declaration
ZEND_BEGIN_ARG_INFO_EX(arginfo_foo, 0, 0, 1)
ZEND_ARG_INFO(0, "mylong")
ZEND_END_ARG_INFO()
static zend_function_entry extworkshop_functions[] = {
PHP_FE(foo, arginfo_foo)
PHP_FE_END
};
 Have a look at arginfo macros in zend_API.h
#define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args)
#define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference,
required_num_args, type, class_name, allow_null)
#define ZEND_ARG_INFO(pass_by_ref, name)
#define ZEND_ARG_PASS_INFO(pass_by_ref)
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null)
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null)
#define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null)
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null)
#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name)
Function args declaration
 Add some arginfo to our functions
 Try to use Reflection again
HashTables (PHP arrays)
HashTable quickly
 C noticeable structure
 Lots of ways to implement them in C
 Mostly lots of operations are O(1) with worst case O(n)
 http://lxr.linux.no/linux+v3.12.5/include/linux/list.h#L560
 Used everywhere, in every strong program
 Implementation of PHP arrays
 Keys can be numeric type or string type
 Values can be any type
HashTables in a picture
Zend HashTables
 zend_hash.c / zend_hash.h
 HashTable struct
 big API
 Doubled : weither key is numeric or string
 Only stores zvals, nothing else
 HashTables are widely used into PHP
 Not only PHP arrays, they are used internally
everywhere
 gdb functions in .gdbinit to help debugging them
Zend HashTables basics
 1 - Allocate
 2 - Initialize
 3 - Fill-in values
 4 - Operate: Retrieve / Compute / count
 5 - Unset values (if needed)
 6 - Destroy
 7 - Free
Zend HashTable API
 Hash size is rounded up to the next power of two
 If size is exceeded, HashTable will automatically be
resized, but at a (low) CPU cost
 pHashFunction is not used anymore, give NULL
 pDestructor is the destructor function
 Will be called on each data stored in each zval-
element when you remove it from the Hash
 This is used to manage memory : usually free it
 If your zvals need custom storage, use a destructor
int zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction,
dtor_func_t pDestructor, zend_bool persistent);
Zend HashTable API example
HashTable myht = {0};
zend_hash_init(&myht, 10, NULL, NULL, 0);
zval myval;
ZVAL_STRINGL(myval, "Hello World", strlen("Hello World"));
if (zend_hash_str_add(&myht, "myvalue", strlen("myvalue"), &myval) == NULL) {
php_error(E_WARNING, "Could not add value to Hash");
} else {
php_printf("The hashTable contains %lu elements", zend_hash_num_elements(&myht));
}
Zend HT common mistakes
 A HashTable is not a zval
 PHP_FUNCTIONs() mainly manipulate zvals (return_value)
 Use, f.e. array_init()/ZVAL_NEW_ARR to create a zval
containing a HT
 Access the HT into a zval using Z_ARR() macro types
 Lots of HashTable functions return a zval* on success
or NULL
 HashTables manipulate only zval*
 HashTables manipulate zend_string as string-based
keys
 char * / size_t couple is also possible
HashTable retrieve API
PHP_FUNCTION(foo)
{
HashTable *myht;
zval *data = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &myht) == FAILURE) {
return;
}
if ((data = zend_hash_str_find(myht, "foo", strlen("foo")) == NULL) {
php_error(E_NOTICE, "Key 'foo' does not exist");
return;
}
RETVAL_ZVAL(data, 1, 0);
}
HashTable exercise
 Create a function that accepts an infinity of
temperature values into an array and converts
them back to C or F
--TEST--
Test temperature converter array
<?php
$temps = array(68, 77, 78.8);
var_dump(multiple_fahrenheit_to_celsius($temps));
?>
--EXPECTF--
array(3) {
[0]=>
float(20)
[1]=>
float(25)
[2]=>
float(26)
}
References exercise
 Turn multiple_fahrenheit_to_celsius() into an
accept-by-reference function
--TEST--
Test temperature converter array by-ref
<?php
$temps = array(68, 77, 78.8);
multiple_fahrenheit_to_celsius($temps));
var_dump($temps);
?>
--EXPECTF--
array(3) {
[0]=>
float(20)
[1]=>
float(25)
[2]=>
float(26)
}
Constants
 Constants are really easy to use into the engine
 You usually register yours in MINIT() phase, use
CONST_PERSISTENT (if not, const will be cleared at RSHUTDOWN)
 You can read any constant with an easy API
PHP_MINIT_FUNCTION(extworkshop)
{
REGISTER_STRING_CONSTANT("fooconst", "foovalue",
CONST_CS | CONST_PERSISTENT);
return SUCCESS;
}
zend_module_entry myext_module_entry = {
STANDARD_MODULE_HEADER,
"extworkshop",
extworkshop_functions, /* Function entries */
PHP_MINIT(extworkshop), /* Module init */
NULL, /* Module shutdown */
...
Reading constants
PHP_FUNCTION(foo)
{
zval *result_const;
zend_string *str = zend_string_init("fooconst", strlen("fooconst"), 0);
if ((result_const = zend_get_constant(str)) != NULL) {
RETURN_ZVAL(result_const, 1, 0);
}
php_error(E_NOTICE, "Could not find 'fooconst' constant");
}
Practice constants
 Create two constants for
temperature_converter() $mode argument
 TEMP_CONVERTER_TO_CELSIUS
 TEMP_CONVERTER_TO_FAHRENHEIT
Customizing phpinfo()
 Extensions may provide information to the phpinfo
functionnality
 PHP_MINFO() used
 php_info_*() functions
 Beware HTML and non-HTML SAPI
zend_module_entry extworkshop_module_entry = {
/* ... */
PHP_MINFO(extworkshop),
/* ... */
};
PHP_MINFO_FUNCTION(extworkshop)
{
php_info_print_table_start();
php_info_print_table_header(2, "myext support", "enabled");
}
Module info practice
 Customize your extension phpinfo() output
Playing with INI settings
INI general concepts
 Each extension may register as many INI settings as it
wants
 Remember INI entries may change during request lifetime
 They store both their original value and their modified (if any)
value
 They store an access level to declare how their value can be
altered (PHP_INI_USER, PHP_INI_SYSTEM, etc...)
 PHP's ini_set() modifies the entry value at runtime
 PHP's ini_restore() restores the original value as current value
 INI entries may be displayed (mainly using phpinfo()),
they embed a "displayer" function pointer
 INI entries are attached to an extension
An INI entry in PHP
struct _zend_ini_entry_def {
const char *name;
ZEND_INI_MH((*on_modify));
void *mh_arg1;
void *mh_arg2;
void *mh_arg3;
const char *value;
void (*displayer)(zend_ini_entry *ini_entry, int type);
int modifiable;
uint name_length;
uint value_length;
};
INI entries main
 Register at MINIT
 Unregister at MSHUTDOWN
 Display in phpinfo() (usually)
 Many MACROS (once more)
 Read the original or the modified value (your
choice) in your extension
 Create your own modifier/displayer (if needed)
My first INI entry
 This declares a zend_ini_entry vector
 Register / Unregister it
 Display it in phpinfo
PHP_INI_BEGIN()
PHP_INI_ENTRY("logger.default_file", LOGGER_DEFAULT_LOG_FILE, PHP_INI_ALL, NULL)
PHP_INI_END()
#define PHP_INI_ENTRY(name, default_value, modifiable, on_modify)
PHP_MINIT_FUNCTION(myext)
{
REGISTER_INI_ENTRIES();
... ...
}
PHP_MSHUTDOWN_FUNCTION(myext)
{
UNREGISTER_INI_ENTRIES();
... ...
}
PHP_MINFO_FUNCTION(myext)
{
DISPLAY_INI_ENTRIES();
... ...
}
Using an INI entry
 To read your entry, use one of the MACROs
 Same way to read the original value :
INI_STR(entry);
INI_FLT(entry);
INI_INT(entry);
INIT_BOOL(entry);
INI_ORIG_STR(entry);
INI_ORIG_FLT(entry);
INI_ORIG_INT(entry);
INIT_ORIG_BOOL(entry);
Modifying an INI entry
 INI entries may be attached a "modifier"
 A function pointer used to check the new attached
value and to validate it
 For example, for bools, users may only provide 1 or 0,
nothing else
 Many modifiers/validators already exist :
 You may create your own modifier/validator
OnUpdateBool
OnUpdateLong
OnUpdateLongGEZero
OnUpdateReal
OnUpdateString
OnUpdateStringUnempty
Using a modifier
 The modifier should return FAILURE or SUCCESS
 The engine takes care of everything
 Access control, error message, writing to the entry...
PHP_INI_BEGIN()
PHP_INI_ENTRY("logger.default_file", LOGGER_DEFAULT_LOG_FILE,
PHP_INI_ALL, OnUpdateStringUnempty)
PHP_INI_END()
ZEND_API ZEND_INI_MH(OnUpdateStringUnempty)
{
char **p;
char *base = (char *) mh_arg2;
if (new_value && !ZSTR_VAL(new_value)[0]) {
return FAILURE;
}
p = (char **) (base+(size_t) mh_arg1);
*p = new_value ? ZSTR_VAL(new_value) : NULL;
return SUCCESS;
}
Linking INI entry to a global
 If you use your entry often by accessing it, you
will trigger a hash lookup everytime
 This is not nice for performance
 Why not have a global of yours change when
the INI entry is changed (by the PHP user
likely)?
 Please, welcome "modifiers linkers"
Linking INI entry to a global
 Declare a global struct, and tell the engine
which field it must update when your INI entry
gets updated
typedef struct myglobals {
char *my_path;
void *some_foo;
void *some_bar;
} myglobals;
static myglobals my_globals; /* should be thread protected */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("logger.default_file", LOGGER_DEFAULT_LOG_FILE, PHP_INI_ALL,
OnUpdateStringUnempty, my_path, myglobals, my_globals)
PHP_INI_END()
Classes and objects
Classes and objects
 More complex than functions as more structures
are involved
 zend_class_entry
 Represents a class
 zend_object
 Represents an object
 zend_object_handlers
 Function pointers to specific object actions (lots of them)
 zend_object_store
 Big global single object repository storing every known
object
All starts with a class
 A very big structure : zend_class_entry
 Lots of macros to help managing classes
 Internal classes need to be registered at MINIT()
 Internal classes are not destroyed at the end of the
request (user classes are)
 An interface is a (special) class
 A trait is a (special) class
 Once a class is registered into the engine, you may
create as many objects as you want with low memory
footprint
Registering a new class
 zend_register_internal_class()
 Takes a zend_class_entry* as model
 Initialize internal class members
 Registers the class into the engine
 Returns a new pointer to this freshly added class
zend_class_entry *ce_Logger;
PHP_MINIT_FUNCTION(myext)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Logger", NULL);
ce_Logger = zend_register_internal_class(&ce);
return SUCCESS;
}
Registering a new class
 Usually the class pointer is shared into a global
variable
 This one should be exported in a header file
 This allows other extensions to use/redefine our class
zend_class_entry *ce_Logger;
PHP_MINIT_FUNCTION(myext)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Logger", NULL);
ce_Logger = zend_register_internal_class(&ce);
return SUCCESS;
}
Other class noticeable items
 zend_class_entry also manages
 Static attributes (zvals)
 Constants (zvals)
 Functions (object methods and class static methods)
 Interfaces (zend_class_entry as well)
 Inheritence classes tree
 Used traits (zend_class_entry again)
 Other stuff such as handlers
 We'll see how to take care of such item later on
An example logger class
 We will design something like that :
 Now : register the Logger class
<?php
try {
$log = new Logger('/tmp/mylog.log');
} catch (LoggerException $e) {
printf("Woops, could not create object : %s", $e->getMessage());
}
$log->log(Logger::DEBUG, "My debug message");
class constants
 zend_declare_class_constant_<type>()
 Will use ce->constants_table HashTable
#define LOG_INFO 2
PHP_MINIT_FUNCTION(myext)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Logger", NULL);
ce_Logger = zend_register_internal_class(&ce);
zend_declare_class_constant_long(ce_Logger, "INFO", strlen("INFO"), LOG_INFO);
}
class/object attributes
 zend_declare_property_<type>()
 Can declare both static and non static attr.
 Can declare any visibility, only type matters
PHP_MINIT_FUNCTION(myext)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Logger", NULL);
ce_Logger = zend_register_internal_class(&ce);
zend_declare_property_string(ce_Logger, "file", strlen("file"), "",
ZEND_ACC_PROTECTED);
}
Practice creating a class
 Create the logger class
 With 3 constants : INFO, DEBUG, ERROR
 With 2 properties
 handle : private , null
 file : protected , string
 You may declare a namespaced class
 Use INIT_NS_CLASS_ENTRY for this
Adding methods
 Methods are just functions attached to a class
 Very common with PHP_FUNCTION
ZEND_BEGIN_ARG_INFO(arginfo_logger___construct, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
static zend_function_entry logger_class_functions[] = {
PHP_ME( Logger, __construct, arginfo_logger___construct,
ZEND_ACC_PUBLIC|ZEND_ACC_CTOR )
PHP_FE_END
};
PHP_METHOD( Logger, __construct ) { /* some code here */ }
PHP_MINIT_FUNCTION(myext)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Logger", logger_class_functions);
/* ... */
}
Visibility modifier
 One may use
 ZEND_ACC_PROTECTED
 ZEND_ACC_PUBLIC
 ZEND_ACC_PRIVATE
 ZEND_ACC_FINAL
 ZEND_ACC_ABSTRACT
 ZEND_ACC_STATIC
 Usually, the other flags (like ZEND_ACC_INTERFACE)
are set by the engine when you call proper functions
 ZEND_ACC_CTOR/DTOR/CLONE are used by
reflection only
Exercise methods
 Add
 __construct(string $file)
 log(long $level, string $message)
Designing and using interfaces
 An interface is a zend_class_entry with special
flags and abstract methods only
 zend_register_internal_interface() is used
 It simply sets ZEND_ACC_INTERFACE on the
zend_class_entry structure
 zend_class_implements() is then used to
implement the interface
Practice : add an interface
 Detach the log() method into an interface and
implement it
Exceptions
 Use zend_throw_exception() to throw an
Exception
 Passing NULL as class_entry will use default Exception
 You may want to register and use your own
Exceptions
 Just create your exception class
 Make it extend a base Exception class
 Use zend_register_class_entry_ex() for that
zend_throw_exception(my_exception_ce, "An error occured", 0);
INIT_CLASS_ENTRY(ce_exception, "LoggerException", NULL);
ce_Logger_ex = zend_register_internal_class_ex(&ce_exception,
zend_exception_get_default(), NULL);
Practice
 Write real code for our Logger class
 You may need to update properties
 zend_update_property_<type>()
 You may need to access $this in your methods
 use getThis() macro or this_ptr from func args
 You may need to use php streams
 If so, try getting used to their API by yourself
Playing with globals
Globals ?
 They are sometimes (often) needed
 Every program needs some kind of global state
 Try however to prevent their usage when
possible
 Use reentrancy instead
PHP globals problem
 If the environnement is threaded, many (every?)
global access in write should be protected
 Basicaly using some kind of locking technology
 PHP can be compiled with ZendThreadSafety (ZTS) or
not (NZTS)
 Globals access in ZTS mode need to be mutexed
 Globals access in NZTS mode don't need such
protection
 So accessing globals will differ according to ZTS or not
 Thus we'll use macros for such tasks
Declaring globals
 Declare the structure (usually in .h)
 Declare a variable holding the structure
 Declare TSRM STATIC CACHE
ZEND_BEGIN_MODULE_GLOBALS(extworkshop)
char *my_string;
ZEND_END_MODULE_GLOBALS(extworkshop)
ZEND_DECLARE_MODULE_GLOBALS(extworkshop)
ZEND_TSRMLS_CACHE_DEFINE()
Initializing globals
 Most likely, your globals will need to be
initialized (most likely, to 0).
 There exists two hooks for that
 Right before MINIT : GINIT
 Right after MSHUTDOWN : GSHUTDOWN
 Remember that globals are global (...)
 Nothing to do with request lifetime
 Booted very early
 Destroyed very late
Globals hook
zend_module_entry extworkshop_module_entry = {
STANDARD_MODULE_HEADER,
"extworkshop",
extworkshop_functions,
PHP_MINIT(extworkshop),
PHP_MSHUTDOWN(extworkshop),
PHP_RINIT(extworkshop),
PHP_RSHUTDOWN(extworkshop),
PHP_MINFO(extworkshop),
"0.1",
PHP_MODULE_GLOBALS(extworkshop),
PHP_GINIT(extworkshop),
PHP_GSHUTDOWN(extworkshop),
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
GINIT()
PHP_GINIT_FUNCTION(extworkshop)
{
ZEND_TSRMLS_CACHE_UPDATE();
memset(extworkshop_globals, 0, sizeof(*extworkshop_globals));
}
void zm_globals_ctor_extworkshop(zend_extworkshop_globals *extworkshop_globals )
Accessing globals
 A macro is present in your .h for that
 YOUR-EXTENSION-NAME_G(global_value_to_fetch)
#ifdef ZTS
#define EXTWORKSHOP_G(v) 
ZEND_MODULE_GLOBALS_ACCESSOR(extworkshop, v)
#else
#define EXTWORKSHOP_G(v) (extworkshop_globals.v)
#endif
if (EXTWORKSHOP_G(my_string)) {
...
}
Globals : practice
 Move our resource_id to a protected global
 Our extension is now Thread Safe !
Thank you

Contenu connexe

Tendances

Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best PracticesTheo Jungeblut
 
Deep drive into rust programming language
Deep drive into rust programming languageDeep drive into rust programming language
Deep drive into rust programming languageVigneshwer Dhinakaran
 
Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)Olve Maudal
 
Clean Code Principles
Clean Code PrinciplesClean Code Principles
Clean Code PrinciplesYeurDreamin'
 
7 rules of simple and maintainable code
7 rules of simple and maintainable code7 rules of simple and maintainable code
7 rules of simple and maintainable codeGeshan Manandhar
 
C++20 the small things - Timur Doumler
C++20 the small things - Timur DoumlerC++20 the small things - Timur Doumler
C++20 the small things - Timur Doumlercorehard_by
 
Valgrind tutorial
Valgrind tutorialValgrind tutorial
Valgrind tutorialSatabdi Das
 
Introduction to Rust language programming
Introduction to Rust language programmingIntroduction to Rust language programming
Introduction to Rust language programmingRodolfo Finochietti
 
Rust: Systems Programming for Everyone
Rust: Systems Programming for EveryoneRust: Systems Programming for Everyone
Rust: Systems Programming for EveryoneC4Media
 
Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...
Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...
Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...Edureka!
 
StackOverflow
StackOverflowStackOverflow
StackOverflowSusam Pal
 
Insecure coding in C (and C++)
Insecure coding in C (and C++)Insecure coding in C (and C++)
Insecure coding in C (and C++)Olve Maudal
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기Chris Ohk
 
Chapter 1 : Balagurusamy_ Programming ANsI in C
Chapter 1  :  Balagurusamy_ Programming ANsI in C Chapter 1  :  Balagurusamy_ Programming ANsI in C
Chapter 1 : Balagurusamy_ Programming ANsI in C BUBT
 

Tendances (20)

Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
 
Deep drive into rust programming language
Deep drive into rust programming languageDeep drive into rust programming language
Deep drive into rust programming language
 
Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)
 
Clean code
Clean codeClean code
Clean code
 
Clean code
Clean codeClean code
Clean code
 
Clean Code Principles
Clean Code PrinciplesClean Code Principles
Clean Code Principles
 
7 rules of simple and maintainable code
7 rules of simple and maintainable code7 rules of simple and maintainable code
7 rules of simple and maintainable code
 
Introduction to Rust
Introduction to RustIntroduction to Rust
Introduction to Rust
 
C++20 the small things - Timur Doumler
C++20 the small things - Timur DoumlerC++20 the small things - Timur Doumler
C++20 the small things - Timur Doumler
 
Java Concurrency by Example
Java Concurrency by ExampleJava Concurrency by Example
Java Concurrency by Example
 
Valgrind tutorial
Valgrind tutorialValgrind tutorial
Valgrind tutorial
 
Introduction to Rust language programming
Introduction to Rust language programmingIntroduction to Rust language programming
Introduction to Rust language programming
 
Clean code
Clean codeClean code
Clean code
 
New PHP Exploitation Techniques
New PHP Exploitation TechniquesNew PHP Exploitation Techniques
New PHP Exploitation Techniques
 
Rust: Systems Programming for Everyone
Rust: Systems Programming for EveryoneRust: Systems Programming for Everyone
Rust: Systems Programming for Everyone
 
Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...
Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...
Rust Tutorial | Rust Programming Language Tutorial For Beginners | Rust Train...
 
StackOverflow
StackOverflowStackOverflow
StackOverflow
 
Insecure coding in C (and C++)
Insecure coding in C (and C++)Insecure coding in C (and C++)
Insecure coding in C (and C++)
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
 
Chapter 1 : Balagurusamy_ Programming ANsI in C
Chapter 1  :  Balagurusamy_ Programming ANsI in C Chapter 1  :  Balagurusamy_ Programming ANsI in C
Chapter 1 : Balagurusamy_ Programming ANsI in C
 

Similaire à Php7 extensions workshop

Php extensions workshop
Php extensions workshopPhp extensions workshop
Php extensions workshopjulien pauli
 
Php through the eyes of a hoster
Php through the eyes of a hosterPhp through the eyes of a hoster
Php through the eyes of a hosterCombell NV
 
Is your code ready for PHP 7 ?
Is your code ready for PHP 7 ?Is your code ready for PHP 7 ?
Is your code ready for PHP 7 ?Wim Godden
 
Php through the eyes of a hoster phpbnl11
Php through the eyes of a hoster phpbnl11Php through the eyes of a hoster phpbnl11
Php through the eyes of a hoster phpbnl11Combell NV
 
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)Bastian Feder
 
The why and how of moving to PHP 5.5/5.6
The why and how of moving to PHP 5.5/5.6The why and how of moving to PHP 5.5/5.6
The why and how of moving to PHP 5.5/5.6Wim Godden
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
3. build your own php extension ai ti aptech
3. build your own php extension   ai ti aptech3. build your own php extension   ai ti aptech
3. build your own php extension ai ti aptechQuang Anh Le
 
07 build your-own_php_extension
07 build your-own_php_extension07 build your-own_php_extension
07 build your-own_php_extensionNguyen Duc Phu
 
Build your own PHP extension
Build your own PHP extensionBuild your own PHP extension
Build your own PHP extensionVõ Duy Tuấn
 
Php through the eyes of a hoster confoo
Php through the eyes of a hoster confooPhp through the eyes of a hoster confoo
Php through the eyes of a hoster confooCombell NV
 
build your own php extension
build your own php extensionbuild your own php extension
build your own php extensionhazzaz
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfonyFrancois Zaninotto
 
Dynamic PHP web-application analysis
Dynamic PHP web-application analysisDynamic PHP web-application analysis
Dynamic PHP web-application analysisax330d
 
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Fabrice Bernhard
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsMark Baker
 
A quick start on Zend Framework 2
A quick start on Zend Framework 2A quick start on Zend Framework 2
A quick start on Zend Framework 2Enrico Zimuel
 

Similaire à Php7 extensions workshop (20)

Php extensions workshop
Php extensions workshopPhp extensions workshop
Php extensions workshop
 
Php through the eyes of a hoster
Php through the eyes of a hosterPhp through the eyes of a hoster
Php through the eyes of a hoster
 
Is your code ready for PHP 7 ?
Is your code ready for PHP 7 ?Is your code ready for PHP 7 ?
Is your code ready for PHP 7 ?
 
Php through the eyes of a hoster phpbnl11
Php through the eyes of a hoster phpbnl11Php through the eyes of a hoster phpbnl11
Php through the eyes of a hoster phpbnl11
 
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
 
Php extensions
Php extensionsPhp extensions
Php extensions
 
The why and how of moving to PHP 5.5/5.6
The why and how of moving to PHP 5.5/5.6The why and how of moving to PHP 5.5/5.6
The why and how of moving to PHP 5.5/5.6
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
3. build your own php extension ai ti aptech
3. build your own php extension   ai ti aptech3. build your own php extension   ai ti aptech
3. build your own php extension ai ti aptech
 
07 build your-own_php_extension
07 build your-own_php_extension07 build your-own_php_extension
07 build your-own_php_extension
 
Build your own PHP extension
Build your own PHP extensionBuild your own PHP extension
Build your own PHP extension
 
Php through the eyes of a hoster confoo
Php through the eyes of a hoster confooPhp through the eyes of a hoster confoo
Php through the eyes of a hoster confoo
 
Xdebug from a to x
Xdebug from a to xXdebug from a to x
Xdebug from a to x
 
build your own php extension
build your own php extensionbuild your own php extension
build your own php extension
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
 
PHP selber bauen
PHP selber bauenPHP selber bauen
PHP selber bauen
 
Dynamic PHP web-application analysis
Dynamic PHP web-application analysisDynamic PHP web-application analysis
Dynamic PHP web-application analysis
 
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensions
 
A quick start on Zend Framework 2
A quick start on Zend Framework 2A quick start on Zend Framework 2
A quick start on Zend Framework 2
 

Plus de julien pauli

Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019julien pauli
 
PHP 7 OPCache extension review
PHP 7 OPCache extension reviewPHP 7 OPCache extension review
PHP 7 OPCache extension reviewjulien pauli
 
PHP Internals and Virtual Machine
PHP Internals and Virtual MachinePHP Internals and Virtual Machine
PHP Internals and Virtual Machinejulien pauli
 
Basics of Cryptography - Stream ciphers and PRNG
Basics of Cryptography - Stream ciphers and PRNGBasics of Cryptography - Stream ciphers and PRNG
Basics of Cryptography - Stream ciphers and PRNGjulien pauli
 
Mastering your home network - Do It Yourself
Mastering your home network - Do It YourselfMastering your home network - Do It Yourself
Mastering your home network - Do It Yourselfjulien pauli
 
SymfonyCon 2017 php7 performances
SymfonyCon 2017 php7 performancesSymfonyCon 2017 php7 performances
SymfonyCon 2017 php7 performancesjulien pauli
 
Symfony live 2017_php7_performances
Symfony live 2017_php7_performancesSymfony live 2017_php7_performances
Symfony live 2017_php7_performancesjulien pauli
 
Profiling php5 to php7
Profiling php5 to php7Profiling php5 to php7
Profiling php5 to php7julien pauli
 
PHP 7 performances from PHP 5
PHP 7 performances from PHP 5PHP 7 performances from PHP 5
PHP 7 performances from PHP 5julien pauli
 
Mysqlnd, an unknown powerful PHP extension
Mysqlnd, an unknown powerful PHP extensionMysqlnd, an unknown powerful PHP extension
Mysqlnd, an unknown powerful PHP extensionjulien pauli
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objectsjulien pauli
 
PHP Tips for certification - OdW13
PHP Tips for certification - OdW13PHP Tips for certification - OdW13
PHP Tips for certification - OdW13julien pauli
 
Php in 2013 (Web-5 2013 conference)
Php in 2013 (Web-5 2013 conference)Php in 2013 (Web-5 2013 conference)
Php in 2013 (Web-5 2013 conference)julien pauli
 
Understanding PHP memory
Understanding PHP memoryUnderstanding PHP memory
Understanding PHP memoryjulien pauli
 

Plus de julien pauli (20)

Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019
 
Php engine
Php enginePhp engine
Php engine
 
PHP 7 OPCache extension review
PHP 7 OPCache extension reviewPHP 7 OPCache extension review
PHP 7 OPCache extension review
 
Dns
DnsDns
Dns
 
PHP Internals and Virtual Machine
PHP Internals and Virtual MachinePHP Internals and Virtual Machine
PHP Internals and Virtual Machine
 
Basics of Cryptography - Stream ciphers and PRNG
Basics of Cryptography - Stream ciphers and PRNGBasics of Cryptography - Stream ciphers and PRNG
Basics of Cryptography - Stream ciphers and PRNG
 
Mastering your home network - Do It Yourself
Mastering your home network - Do It YourselfMastering your home network - Do It Yourself
Mastering your home network - Do It Yourself
 
SymfonyCon 2017 php7 performances
SymfonyCon 2017 php7 performancesSymfonyCon 2017 php7 performances
SymfonyCon 2017 php7 performances
 
Tcpip
TcpipTcpip
Tcpip
 
Symfony live 2017_php7_performances
Symfony live 2017_php7_performancesSymfony live 2017_php7_performances
Symfony live 2017_php7_performances
 
PHP 7 new engine
PHP 7 new enginePHP 7 new engine
PHP 7 new engine
 
Profiling php5 to php7
Profiling php5 to php7Profiling php5 to php7
Profiling php5 to php7
 
PHP 7 performances from PHP 5
PHP 7 performances from PHP 5PHP 7 performances from PHP 5
PHP 7 performances from PHP 5
 
PHP7 is coming
PHP7 is comingPHP7 is coming
PHP7 is coming
 
Mysqlnd, an unknown powerful PHP extension
Mysqlnd, an unknown powerful PHP extensionMysqlnd, an unknown powerful PHP extension
Mysqlnd, an unknown powerful PHP extension
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objects
 
PHP Tips for certification - OdW13
PHP Tips for certification - OdW13PHP Tips for certification - OdW13
PHP Tips for certification - OdW13
 
PHP5.5 is Here
PHP5.5 is HerePHP5.5 is Here
PHP5.5 is Here
 
Php in 2013 (Web-5 2013 conference)
Php in 2013 (Web-5 2013 conference)Php in 2013 (Web-5 2013 conference)
Php in 2013 (Web-5 2013 conference)
 
Understanding PHP memory
Understanding PHP memoryUnderstanding PHP memory
Understanding PHP memory
 

Dernier

Check out the Free Landing Page Hosting in 2024
Check out the Free Landing Page Hosting in 2024Check out the Free Landing Page Hosting in 2024
Check out the Free Landing Page Hosting in 2024Shubham Pant
 
LESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdf
LESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdfLESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdf
LESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdfmchristianalwyn
 
Introduction to ICANN and Fellowship program by Shreedeep Rayamajhi.pdf
Introduction to ICANN and Fellowship program  by Shreedeep Rayamajhi.pdfIntroduction to ICANN and Fellowship program  by Shreedeep Rayamajhi.pdf
Introduction to ICANN and Fellowship program by Shreedeep Rayamajhi.pdfShreedeep Rayamajhi
 
Presentation2.pptx - JoyPress Wordpress
Presentation2.pptx -  JoyPress WordpressPresentation2.pptx -  JoyPress Wordpress
Presentation2.pptx - JoyPress Wordpressssuser166378
 
Niche Domination Prodigy Review Plus Bonus
Niche Domination Prodigy Review Plus BonusNiche Domination Prodigy Review Plus Bonus
Niche Domination Prodigy Review Plus BonusSkylark Nobin
 
Bio Medical Waste Management Guideliness 2023 ppt.pptx
Bio Medical Waste Management Guideliness 2023 ppt.pptxBio Medical Waste Management Guideliness 2023 ppt.pptx
Bio Medical Waste Management Guideliness 2023 ppt.pptxnaveenithkrishnan
 
Computer 10 Lesson 8: Building a Website
Computer 10 Lesson 8: Building a WebsiteComputer 10 Lesson 8: Building a Website
Computer 10 Lesson 8: Building a WebsiteMavein
 
WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024
WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024
WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024Jan Löffler
 
Vision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced Horizons
Vision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced HorizonsVision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced Horizons
Vision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced HorizonsRoxana Stingu
 
LESSON 10/ GROUP 10/ ST. THOMAS AQUINASS
LESSON 10/ GROUP 10/ ST. THOMAS AQUINASSLESSON 10/ GROUP 10/ ST. THOMAS AQUINASS
LESSON 10/ GROUP 10/ ST. THOMAS AQUINASSlesteraporado16
 
world Tuberculosis day ppt 25-3-2024.pptx
world Tuberculosis day ppt 25-3-2024.pptxworld Tuberculosis day ppt 25-3-2024.pptx
world Tuberculosis day ppt 25-3-2024.pptxnaveenithkrishnan
 
Benefits of doing Internet peering and running an Internet Exchange (IX) pres...
Benefits of doing Internet peering and running an Internet Exchange (IX) pres...Benefits of doing Internet peering and running an Internet Exchange (IX) pres...
Benefits of doing Internet peering and running an Internet Exchange (IX) pres...APNIC
 
A_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptx
A_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptxA_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptx
A_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptxjayshuklatrainer
 
Zero-day Vulnerabilities
Zero-day VulnerabilitiesZero-day Vulnerabilities
Zero-day Vulnerabilitiesalihassaah1994
 
TYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDS
TYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDSTYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDS
TYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDSedrianrheine
 

Dernier (15)

Check out the Free Landing Page Hosting in 2024
Check out the Free Landing Page Hosting in 2024Check out the Free Landing Page Hosting in 2024
Check out the Free Landing Page Hosting in 2024
 
LESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdf
LESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdfLESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdf
LESSON 5 GROUP 10 ST. THOMAS AQUINAS.pdf
 
Introduction to ICANN and Fellowship program by Shreedeep Rayamajhi.pdf
Introduction to ICANN and Fellowship program  by Shreedeep Rayamajhi.pdfIntroduction to ICANN and Fellowship program  by Shreedeep Rayamajhi.pdf
Introduction to ICANN and Fellowship program by Shreedeep Rayamajhi.pdf
 
Presentation2.pptx - JoyPress Wordpress
Presentation2.pptx -  JoyPress WordpressPresentation2.pptx -  JoyPress Wordpress
Presentation2.pptx - JoyPress Wordpress
 
Niche Domination Prodigy Review Plus Bonus
Niche Domination Prodigy Review Plus BonusNiche Domination Prodigy Review Plus Bonus
Niche Domination Prodigy Review Plus Bonus
 
Bio Medical Waste Management Guideliness 2023 ppt.pptx
Bio Medical Waste Management Guideliness 2023 ppt.pptxBio Medical Waste Management Guideliness 2023 ppt.pptx
Bio Medical Waste Management Guideliness 2023 ppt.pptx
 
Computer 10 Lesson 8: Building a Website
Computer 10 Lesson 8: Building a WebsiteComputer 10 Lesson 8: Building a Website
Computer 10 Lesson 8: Building a Website
 
WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024
WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024
WordPress by the numbers - Jan Loeffler, CTO WebPros, CloudFest 2024
 
Vision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced Horizons
Vision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced HorizonsVision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced Horizons
Vision Forward: Tracing Image Search SEO From Its Roots To AI-Enhanced Horizons
 
LESSON 10/ GROUP 10/ ST. THOMAS AQUINASS
LESSON 10/ GROUP 10/ ST. THOMAS AQUINASSLESSON 10/ GROUP 10/ ST. THOMAS AQUINASS
LESSON 10/ GROUP 10/ ST. THOMAS AQUINASS
 
world Tuberculosis day ppt 25-3-2024.pptx
world Tuberculosis day ppt 25-3-2024.pptxworld Tuberculosis day ppt 25-3-2024.pptx
world Tuberculosis day ppt 25-3-2024.pptx
 
Benefits of doing Internet peering and running an Internet Exchange (IX) pres...
Benefits of doing Internet peering and running an Internet Exchange (IX) pres...Benefits of doing Internet peering and running an Internet Exchange (IX) pres...
Benefits of doing Internet peering and running an Internet Exchange (IX) pres...
 
A_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptx
A_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptxA_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptx
A_Z-1_0_4T_00A-EN_U-Po_w_erPoint_06.pptx
 
Zero-day Vulnerabilities
Zero-day VulnerabilitiesZero-day Vulnerabilities
Zero-day Vulnerabilities
 
TYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDS
TYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDSTYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDS
TYPES AND DEFINITION OF ONLINE CRIMES AND HAZARDS
 

Php7 extensions workshop

  • 2. Good morning  Julien PAULI  PHP programmer for many years  PHP internals source hacker  5.5 and 5.6 Release Manager  Writes tech articles and books  http://www.phpinternalsbook.com  http://jpauli.github.io  Working at SensioLabs in Paris  Mainly doing cool C stuff on PHP / Symfony2  @julienpauli - github.com/jpauli - jpauli@php.net
  • 3. The road  Compile PHP and use debug mode  PHP extensions details and lifetime  PHP extensions globals management  Memory management  PHP variables : zvals  PHP INI settings  PHP functions, objects and classes  Overwritting existing behaviors  Changing deep Zend Engine behaviors
  • 4. What you should bring  A laptop under Linux/Unix  Good C knowledge  Linux knowledge (your-OS knowledge)  Any C dev environment  Those slides will assume a Debian based Linux
  • 5. Compiling PHP, using debug  Grab a PHP source code from php.net or git  Install a C code compiling environment  You'll probably need some libs to compile PHP :$> apt-get install build-essential autoconf :$> apt-get install libxml2-dev
  • 6. Compiling PHP, using debug  Compile a debug PHP and install it  Do not forget debug flag  Extensions compiled against debug PHP won't load on "normal" PHP => need recompile  Always develop extension under debug mode :$> ./configure --enable-debug --prefix=my/install/dir :$> make && make install :$> my/install/dir/bin/php -v PHP 7.0.7-dev (cli) (built: Apr 15 2016 09:11:24) ( NTS DEBUG ) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
  • 7. Create your first extension  There exists a skeleton generator, let's use it :$> cd phpsrc/ext :$phpsrc/ext> ./ext_skel --extname=extworkshop Creating directory ext-workshop Creating basic files: config.m4 config.w32 .svnignore extworkshop.c php_extworkshop.h CREDITS EXPERIMENTAL tests/001.phpt extworkshop.php [done]. :~> cd extworkshop && tree . |-- config.m4 |-- config.w32 |-- CREDITS |-- EXPERIMENTAL |-- extworkshop.c |-- extworkshop.php |-- php_extworkshop.h `-- tests `-- 001.phpt
  • 8. Activate your first extension  config.m4 tells the build tools about your ext  Uncomment --enable if your extension is stand alone  Uncomment --with if your extension has dependencies against other libraries :~/extworkshop> vim config.m4 PHP_ARG_ENABLE(ext-workshop, whether to enable extworkshop support, [ --enable-extworkshop Enable extworkshop support]) PHP_NEW_EXTENSION(extworkshop, extworkshop.c, $ext_shared)
  • 9. Compile and install your ext  phpize tool is under `php-install-dir`/bin  It's a shell script importing PHP sources into your ext dir for it to get ready to compile  It performs some checks  It imports the configure script  This will make you compile a shared object  For static compilation, rebuild main configure using buildconf script  Run phpize --clean to clean the env when finished :~/extworkshop> phpize && ./configure --with-php-config=/path/to/php-config && make install
  • 10. API numbers  PHP Api Version is the num of the version of the internal API  ZendModule API is the API of the extension system  ZendExtension API is the API of the zend_extension system  ZEND_DEBUG and ZTS are about debug mode activation and thread safety layer activation  Those 5 criterias need to match your extension's when you load it  Different PHP versions have different API numbers  Extensions may not work cross-PHP versions Configuring for: PHP Api Version: 20151012 Zend Module Api No: 20151012 Zend Extension Api No: 320151012
  • 11. Check your extension install :~> path/to/php -dextension=extworkshop.so -m [PHP Modules] bcmath bz2 ... extworkshop ... [Zend Modules] :~> path/to/php -dextension=extworkshop.so --re extworkshop Extension [ <persistent> extension #51 extworkshop version 0.1.0 ] { - Functions { Function [ <internal:extworkshop> function confirm_extworkshop_compiled ] { } } }
  • 13. What extensions can do  Extensions can :  Add new functions, classes, interfaces  Add and manage php.ini settings and phpinfo() output  Add new global variables or constants  Add new stream wrappers/filters, new resource types  Overwrite what other extensions defined  Hook by overwriting global function pointers  Extensions cannot :  Modify PHP syntax  Zend extensions :  Are able to hook into OPArrays (very advanced usage)
  • 14. Why create an extension ?  Bundle an external library code into PHP  redis, curl, gd, zip ... so many of them  Optimize performances by adding features  C is way faster than PHP  C is used everywhere in Unix/Linux, including Kernel  Create your own C structures and manage them by providing PHP functions  Create your own resource intensive algorithms  Exemple : https://github.com/phadej/igbinary
  • 15. C vs PHP  Don't try to turn the world to C  Why you should use PHP over C :  C is way more difficult to develop than PHP  C is less maintainable  C can be really tricky to debug  C is platform dependant. CrossPlatform can turn to PITA  Cross-PHP-Version is a pain  Why you should use C over PHP :  Bundle an external lib into PHP (cant be done in PHP)  Looking for very high speed and fast/efficient algos  Changing PHP behavior deeply, make it do what you want
  • 16. PHP and extensions lifetime
  • 18. Extension lifetime through code zend_module_entry extworkshop_module_entry = { STANDARD_MODULE_HEADER, "extworkshop", extworkshop_functions, PHP_MINIT(extworkshop), PHP_MSHUTDOWN(extworkshop), PHP_RINIT(extworkshop), PHP_RSHUTDOWN(extworkshop), PHP_MINFO(extworkshop), PHP_EXTWORKSHOP_VERSION, STANDARD_MODULE_PROPERTIES };
  • 20. Reminders  Memory alloc main pools :  Stack  Heap  Memory alloc classes :  auto  static  dynamic  Memory check tools :  Zend Memory Manager  Valgrind / electric fence
  • 21. Zend Memory Manager API  Request-lifetime heap memory should be reclaimed using ZMM API  Infinite lifetime memory can be reclaimed using ZMM "persist" API, or direct libc calls #define emalloc(size) #define safe_emalloc(nmemb, size, offset) #define efree(ptr) #define ecalloc(nmemb, size) #define erealloc(ptr, size) #define safe_erealloc(ptr, nmemb, size, offset) #define erealloc_recoverable(ptr, size) #define estrdup(s) #define estrndup(s, length) #define zend_mem_block_size(ptr)
  • 22. ZMM help  ZMM alloc functions track leaks for you  They help finding leaks and overwrites  If PHP is built with --enable-debug  If report_memleaks is On in php.ini (default)  Always use ZMM alloc functions  Don't hesitate to use valgrind to debug memory  USE_ZEND_ALLOC=0 env var disables ZendMM
  • 24. Zval intro struct _zval_struct { zend_value value; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) } v; uint32_t type_info; } u1; union { uint32_t var_flags; uint32_t next; uint32_t cache_slot; uint32_t lineno; uint32_t num_args; uint32_t fe_pos; uint32_t fe_iter_idx; } u2; };
  • 25. Zval as a container  The zval is just a container for your data  You provide the data as zend_value  Can be anything : double, string, ast, class, function, custom-type  You provide some infos about the data (type_info)  Is your data requiring heap memory management ?  Like strings, like arrays ...  What to do when the engine will have to dup() your data ?  Can your data be part of a GC cycle ?
  • 26. Zval as a container struct _zval_struct { zend_value value; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) } v; uint32_t type_info; } u1; ... ... typedef union _zend_value { zend_long lval; double dval; 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; ... } zend_value;
  • 27. Refcounted values  Some values need to be refcounted  a zend_refcounted structure is then used as header typedef struct _zend_refcounted_h { uint32_t refcount; union { struct { ZEND_ENDIAN_LOHI_3( zend_uchar type, zend_uchar flags, uint16_t gc_info) } v; uint32_t type_info; } u; } zend_refcounted_h;
  • 28. Zval steps  There exists tons of macros helping you :  Store data into zval  Change zval type  Change zval real value  Deal with zval copy  Return zval from PHP functions  ...
  • 29. Zval main macros Play with refcount/is_ref ZVAL_MAKE_REF() Z_REFCOUNT() Z_ADDREF() / Z_TRY_ADDREF() Z_DELREF() / Z_TRY_DELREF() Z_ISREF() Z_SET_REFCOUNT() Copy / separate ZVAL_COPY_VALUE() ZVAL_COPY() ZVAL_DUP() zval_copy_ctor() SEPARATE_ZVAL() SEPARATE_ZVAL_IF_NOT_REF() Type jugling Z_TYPE() Z_TYPE_INFO() Z_TYPE_FLAGS() ZVAL_STRING() ZVAL_STRINGL() ZVAL_EMPTY_STRING() ZVAL_TRUE() ZVAL_FALSE() ZVAL_LONG() ZVAL_ARR() ZVAL_DOUBLE() ZVAL_RESOURCE()
  • 30. Zval and pointers  You'll manipulate, basically :  zval : use MACRO()  zval* : use MACRO_P()  Read macros expansions  Use your IDE Play with pointers Z_ADDREF(myzval) Z_ADDREF_P(myzval *)
  • 32. Zval Types (LP64)  long = 8 bytes  double = 8 bytes IEEE754  strings are zend_string structures  They are NUL terminated, but may encapsulate NULs  They embed their size as a size_t  size = number of ASCII chars without ending NUL  Many macros to take care of them  Bools are stored as a long (1 or 0)  Resources are zend_resource  Arrays = HashTable type (more later)  Objects = lots of things involved (more later)
  • 33. Zval types differences  Complex types need special handling  Strings  Arrays  Objects  Resources  References  Those are refcounted and will embed a zend_refcounted as header  Simple types can be carried, copied, destroyed more easilly (long/double/bool/null)
  • 34. Zval Types macros  When you want to read or write a Zval, you use once again dedicated macros : zval myval; ZVAL_DOUBLE(&myval, 16.3); ZVAL_TRUE(&myval); ZVAL_STRINGL(&myval, "foo", sizeof("foo")-1); ZVAL_EMPTY_STRING(&myval); printf("%*s", Z_STRLEN(myval), Z_STRVAL(myval)); printf("%ld", Z_LVAL(myval)); ...
  • 35. Zval type switching  You can ask PHP to switch from a type to another, using its known internal rules  Those functions change the zval*, returning void  Copy the value, if you need to work on a copy convert_to_array() convert_to_object() convert_to_string() convert_to_boolean() convert_to_null() convert_to_long()
  • 36. Zval gc info  Some values need GC  strings, arrays, objects, resources  some others don't  longs, floats, bools, null, undef  Always use ZVAL macros to correctly handle GC refcount, types and heap memory  Always think about what's going to happen to your data once thrown into the zend engine ZVAL_COPY_VALUE() Z_TRY_ADDREF() SEPARATE_ZVAL()
  • 37. Creating and destroying zvals  Creation = simply stack allocation (no heap alloc)  Destruction = decrement refcount if data is refcountable, and free it if needed  Remember zval is just a container over your data for the engine to carry it zval myval; zval_dtor(&myval);
  • 38. Copying zvals  You may want to :  Copy a zval content into another without incrementing its refcount  Use ZVAL_COPY_VALUE()  Copy a zval content into another and increment the GC refcount if needed (very often)  Use ZVAL_COPY()  Duplicate (deep copy) a zval content into another, and increment GC refcount if needed  Use ZVAL_DUP()
  • 39. Using references  A reference may be used as a IS_REFERENCE type  A zval is then stored into your zval together with a zend_refcounted header  You can create a reference from a zval using ZVAL_NEW_REF() : zval myval, myref; ZVAL_STRING(&myval, "foo"); ZVAL_NEW_REF(&myref, &myval);
  • 40. Using references  You may also need to work with a reference  Z_REFVAL() to access it through a zval  Or unwrap the ref to work with it directly  ZVAL_DEREF()  Or make a copy of the reference, and work with the copy (separate)  ZVAL_DEREF() + ZVAL_DUP()
  • 41. Strings  String use zend_string structure and its API.  Many places in the engine will require you to manipulate zend_string  zend_string's are refcounted, they may be shared, take care  You may like smart_str fast API for string complex constructions (concat) struct _zend_string { zend_refcounted_h gc; zend_ulong h; /* hash value */ size_t len; char val[1]; /* struct hack */ };
  • 42. Zend_string API  Create  Manipulate  Copy / dup  Release / destroy zend_string *str ; str = zend_string_init("foo", strlen("foo"), 0) ; char *c_str; size_t len; str = ZSTR_VAL(str) ; len = ZSTR_LEN(str) ; zend_string *str2, *str3; str2 = zend_string_copy(str); str3 = zend_string_dup(str); zend_string_release(str2); zend_string_destroy(str3);
  • 44. Welcome PHP function typedef struct _zend_function_entry { const char *fname; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); const struct _zend_internal_arg_info *arg_info; uint32_t num_args; uint32_t flags; } zend_function_entry;
  • 45. PHP functions  Each extension may register a zend_function_entry array zend_module_entry extworkshop_module_entry = { STANDARD_MODULE_HEADER, "extworkshop", extworkshop_functions, PHP_MINIT(extworkshop), PHP_MSHUTDOWN(extworkshop), PHP_RINIT(extworkshop), PHP_RSHUTDOWN(extworkshop), PHP_MINFO(extworkshop), ... ... static zend_function_entry extworkshop_functions[] = { PHP_FE(my_function, NULL) PHP_FE_END };
  • 46. PHP functions declaration  Two macros :  PHP_FE() (php function entry)  PHP_FUNCTION() static zend_function_entry extworkshop_functions[] = { PHP_FE(my_function, NULL) PHP_FE_END }; PHP_FUNCTION(my_function) { /* do something */ } PHP_FE(function_name, function_arginfo) void zif_my_function(zend_execute_data *execute_data, zval *return_value) PHP_FE_END { ((void *)0), ((void *)0), ((void *)0), 0, 0 } PHP_FUNCTION(my_function) zif_my_function
  • 47. Function exercise  Declare two new functions  celsius_to_fahrenheit  fahrenheit_to_celsius  They should just be empty for the moment  Confirm all works
  • 48. Functions: accepting arguments  A very nice API exists  Have a look at phpsrc/README.PARAMETER_PARSING_API  zend_parse_parameters() converts arguments to the type you ask  Follows PHP rules  zend_parse_parameters() short : "zpp" zend_parse_parameters(int num_args_to_parse, char* arg_types, (va_arg args...))
  • 49. Playing with zpp  zpp returns FAILURE or SUCCESS  On failure, you usually return, the engine takes care of the PHP error message  You always use pointers to data in zpp PHP_FUNCTION(foo) { zend_long mylong; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mylong) == FAILURE) { return; } RETVAL_LONG(mylong); }
  • 50. zpp formatsa - array (zval*) A - array or object (zval *) b - boolean (zend_bool) C - class (zend_class_entry*) d - double (double) f - function or array containing php method call info (returned as zend_fcall_info and zend_fcall_info_cache) h - array (returned as HashTable*) H - array or HASH_OF(object) (returned as HashTable*) l - long (zend_long) L - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (zend_long) o - object of any type (zval*) O - object of specific type given by class entry (zval*, zend_class_entry) p - valid path (string without null bytes in the middle) and its length (char*, int) P - valid path (string without null bytes in the middle) and its length as zend_string r - resource (zval*) S - string (with possible null bytes) as zend_string s - string (with possible null bytes) and its length (char*, size_t) z - the actual zval (zval*) * - variable arguments list (0 or more) + - variable arguments list (1 or more)
  • 51. zpp special formats | - indicates that the remaining parameters are optional, they should be initialized to default values by the extension since they will not be touched by the parsing function if they are not passed to it. / - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows ! - the parameter it follows can be of specified type or NULL. If NULL is passed and the output for such type is a pointer, then the output pointer is set to a native NULL pointer. For 'b', 'l' and 'd', an extra argument of type zend_bool* must be passed after the corresponding bool*, long* or double* arguments, respectively. A non-zero value will be written to the zend_bool iif a PHP NULL is passed.
  • 52. zpp examples char *name, *value = NULL, *path = NULL, *domain = NULL; zend_long expires = 0; zend_bool secure = 0, httponly = 0; size_t name_len, value_len = 0, path_len = 0, domain_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|slssbb", &name, &name_len, &value, &value_len, &expires, &path, &path_len, &domain, &domain_len, &secure, &httponly) == FAILURE) { return; } /* Gets an object or null, and an array. If null is passed for object, obj will be set to NULL. */ zval *obj; zval *arr; if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a", &obj, &arr) == FAILURE) { return; }
  • 53. Practice zpp  make our temperature functions accept argument and return a true result  Parse the argument  Check RETVAL_**() macros, they'll help °C x 9/5 + 32 = °F (°F - 32) x 5/9 = °C
  • 54. Writing a test  PHP's got a framework for testing itself and its extensions  Welcome "PHPT"  Learn more about it at http://qa.php.net/write-test.php
  • 56. Practice  Write some tests for our temperature functions
  • 57. Generating errors  Two kinds :  Errors  Exceptions  For errors :  php_error_docref() : Sends an error with a docref  php_error() / zend_error() : Sends an error  For exceptions :  zend_throw_exception() : throws an exception php_error(E_WARNING, "The number %lu is too big", myulong); zend_throw_exception_ex(zend_exception_get_default(), 0, "%lu too big", myulong);
  • 58. Practice errors  Create a function temperature_converter($value, $convert_type)  convert_type can only be 1 or 2  1 = F° to C°  2 = C° to F°  It should output an error if $convert_type is wrong  The function should return a string describing the scenario run  Have a look at php_printf() function to help echo temperature_converter(20, 2); "20 degrees celsius give 68 degrees fahrenheit" echo temperature_converter(20, 8); Warning: convert_type not recognized
  • 59. A quick word on string formats  Know your libc's printf() formats  http://www.cplusplus.com/reference/cstdio/printf/  Always use right formats with well sized buffers  Lot's of PHP functions use "extra", internal implementation of libc's printf()/spprintf()/snprintf()  Error messages for example  Read spprintf.c and snprintf.h to know more about PHP specific formats, such as "%Z"  Lots of nice comments in those sources
  • 60. Function argument declaration  zpp is clever enough to compute needed args  zpp uses ZEND_NUM_ARGS()  it may return FAILURE if number is incorrect PHP_FUNCTION(foo) { long mylong; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mylong) == FAILURE) { return; } } <?php foo(); Warning: foo() expects exactly 1 parameter, 0 given in /tmp/myext.php on line 3
  • 61. Function args declaration  Try to use Reflection on your temperature functions $> php -dextension=extworkshop.so --rf temperature_converter
  • 62. Function args declaration  You may help reflection knowing about accepted parameters  For this, you need to declare them all to the engine  The engine can't compute them by itself  Welcome "arginfos"
  • 63. zend_arg_info typedef struct _zend_internal_arg_info { const char *name; const char *class_name; zend_uchar type_hint; zend_uchar pass_by_reference; zend_bool allow_null; zend_bool is_variadic; } zend_arg_info; typedef struct _zend_function_entry { const char *fname; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); const struct _zend_internal_arg_info *arg_info; zend_uint num_args; zend_uint flags; } zend_function_entry;
  • 64. Function args declaration ZEND_BEGIN_ARG_INFO_EX(arginfo_foo, 0, 0, 1) ZEND_ARG_INFO(0, "mylong") ZEND_END_ARG_INFO() static zend_function_entry extworkshop_functions[] = { PHP_FE(foo, arginfo_foo) PHP_FE_END };  Have a look at arginfo macros in zend_API.h #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, class_name, allow_null) #define ZEND_ARG_INFO(pass_by_ref, name) #define ZEND_ARG_PASS_INFO(pass_by_ref) #define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) #define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) #define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) #define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) #define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name)
  • 65. Function args declaration  Add some arginfo to our functions  Try to use Reflection again
  • 67. HashTable quickly  C noticeable structure  Lots of ways to implement them in C  Mostly lots of operations are O(1) with worst case O(n)  http://lxr.linux.no/linux+v3.12.5/include/linux/list.h#L560  Used everywhere, in every strong program  Implementation of PHP arrays  Keys can be numeric type or string type  Values can be any type
  • 68. HashTables in a picture
  • 69. Zend HashTables  zend_hash.c / zend_hash.h  HashTable struct  big API  Doubled : weither key is numeric or string  Only stores zvals, nothing else  HashTables are widely used into PHP  Not only PHP arrays, they are used internally everywhere  gdb functions in .gdbinit to help debugging them
  • 70. Zend HashTables basics  1 - Allocate  2 - Initialize  3 - Fill-in values  4 - Operate: Retrieve / Compute / count  5 - Unset values (if needed)  6 - Destroy  7 - Free
  • 71. Zend HashTable API  Hash size is rounded up to the next power of two  If size is exceeded, HashTable will automatically be resized, but at a (low) CPU cost  pHashFunction is not used anymore, give NULL  pDestructor is the destructor function  Will be called on each data stored in each zval- element when you remove it from the Hash  This is used to manage memory : usually free it  If your zvals need custom storage, use a destructor int zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent);
  • 72. Zend HashTable API example HashTable myht = {0}; zend_hash_init(&myht, 10, NULL, NULL, 0); zval myval; ZVAL_STRINGL(myval, "Hello World", strlen("Hello World")); if (zend_hash_str_add(&myht, "myvalue", strlen("myvalue"), &myval) == NULL) { php_error(E_WARNING, "Could not add value to Hash"); } else { php_printf("The hashTable contains %lu elements", zend_hash_num_elements(&myht)); }
  • 73. Zend HT common mistakes  A HashTable is not a zval  PHP_FUNCTIONs() mainly manipulate zvals (return_value)  Use, f.e. array_init()/ZVAL_NEW_ARR to create a zval containing a HT  Access the HT into a zval using Z_ARR() macro types  Lots of HashTable functions return a zval* on success or NULL  HashTables manipulate only zval*  HashTables manipulate zend_string as string-based keys  char * / size_t couple is also possible
  • 74. HashTable retrieve API PHP_FUNCTION(foo) { HashTable *myht; zval *data = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &myht) == FAILURE) { return; } if ((data = zend_hash_str_find(myht, "foo", strlen("foo")) == NULL) { php_error(E_NOTICE, "Key 'foo' does not exist"); return; } RETVAL_ZVAL(data, 1, 0); }
  • 75. HashTable exercise  Create a function that accepts an infinity of temperature values into an array and converts them back to C or F --TEST-- Test temperature converter array <?php $temps = array(68, 77, 78.8); var_dump(multiple_fahrenheit_to_celsius($temps)); ?> --EXPECTF-- array(3) { [0]=> float(20) [1]=> float(25) [2]=> float(26) }
  • 76. References exercise  Turn multiple_fahrenheit_to_celsius() into an accept-by-reference function --TEST-- Test temperature converter array by-ref <?php $temps = array(68, 77, 78.8); multiple_fahrenheit_to_celsius($temps)); var_dump($temps); ?> --EXPECTF-- array(3) { [0]=> float(20) [1]=> float(25) [2]=> float(26) }
  • 77. Constants  Constants are really easy to use into the engine  You usually register yours in MINIT() phase, use CONST_PERSISTENT (if not, const will be cleared at RSHUTDOWN)  You can read any constant with an easy API PHP_MINIT_FUNCTION(extworkshop) { REGISTER_STRING_CONSTANT("fooconst", "foovalue", CONST_CS | CONST_PERSISTENT); return SUCCESS; } zend_module_entry myext_module_entry = { STANDARD_MODULE_HEADER, "extworkshop", extworkshop_functions, /* Function entries */ PHP_MINIT(extworkshop), /* Module init */ NULL, /* Module shutdown */ ...
  • 78. Reading constants PHP_FUNCTION(foo) { zval *result_const; zend_string *str = zend_string_init("fooconst", strlen("fooconst"), 0); if ((result_const = zend_get_constant(str)) != NULL) { RETURN_ZVAL(result_const, 1, 0); } php_error(E_NOTICE, "Could not find 'fooconst' constant"); }
  • 79. Practice constants  Create two constants for temperature_converter() $mode argument  TEMP_CONVERTER_TO_CELSIUS  TEMP_CONVERTER_TO_FAHRENHEIT
  • 80. Customizing phpinfo()  Extensions may provide information to the phpinfo functionnality  PHP_MINFO() used  php_info_*() functions  Beware HTML and non-HTML SAPI zend_module_entry extworkshop_module_entry = { /* ... */ PHP_MINFO(extworkshop), /* ... */ }; PHP_MINFO_FUNCTION(extworkshop) { php_info_print_table_start(); php_info_print_table_header(2, "myext support", "enabled"); }
  • 81. Module info practice  Customize your extension phpinfo() output
  • 82. Playing with INI settings
  • 83. INI general concepts  Each extension may register as many INI settings as it wants  Remember INI entries may change during request lifetime  They store both their original value and their modified (if any) value  They store an access level to declare how their value can be altered (PHP_INI_USER, PHP_INI_SYSTEM, etc...)  PHP's ini_set() modifies the entry value at runtime  PHP's ini_restore() restores the original value as current value  INI entries may be displayed (mainly using phpinfo()), they embed a "displayer" function pointer  INI entries are attached to an extension
  • 84. An INI entry in PHP struct _zend_ini_entry_def { const char *name; ZEND_INI_MH((*on_modify)); void *mh_arg1; void *mh_arg2; void *mh_arg3; const char *value; void (*displayer)(zend_ini_entry *ini_entry, int type); int modifiable; uint name_length; uint value_length; };
  • 85. INI entries main  Register at MINIT  Unregister at MSHUTDOWN  Display in phpinfo() (usually)  Many MACROS (once more)  Read the original or the modified value (your choice) in your extension  Create your own modifier/displayer (if needed)
  • 86. My first INI entry  This declares a zend_ini_entry vector  Register / Unregister it  Display it in phpinfo PHP_INI_BEGIN() PHP_INI_ENTRY("logger.default_file", LOGGER_DEFAULT_LOG_FILE, PHP_INI_ALL, NULL) PHP_INI_END() #define PHP_INI_ENTRY(name, default_value, modifiable, on_modify) PHP_MINIT_FUNCTION(myext) { REGISTER_INI_ENTRIES(); ... ... } PHP_MSHUTDOWN_FUNCTION(myext) { UNREGISTER_INI_ENTRIES(); ... ... } PHP_MINFO_FUNCTION(myext) { DISPLAY_INI_ENTRIES(); ... ... }
  • 87. Using an INI entry  To read your entry, use one of the MACROs  Same way to read the original value : INI_STR(entry); INI_FLT(entry); INI_INT(entry); INIT_BOOL(entry); INI_ORIG_STR(entry); INI_ORIG_FLT(entry); INI_ORIG_INT(entry); INIT_ORIG_BOOL(entry);
  • 88. Modifying an INI entry  INI entries may be attached a "modifier"  A function pointer used to check the new attached value and to validate it  For example, for bools, users may only provide 1 or 0, nothing else  Many modifiers/validators already exist :  You may create your own modifier/validator OnUpdateBool OnUpdateLong OnUpdateLongGEZero OnUpdateReal OnUpdateString OnUpdateStringUnempty
  • 89. Using a modifier  The modifier should return FAILURE or SUCCESS  The engine takes care of everything  Access control, error message, writing to the entry... PHP_INI_BEGIN() PHP_INI_ENTRY("logger.default_file", LOGGER_DEFAULT_LOG_FILE, PHP_INI_ALL, OnUpdateStringUnempty) PHP_INI_END() ZEND_API ZEND_INI_MH(OnUpdateStringUnempty) { char **p; char *base = (char *) mh_arg2; if (new_value && !ZSTR_VAL(new_value)[0]) { return FAILURE; } p = (char **) (base+(size_t) mh_arg1); *p = new_value ? ZSTR_VAL(new_value) : NULL; return SUCCESS; }
  • 90. Linking INI entry to a global  If you use your entry often by accessing it, you will trigger a hash lookup everytime  This is not nice for performance  Why not have a global of yours change when the INI entry is changed (by the PHP user likely)?  Please, welcome "modifiers linkers"
  • 91. Linking INI entry to a global  Declare a global struct, and tell the engine which field it must update when your INI entry gets updated typedef struct myglobals { char *my_path; void *some_foo; void *some_bar; } myglobals; static myglobals my_globals; /* should be thread protected */ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("logger.default_file", LOGGER_DEFAULT_LOG_FILE, PHP_INI_ALL, OnUpdateStringUnempty, my_path, myglobals, my_globals) PHP_INI_END()
  • 93. Classes and objects  More complex than functions as more structures are involved  zend_class_entry  Represents a class  zend_object  Represents an object  zend_object_handlers  Function pointers to specific object actions (lots of them)  zend_object_store  Big global single object repository storing every known object
  • 94. All starts with a class  A very big structure : zend_class_entry  Lots of macros to help managing classes  Internal classes need to be registered at MINIT()  Internal classes are not destroyed at the end of the request (user classes are)  An interface is a (special) class  A trait is a (special) class  Once a class is registered into the engine, you may create as many objects as you want with low memory footprint
  • 95. Registering a new class  zend_register_internal_class()  Takes a zend_class_entry* as model  Initialize internal class members  Registers the class into the engine  Returns a new pointer to this freshly added class zend_class_entry *ce_Logger; PHP_MINIT_FUNCTION(myext) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Logger", NULL); ce_Logger = zend_register_internal_class(&ce); return SUCCESS; }
  • 96. Registering a new class  Usually the class pointer is shared into a global variable  This one should be exported in a header file  This allows other extensions to use/redefine our class zend_class_entry *ce_Logger; PHP_MINIT_FUNCTION(myext) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Logger", NULL); ce_Logger = zend_register_internal_class(&ce); return SUCCESS; }
  • 97. Other class noticeable items  zend_class_entry also manages  Static attributes (zvals)  Constants (zvals)  Functions (object methods and class static methods)  Interfaces (zend_class_entry as well)  Inheritence classes tree  Used traits (zend_class_entry again)  Other stuff such as handlers  We'll see how to take care of such item later on
  • 98. An example logger class  We will design something like that :  Now : register the Logger class <?php try { $log = new Logger('/tmp/mylog.log'); } catch (LoggerException $e) { printf("Woops, could not create object : %s", $e->getMessage()); } $log->log(Logger::DEBUG, "My debug message");
  • 99. class constants  zend_declare_class_constant_<type>()  Will use ce->constants_table HashTable #define LOG_INFO 2 PHP_MINIT_FUNCTION(myext) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Logger", NULL); ce_Logger = zend_register_internal_class(&ce); zend_declare_class_constant_long(ce_Logger, "INFO", strlen("INFO"), LOG_INFO); }
  • 100. class/object attributes  zend_declare_property_<type>()  Can declare both static and non static attr.  Can declare any visibility, only type matters PHP_MINIT_FUNCTION(myext) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Logger", NULL); ce_Logger = zend_register_internal_class(&ce); zend_declare_property_string(ce_Logger, "file", strlen("file"), "", ZEND_ACC_PROTECTED); }
  • 101. Practice creating a class  Create the logger class  With 3 constants : INFO, DEBUG, ERROR  With 2 properties  handle : private , null  file : protected , string  You may declare a namespaced class  Use INIT_NS_CLASS_ENTRY for this
  • 102. Adding methods  Methods are just functions attached to a class  Very common with PHP_FUNCTION ZEND_BEGIN_ARG_INFO(arginfo_logger___construct, 0) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() static zend_function_entry logger_class_functions[] = { PHP_ME( Logger, __construct, arginfo_logger___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR ) PHP_FE_END }; PHP_METHOD( Logger, __construct ) { /* some code here */ } PHP_MINIT_FUNCTION(myext) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Logger", logger_class_functions); /* ... */ }
  • 103. Visibility modifier  One may use  ZEND_ACC_PROTECTED  ZEND_ACC_PUBLIC  ZEND_ACC_PRIVATE  ZEND_ACC_FINAL  ZEND_ACC_ABSTRACT  ZEND_ACC_STATIC  Usually, the other flags (like ZEND_ACC_INTERFACE) are set by the engine when you call proper functions  ZEND_ACC_CTOR/DTOR/CLONE are used by reflection only
  • 104. Exercise methods  Add  __construct(string $file)  log(long $level, string $message)
  • 105. Designing and using interfaces  An interface is a zend_class_entry with special flags and abstract methods only  zend_register_internal_interface() is used  It simply sets ZEND_ACC_INTERFACE on the zend_class_entry structure  zend_class_implements() is then used to implement the interface
  • 106. Practice : add an interface  Detach the log() method into an interface and implement it
  • 107. Exceptions  Use zend_throw_exception() to throw an Exception  Passing NULL as class_entry will use default Exception  You may want to register and use your own Exceptions  Just create your exception class  Make it extend a base Exception class  Use zend_register_class_entry_ex() for that zend_throw_exception(my_exception_ce, "An error occured", 0); INIT_CLASS_ENTRY(ce_exception, "LoggerException", NULL); ce_Logger_ex = zend_register_internal_class_ex(&ce_exception, zend_exception_get_default(), NULL);
  • 108. Practice  Write real code for our Logger class  You may need to update properties  zend_update_property_<type>()  You may need to access $this in your methods  use getThis() macro or this_ptr from func args  You may need to use php streams  If so, try getting used to their API by yourself
  • 110. Globals ?  They are sometimes (often) needed  Every program needs some kind of global state  Try however to prevent their usage when possible  Use reentrancy instead
  • 111. PHP globals problem  If the environnement is threaded, many (every?) global access in write should be protected  Basicaly using some kind of locking technology  PHP can be compiled with ZendThreadSafety (ZTS) or not (NZTS)  Globals access in ZTS mode need to be mutexed  Globals access in NZTS mode don't need such protection  So accessing globals will differ according to ZTS or not  Thus we'll use macros for such tasks
  • 112. Declaring globals  Declare the structure (usually in .h)  Declare a variable holding the structure  Declare TSRM STATIC CACHE ZEND_BEGIN_MODULE_GLOBALS(extworkshop) char *my_string; ZEND_END_MODULE_GLOBALS(extworkshop) ZEND_DECLARE_MODULE_GLOBALS(extworkshop) ZEND_TSRMLS_CACHE_DEFINE()
  • 113. Initializing globals  Most likely, your globals will need to be initialized (most likely, to 0).  There exists two hooks for that  Right before MINIT : GINIT  Right after MSHUTDOWN : GSHUTDOWN  Remember that globals are global (...)  Nothing to do with request lifetime  Booted very early  Destroyed very late
  • 114. Globals hook zend_module_entry extworkshop_module_entry = { STANDARD_MODULE_HEADER, "extworkshop", extworkshop_functions, PHP_MINIT(extworkshop), PHP_MSHUTDOWN(extworkshop), PHP_RINIT(extworkshop), PHP_RSHUTDOWN(extworkshop), PHP_MINFO(extworkshop), "0.1", PHP_MODULE_GLOBALS(extworkshop), PHP_GINIT(extworkshop), PHP_GSHUTDOWN(extworkshop), NULL, STANDARD_MODULE_PROPERTIES_EX };
  • 116. Accessing globals  A macro is present in your .h for that  YOUR-EXTENSION-NAME_G(global_value_to_fetch) #ifdef ZTS #define EXTWORKSHOP_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(extworkshop, v) #else #define EXTWORKSHOP_G(v) (extworkshop_globals.v) #endif if (EXTWORKSHOP_G(my_string)) { ... }
  • 117. Globals : practice  Move our resource_id to a protected global  Our extension is now Thread Safe !