Slide 1

Slide 1 text

INTRODUCTION: PHP EXTENSIONS @ThomasWeinert 1

Slide 2

Slide 2 text

PART I: BASICS 2

Slide 3

Slide 3 text

REASONS Performance Memory Library Access 3 . 1

Slide 4

Slide 4 text

ALTERNATIVES Zephyr: PHPCPP: SWIG: zephir-lang.com/ www.php-cpp.com/ www.swig.org/Doc1.3/Php.html 3 . 2

Slide 5

Slide 5 text

CORE CONTRIBUTORS Forks: 3891 Contributors: 444 in 2016: 52 > 10 commits: 34 3 . 3

Slide 6

Slide 6 text

DISCLAIMER This slides contain C code But this is NOT a talk about C I am not a core developer, yet. 3 . 4

Slide 7

Slide 7 text

ZEND API main/php.h Zend/zend_API.h ( ) https://github.com/php/php- src http://lxr.php.net/ http://lxr.room11.org/ 4 . 1

Slide 8

Slide 8 text

4 . 2

Slide 9

Slide 9 text

4 . 3

Slide 10

Slide 10 text

FILES config.m4 php_sample.h sample.c config.w32 5 . 1

Slide 11

Slide 11 text

CONFIG.M4 PHP_ARG_ENABLE(sample, [Whether to enable the "sample" extension], [ ­­enable­sample Enable "sample" extension support]) if test $PHP_SAMPLE != "no"; then PHP_SUBST(SAMPLE_SHARED_LIBADD) PHP_NEW_EXTENSION(sample, sample.c, $ext_shared) fi Makefile 5 . 2

Slide 12

Slide 12 text

PHP_SAMPLE.H #ifndef PHP_SAMPLE_H #define PHP_SAMPLE_H #define PHP_SAMPLE_EXT_NAME "sample" #define PHP_SAMPLE_EXT_VERSION "1.0" #define PHP_SAMPLE_EXT_NS "sample" #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include "php.h" #ifdef ZTS #include "TSRM.h" #endif #if defined(ZTS) && defined(COMPILE_DL_SAMPLE) ZEND_TSRMLS_CACHE_EXTERN() #endif #endif /* PHP_SAMPLE_H */ C 5 . 3

Slide 13

Slide 13 text

SAMPLE.C #include "php_sample.h" zend_module_entry sample_module_entry = { STANDARD_MODULE_HEADER, PHP_SAMPLE_EXT_NAME, NULL, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ PHP_SAMPLE_EXT_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_SAMPLE C 5 . 4

Slide 14

Slide 14 text

COMPILE 6 . 1

Slide 15

Slide 15 text

PHPIZE > phpize 6 . 2

Slide 16

Slide 16 text

PHPIZE > phpize 6 . 3

Slide 17

Slide 17 text

CONFIGURE > ./configure 6 . 4

Slide 18

Slide 18 text

MAKE > make > make test > sudo make install 6 . 5

Slide 19

Slide 19 text

TESTS ===================================================================== TEST RESULT SUMMARY ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ Exts skipped : 0 Exts tested : 26 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ Number of tests : 1 1 Tests skipped : 0 ( 0.0%) ‐‐‐‐‐‐‐‐ Tests warned : 0 ( 0.0%) ( 0.0%) Tests failed : 1 (100.0%) (100.0%) Expected fail : 0 ( 0.0%) ( 0.0%) Tests passed : 0 ( 0.0%) ( 0.0%) ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ Time taken : 1 seconds ===================================================================== ===================================================================== FAILED TEST SUMMARY ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ Call function with string argument [tests/001.phpt] ===================================================================== 6 . 6

Slide 20

Slide 20 text

FEEDBACK TO PHP QA This report can be automatically sent to the PHP QA team at http://qa.php.net/reports and http://news.php.net/php.qa.reports This gives us a better understanding of PHP's behavior. If you don't want to send the report immediately you can choose option "s" to save it. You can then email it to qa‐[email protected] Do you want to send this report now? [Yns]: > export NO_INTERACTION=1 6 . 7

Slide 21

Slide 21 text

TESTS FAILED qa.php.net/write-test.php 6 . 8

Slide 22

Slide 22 text

CLEAN > phpize ‐‐clean 6 . 9

Slide 23

Slide 23 text

> php ‐‐ri sample sample Version => 1.0 6 . 10

Slide 24

Slide 24 text

> php ‐‐re sample Extension [ extension #26 sample version 1.0 ] { } 6 . 11

Slide 25

Slide 25 text

PHPINFO() 7 . 1

Slide 26

Slide 26 text

MINFO FUNCTION PHP_MINFO_FUNCTION(sample) { php_info_print_table_start(); php_info_print_table_header(2, "sample support", "enabled"); php_info_print_table_row(2, "1.", "Basic extension"); php_info_print_table_end(); } C 7 . 2

Slide 27

Slide 27 text

REGISTER MINFO FUNCTION zend_module_entry sample_module_entry = { STANDARD_MODULE_HEADER, PHP_SAMPLE_EXT_NAME, NULL, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ PHP_MINFO(sample), /* MINFO */ PHP_SAMPLE_EXT_VERSION, STANDARD_MODULE_PROPERTIES }; C 7 . 3

Slide 28

Slide 28 text

OUTPUT 7 . 4

Slide 29

Slide 29 text

> php ‐‐ri sample sample sample support => enabled 1. => Basic extension 7 . 5

Slide 30

Slide 30 text

FUNCTION echo \sample\helloWorld(); PHP 8 . 1

Slide 31

Slide 31 text

IMPLEMENT PHP_FUNCTION(sample_hello_world) { php_printf("Hello World!\n"); } C 8 . 2

Slide 32

Slide 32 text

FUNCTION LIST const zend_function_entry php_sample_functions[] = { ZEND_NS_NAMED_FE( PHP_SAMPLE_EXT_NS, helloWorld, ZEND_FN(sample_hello_world), NULL ) PHP_FE_END }; C 8 . 3

Slide 33

Slide 33 text

REGISTER FUNCTIONS ZEND_NS_NAMED_FE ZEND_NS_FE ZEND_NS_FALIAS ZEND_NS_DEP_FE ZEND_NS_DEP_FALIAS PHP_FE / ZEND_FE PHP_NAMED_FE / ZEND_NAMED_FE ... 8 . 4

Slide 34

Slide 34 text

REGISTER FUNCTION LIST zend_module_entry sample_module_entry = { STANDARD_MODULE_HEADER, PHP_SAMPLE_EXT_NAME, php_sample_functions, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ PHP_SAMPLE_EXT_VERSION, STANDARD_MODULE_PROPERTIES }; C 8 . 5

Slide 35

Slide 35 text

> php ‐‐re sample Extension [ extension #26 sample version 1.0 ] { ‐ Functions { Function [ function sample\helloWorld ] { } } } 8 . 6

Slide 36

Slide 36 text

GLOBAL VARIABLE 9 . 1

Slide 37

Slide 37 text

DEFINE MODULE VARIABLES php_sample.h ZEND_BEGIN_MODULE_GLOBALS(sample) long sample_value; ZEND_END_MODULE_GLOBALS(sample) C 9 . 2

Slide 38

Slide 38 text

ACCESSOR TEMPLATE php_sample.h #define SAMPLE_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(sample, v) C 9 . 3

Slide 39

Slide 39 text

DECLARE VARIABLE sample.c ZEND_DECLARE_MODULE_GLOBALS(sample) C 9 . 4

Slide 40

Slide 40 text

USE VARIABLE sample.c PHP_FUNCTION(sample_get_value) { long value; value = SAMPLE_G(sample_value); php_printf("Current value: %d\n", value); SAMPLE_G(sample_value) = (value == 42) ? 21 : 42; } C 9 . 5

Slide 41

Slide 41 text

INITIALIZE VARIABLE sample.c PHP_RINIT_FUNCTION(sample) { SAMPLE_G(sample_value) = 21; } C 9 . 6

Slide 42

Slide 42 text

REGISTER INITIALIZATION sample.c zend_module_entry sample_module_entry = { STANDARD_MODULE_HEADER, PHP_SAMPLE_EXT_NAME, php_sample_functions, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ PHP_RINIT(sample), /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ PHP_SAMPLE_EXT_VERSION, STANDARD_MODULE_PROPERTIES }; C 9 . 7

Slide 43

Slide 43 text

FUNCTION ARGUMENT \sample\hello('Universe'); PHP 10 . 1

Slide 44

Slide 44 text

IMPLEMENT PHP_FUNCTION(sample_hello_name) { char *name; size_t name_len; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(name, name_len) ZEND_PARSE_PARAMETERS_END(); php_printf("Hello %s!", name, name_len); } C 10 . 2

Slide 45

Slide 45 text

TEMPLATES (1/2) Z_PARAM_ARRAY(dest) Z_PARAM_ARRAY_OR_OBJECT(dest) Z_PARAM_BOOL(dest) Z_PARAM_CLASS(dest) Z_PARAM_DOUBLE(dest) Z_PARAM_FUNC(fci, fcc) Z_PARAM_ARRAY_HT(dest) Z_PARAM_ARRAY_OR_OBJECT_HT(dest) Z_PARAM_LONG(dest) Z_PARAM_STRICT_LONG(dest) 10 . 3

Slide 46

Slide 46 text

TEMPLATES (2/2) Z_PARAM_OBJECT(dest) Z_PARAM_OBJECT_OF_CLASS(dest, ce) Z_PARAM_PATH(dest, dest_len) Z_PARAM_PATH_STR(dest) Z_PARAM_RESOURCE(dest) Z_PARAM_STRING(dest, dest_len) Z_PARAM_STR(dest) Z_PARAM_ZVAL(dest) Z_PARAM_ZVAL_DEREF(dest) 10 . 4

Slide 47

Slide 47 text

ALTERNATIVE SYNTAX PHP_FUNCTION(sample_hello_name) { char *name; size_t name_len; if ( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len ) == FAILURE ) { RETURN_NULL(); } php_printf("Hello %s!", name, name_len); } C 10 . 5

Slide 48

Slide 48 text

FUNCTION RETURN VALUE echo \sample\answer(); PHP 11 . 1

Slide 49

Slide 49 text

IMPLEMENT PHP_FUNCTION(sample_answer) { RETURN_LONG(42); } C 11 . 2

Slide 50

Slide 50 text

TEMPLATES

Slide 51

Slide 51 text

RETURN_BOOL(b) RETURN_NULL() RETURN_LONG(l) RETURN_DOUBLE(d) RETURN_STRING(s) RETURN_EMPTY_STRING() RETURN_RES(r) RETURN_ARR(r) RETURN_OBJ(r) RETURN_FALSE RETURN_TRUE ... 11 . 3

Slide 52

Slide 52 text

RETURN ARRAY PHP_FUNCTION(sample_getGreetingParts) { array_init(return_value); add_assoc_str( return_value, "greeting", zend_string_init("Hello %s!", strlen("Hello %s!"), 0) ); add_assoc_str( return_value, "who", zend_string_init("World", strlen("World"), 0) ); } C 11 . 4

Slide 53

Slide 53 text

ARGUMENT INFO 12 . 1

Slide 54

Slide 54 text

DEFINE ZEND_BEGIN_ARG_INFO(ArgInfo_sample_hello_name, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) ZEND_END_ARG_INFO() C 12 . 2

Slide 55

Slide 55 text

REGISTER const zend_function_entry php_sample_functions[] = { ZEND_NS_NAMED_FE( PHP_SAMPLE_EXT_NS, hello, ZEND_FN(sample_hello_name), ArgInfo_sample_hello_name ) PHP_FE_END }; C 12 . 3

Slide 56

Slide 56 text

> php ‐‐re sample Extension [ extension #26 sample version 1.0 ] { ‐ Functions { Function [ function sample\hello ] { ‐ Parameters [1] { Parameter #0 [ string $name ] } } } } 12 . 4

Slide 57

Slide 57 text

WITH RETURN VALUE ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX( ArgInfo_sample_multiply, 0, 1, IS_LONG, NULL, 0 ) ZEND_ARG_TYPE_INFO(0, first, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, second, IS_LONG, 0) ZEND_END_ARG_INFO() C 12 . 5

Slide 58

Slide 58 text

> php ‐‐re sample Extension [ extension #26 sample version 1.0 ] { ‐ Functions { Function [ function sample\multiply ] { ‐ Parameters [2] { Parameter #0 [ integer $first ] Parameter #1 [ integer $second ] } ‐ Return [ integer ] } } } 12 . 6

Slide 59

Slide 59 text

TEMPLATES (1/2) ZEND_BEGIN_ARG_INFO(name, _unused) ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(name type, class_name, allow_null) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(n return_reference, required_num_args, type class_name, allow_null) ZEND_END_ARG_INFO() 12 . 7

Slide 60

Slide 60 text

TEMPLATES (2/2) 12 . 8

Slide 61

Slide 61 text

OPTIONAL FUNCTION ARGUMENTS echo \sample\multiply(21), "\n"; echo \sample\multiply(21, 2), "\n"; PHP 13 . 1

Slide 62

Slide 62 text

IMPLEMENT PHP_FUNCTION(sample_multiply) { zend_long first; zend_long second = 1; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_LONG(first) Z_PARAM_OPTIONAL Z_PARAM_LONG(second) ZEND_PARSE_PARAMETERS_END(); RETURN_LONG(first * second); } C 13 . 2

Slide 63

Slide 63 text

FUNCTION ARGUMENT: MIXED echo \sample\output(42), "\n"; echo \sample\output(FALSE), "\n"; echo \sample\output("Hello World"), "\n"; PHP 14 . 1

Slide 64

Slide 64 text

FETCH ZVAL zval *value; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); C 14 . 2

Slide 65

Slide 65 text

GET THE TYPE switch (Z_TYPE_P(value)) { case IS_NULL : php_printf("NULL"); break; case IS_TRUE : php_printf("Boolean: TRUE"); break; case IS_FALSE : php_printf("Boolean: FALSE"); break; C 14 . 3

Slide 66

Slide 66 text

CONVERT case IS_LONG : convert_to_string(value); php_printf("Integer: %s", Z_STRVAL_P(value)); break; C 14 . 4

Slide 67

Slide 67 text

Z_*VAL_P case IS_DOUBLE : php_printf("Float: %f", Z_DVAL_P(value)); break; case IS_STRING : php_printf("String: %s", Z_STRVAL_P(value)); break; case IS_RESOURCE : php_printf("Resource: #%ld", Z_RESVAL_P(value)); break; C 14 . 5

Slide 68

Slide 68 text

MORE TEMPLATES Zend/zend_types.h Zend/zend_operators.h 14 . 6

Slide 69

Slide 69 text

ZVAL 15 . 1

Slide 70

Slide 70 text

_ZVAL_STRUCT 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; // hash collision chain uint32_t cache_slot; // literal cache slot C 15 . 2

Slide 71

Slide 71 text

_ZVAL_STRUCT 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; // Ignore these for now, they are special zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; C 15 . 3

Slide 72

Slide 72 text

_ZEND_REFCOUNTED struct _zend_refcounted { 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; }; C 15 . 4

Slide 73

Slide 73 text

MORE ABOUT ZVAL https://nikic.github.io/2015/05/05/Internal-value- representation-in-PHP-7-part-1.html http://jpauli.github.io/2016/01/14/php-7-objects.html 15 . 5

Slide 74

Slide 74 text

FUNCTION ARGUMENT: ARRAY echo \sample\hello(['World', 'Universe']); PHP 16 . 1

Slide 75

Slide 75 text

READ HASHTABLE ARGUMENT HashTable *names; zval *entry; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_HT(names) ZEND_PARSE_PARAMETERS_END(); C 16 . 2

Slide 76

Slide 76 text

ITERATE HASHTABLE Zend/zend_hash.h ZEND_HASH_FOREACH_VAL(names, entry) { zend_string *name = zval_get_string(entry); php_printf("Hello %s!\n", ZSTR_VAL(name)); zend_string_release(name); } ZEND_HASH_FOREACH_END(); C 16 . 3

Slide 77

Slide 77 text

FUNCTION ARGUMENT: VARIADICS echo \sample\hello('World', 'Universe', 42); PHP 17 . 1

Slide 78

Slide 78 text

IN PHP USERLAND function foo(...$bar) { foreach ($bar as $drink) { ... } } foo('Cola', 'Beer', 'Gin Tonic'); PHP 17 . 2

Slide 79

Slide 79 text

READ ARGUMENTS zval *args; int argc, i; ZEND_PARSE_PARAMETERS_START(1, ­1) Z_PARAM_VARIADIC('+', args, argc) ZEND_PARSE_PARAMETERS_END(); C 17 . 3

Slide 80

Slide 80 text

ITERATE ARGUMENTS for (i = 0; i < argc; i++) { zval *arg = args + i; convert_to_string(arg); php_printf("Hello %s!\n", Z_STRVAL_P(arg)); } C 17 . 4

Slide 81

Slide 81 text

CONSTANT echo Sample\SAMPLE_INT; PHP 18 . 1

Slide 82

Slide 82 text

VALUE TEMPLATE #define SAMPLE_INT 42 C 18 . 2

Slide 83

Slide 83 text

MINIT FUNCTION PHP_MINIT_FUNCTION(sample) { REGISTER_NS_LONG_CONSTANT( PHP_SAMPLE_EXT_NS, "SAMPLE_INT", SAMPLE_INT, CONST_CS | CONST_PERSISTENT ); } C 18 . 3

Slide 84

Slide 84 text

DEFINITIONS zend_constants.h REGISTER_NS_NULL_CONSTANT REGISTER_NS_BOOL_CONSTANT REGISTER_NS_LONG_CONSTANT REGISTER_NS_DOUBLE_CONSTANT REGISTER_NS_STRING_CONSTANT REGISTER_NS_STRINGL_CONSTANT 18 . 4

Slide 85

Slide 85 text

FLAGS CONST_CS - case sensitive CONST_PERSISTENT - persistent CONST_CT_SUBST - compile time substitution 18 . 5

Slide 86

Slide 86 text

REGISTER MINIT FUNCTION zend_module_entry sample_module_entry = { STANDARD_MODULE_HEADER, PHP_SAMPLE_EXT_NAME, NULL, /* Functions */ PHP_MINIT(sample), /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ PHP_SAMPLE_EXT_VERSION, STANDARD_MODULE_PROPERTIES }; C 18 . 6

Slide 87

Slide 87 text

RESOURCE $r = sample\createResource(); sample\useResource($r); PHP 19 . 1

Slide 88

Slide 88 text

DEFINE STRUCT php_sample.h typedef struct { zend_long number; } sample_resource; C 19 . 2

Slide 89

Slide 89 text

VARIABLES AND DESTRUCTOR sample.c #define SAMPLE_RESOURCE_NAME "sample_resource" int le_sample_resource; static void sample_resource_dtor(zend_resource *rsrc) { sample_resource *r = (sample_resource*)rsrc­>ptr; if (r) { efree(r); } } C 19 . 3

Slide 90

Slide 90 text

REGISTER RESOURCE PHP_MINIT_FUNCTION(sample) { le_sample_resource = zend_register_list_destructors_ex( sample_resource_dtor, NULL, SAMPLE_RESOURCE_NAME, module_nu ); } C 19 . 4

Slide 91

Slide 91 text

INITIALIZE RESOURCE PHP_FUNCTION(sample_create_resource) { sample_resource *r; r = emalloc(sizeof(sample_resource)); r­>number = 42; RETURN_RES(zend_register_resource(r, le_sample_resource)); } C 19 . 5

Slide 92

Slide 92 text

USE RESOURCE PHP_FUNCTION(sample_use_resource) { sample_resource *r; zval *zr; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_RESOURCE(zr) ZEND_PARSE_PARAMETERS_END(); r = (sample_resource *)zend_fetch_resource( Z_RES_P(zr), SAMPLE_RESOURCE_NAME, le_sample_resource ); php_printf("Number: %ld", r­>number); } C 19 . 6

Slide 93

Slide 93 text

FUNCTION ARGUMENT: CALLABLE echo \sample\hello( function() { return 'Universe'; } ); PHP 20 . 1

Slide 94

Slide 94 text

CALLABLE ARGUMENT PHP_FUNCTION(sample_hello_callback) { zend_fcall_info fci; zend_fcall_info_cache fci_cache; zval retval; ZEND_PARSE_PARAMETERS_START(1, ­1) Z_PARAM_FUNC(fci, fci_cache) Z_PARAM_VARIADIC('*', fci.params, fci.param_count) ZEND_PARSE_PARAMETERS_END(); fci.retval = &retval; C 20 . 2

Slide 95

Slide 95 text

EXECUTE CALLABLE if ( zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF ) { if (Z_ISREF(retval)) { zend_unwrap_reference(&retval); } convert_to_string(&retval); php_printf("Hello %s!\n", Z_STRVAL(retval)); } } C 20 . 3

Slide 96

Slide 96 text

GOAL 21

Slide 97

Slide 97 text

PART II: OOP 22

Slide 98

Slide 98 text

EXCEPTIONS 23 . 1

Slide 99

Slide 99 text

SPL EXCEPTION try { echo \sample\trigger(); } catch (\LogicException $e) { echo $e­>getCode(), ' ­> ', $e­>getMessage(); } PHP 23 . 2

Slide 100

Slide 100 text

THROW SPL EXCEPTION #include #include "ext/spl/spl_exceptions.h" PHP_FUNCTION(sample_trigger_exception) { zend_throw_exception_ex( spl_ce_LogicException, 42, "Sample Exception Message" ); } C 23 . 3

Slide 101

Slide 101 text

CATCH EXCEPTION try { \sample\triggerException(); } catch (\Sample\ExceptionName $e) { echo $e­>getCode(), ' ­> ', $e­>getMessage(); } PHP 23 . 4

Slide 102

Slide 102 text

OWN EXCEPTION CLASS zend_class_entry *sample_exception; void sample_init_exception(TSRMLS_D) { zend_class_entry e; INIT_NS_CLASS_ENTRY( e, PHP_SAMPLE_EXT_NS, "ExceptionName", NULL ); sample_exception = zend_register_internal_class_ex( &e, (zend_class_entry*)zend_exception_get_default(TSRMLS_C) ); } PHP_MINIT_FUNCTION(sample) { C 23 . 5

Slide 103

Slide 103 text

THROW EXCEPTION PHP_FUNCTION(sample_trigger_exception) { zend_throw_exception_ex( sample_exception, 42, "Sample Exception Message" ); } C 23 . 6

Slide 104

Slide 104 text

DEFINE CLASS 24 . 1

Slide 105

Slide 105 text

DEFINE #define PHP_SAMPLE_CLASS_NAME "SampleClass" zend_class_entry *php_sample_class_entry; const zend_function_entry php_sample_class_functions[] = { PHP_FE_END }; C 24 . 2

Slide 106

Slide 106 text

REGISTER PHP_MINIT_FUNCTION(sample) { zend_class_entry ce; INIT_NS_CLASS_ENTRY( ce, PHP_SAMPLE_EXT_NS, PHP_SAMPLE_CLASS_NAME, php_sample_class_functions ); php_sample_class_entry = zend_register_internal_class( &ce TSRMLS_CC ); } C 24 . 3

Slide 107

Slide 107 text

FUNCTION ARGUMENT: CLASS Todo: validate argument 24 . 4

Slide 108

Slide 108 text

FUNCTION ARGUMENT: OBJECT Todo: validate argument 24 . 5

Slide 109

Slide 109 text

ARGUMENT INFO: OBJECT 24 . 6

Slide 110

Slide 110 text

FUNCTION ARGUMENT: OBJECT OF CLASS Todo: validate argument 24 . 7

Slide 111

Slide 111 text

ARGUMENT INFO: OBJECT OF CLASS 24 . 8

Slide 112

Slide 112 text

METHOD $greeting = new Sample\Greeting(); $greeting­>hello(); PHP 25 . 1

Slide 113

Slide 113 text

DEFINE / IMPLEMENT zend_class_entry *php_sample_greeting_class_entry; PHP_METHOD(sample_Greeting, hello) { php_printf("Hello World!"); } C 25 . 2

Slide 114

Slide 114 text

REGISTER const zend_function_entry php_sample_greeting_class_functions[] = { PHP_ME(sample_Greeting, hello, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; C 25 . 3

Slide 115

Slide 115 text

METHOD FLAGS ZEND_ACC_PUBLIC ZEND_ACC_PROTECTED ZEND_ACC_PRIVATE ZEND_ACC_STATIC ZEND_ACC_ABSTRACT ZEND_ACC_FINAL ZEND_ACC_CTOR ZEND_ACC_DTOR ZEND_ACC_CLONE 25 . 4

Slide 116

Slide 116 text

CALL A METHOD class Hello { public function do($name) { printf("Hello %s!\n", $name); } } \sample\greet(new Hello("World")); PHP 26 . 1

Slide 117

Slide 117 text

PREPARE PHP_FUNCTION(sample_greet) { zval fname, params[1], *greeting; ZVAL_STRING(&fname, "do"); ZVAL_STRING(¶ms[0], "World"); ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT(greeting) ZEND_PARSE_PARAMETERS_END(); C 26 . 2

Slide 118

Slide 118 text

CALL if ( call_user_function( NULL, greeting, &fname, return_value, 1, params TSRMLS_CC ) == FAILURE ) { php_error_docref( NULL TSRMLS_CC, E_ERROR, "Unable to call method do() on object argument" ); RETVAL_FALSE; } C 26 . 3

Slide 119

Slide 119 text

CLEANUP zval_dtor(&fname); zval_dtor(¶ms[0]); } C 26 . 4

Slide 120

Slide 120 text

PROPERTY $greeting = new Sample\Greeting("Universe"); $greeting­>hello(); PHP 27 . 1

Slide 121

Slide 121 text

DECLARE PROPERTY PHP_MINIT_FUNCTION(sample) php_sample_greeting_class_entry = zend_register_internal_class(&ce TSRMLS_CC); zend_declare_property_stringl( php_sample_greeting_class_entry, ZEND_STRL("name"), ZEND_STRL("World"), ZEND_ACC_PUBLIC ); C 27 . 2

Slide 122

Slide 122 text

UPDATE PROPERTY PHP_METHOD(sample_Greeting, __construct) zval *object; object = getThis(); zend_update_property_stringl( php_sample_greeting_class_entry, object, ZEND_STRL("name"), name, name_len ); C 27 . 3

Slide 123

Slide 123 text

READ PROPERTY PHP_METHOD(sample_Greeting, hello) { zval rv, *name, tmp; name = zend_read_property( php_sample_greeting_class_entry, getThis(), ZEND_STRL("name"), 0, // silent &rv ); ZVAL_COPY(&tmp, name); convert_to_string(&tmp); php_printf("Hello %s!", Z_STRVAL(tmp)); } C 27 . 4

Slide 124

Slide 124 text

DEFINE AN INTERFACE class SampleClass implements Sample\SampleInterface { public function sampleMethod() { echo ($this instanceof Sample\SampleInterface) ? 'Implemented Interface' : 'FAIL'; } } (new SampleClass())­>sampleMethod(); PHP 28 . 1

Slide 125

Slide 125 text

DEFINE #define PHP_SAMPLE_INTERFACE_NAME "SampleInterface" static zend_class_entry *php_sample_interface_entry; const zend_function_entry php_sample_interface_functions[] = { PHP_ABSTRACT_ME(sample_Interface, sampleMethod, NULL) PHP_FE_END }; C 28 . 2

Slide 126

Slide 126 text

REGISTER PHP_MINIT_FUNCTION(sample) { zend_class_entry ce; INIT_NS_CLASS_ENTRY( ce, PHP_SAMPLE_EXT_NS, PHP_SAMPLE_INTERFACE_NAME, php_sample_interface_functions ); php_sample_interface_entry = zend_register_internal_interface( &ce TSRMLS_CC ); } C 28 . 3

Slide 127

Slide 127 text

IMPLEMENT AN INTERFACE echo json_encode(new Sample\HelloWorld(), JSON_PRETTY_PRINT); PHP 29 . 1

Slide 128

Slide 128 text

IMPLEMENT #define PHP_SAMPLE_CLASS_NAME "HelloWorld" static zend_class_entry *php_sample_class_entry; PHP_METHOD(sample_Class, jsonSerialize) { array_init(return_value); add_assoc_str( return_value, "greeting", zend_string_init("Hello World!", strlen("Hello World!"), ); add_assoc_long(return_value, "answer", 42); } C 29 . 2

Slide 129

Slide 129 text

METHOD LIST const zend_function_entry php_sample_class_functions[] = { PHP_ME(sample_Class, jsonSerialize, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; C 29 . 3

Slide 130

Slide 130 text

REGISTER / DECLARE PHP_MINIT_FUNCTION(sample) { zend_class_entry ce; INIT_NS_CLASS_ENTRY( ce, PHP_SAMPLE_EXT_NS, PHP_SAMPLE_CLASS_NAME, php_sample_class_functions ); php_sample_class_entry = zend_register_internal_class(&ce TSRMLS_CC); zend_class_implements( php_sample_class_entry, 1, php_json_serializable_ce ); } C 29 . 4

Slide 131

Slide 131 text

INTERNAL DATA 30 . 1

Slide 132

Slide 132 text

VARIABLES AND TYPES zend_object_handlers php_sample_greeting_handlers; typedef struct _php_sample_greeting_t { zval who; zend_object std; } php_sample_greeting_t; C 30 . 2

Slide 133

Slide 133 text

TEMPLATES #define php_sample_greeting_from(o) \ ((php_sample_greeting_t*) ((char*) o ­ \ XtOffsetOf(php_sample_greeting_t, std))) #define php_sample_greeting_fetch(z) \ php_sample_greeting_from(Z_OBJ_P(z)) C 30 . 3

Slide 134

Slide 134 text

HANDLER: CREATE OBJECT zend_object* php_sample_greeting_create(zend_class_entry *ce) { php_sample_greeting_t *s = (php_sample_greeting_t*) emalloc( sizeof(php_sample_greeting_t) + zend_object_properties_size(ce) ); zend_object_std_init(&s­>std, ce); object_properties_init(&s­>std, ce); s­>std.handlers = &php_sample_greeting_handlers; return &s­>std; } C 30 . 4

Slide 135

Slide 135 text

HANDLER: FREE OBJECT void php_sample_greeting_free(zend_object *o) { php_sample_greeting_t *s = php_sample_greeting_from(o); zval_dtor(&s­>who); zend_object_std_dtor(o); } C 30 . 5

Slide 136

Slide 136 text

REGISTER HANDLERS PHP_MINIT_FUNCTION(sample) php_sample_greeting_class_entry = zend_register_internal_class( &ce TSRMLS_CC ); php_sample_greeting_class_entry­>create_object = php_sample_greeting_create; memcpy( &php_sample_greeting_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers) ); php_sample_greeting_handlers.offset = XtOffsetOf( php_sample_greeting_t, std ); php_sample_greeting_handlers.free_obj = php_sample_greeting_free; C 30 . 6

Slide 137

Slide 137 text

STORE VALUE PHP_METHOD(sample_Greeting, __construct) { char *name; size_t name_len; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(name, name_len) ZEND_PARSE_PARAMETERS_END(); php_sample_greeting_t *sample = php_sample_greeting_fetch( getThis() ); ZVAL_STRINGL(&sample­>who, name, name_len); } C 30 . 7

Slide 138

Slide 138 text

READ VALUE PHP_METHOD(sample_Greeting, hello) { zval rv, *name, tmp; php_sample_greeting_t *sample = php_sample_greeting_fetch( getThis() ); php_printf("Hello %s!", Z_STRVAL(sample­>who)); } C 30 . 8

Slide 139

Slide 139 text

LINKS Examples: Counter: Vagrant Box: Fast ZPP: github.com/ThomasWeinert/php- extension-sample/ github.com/ThomasWeinert/php- extension-sample-counter/ github.com/rlerdorf/php7dev https://wiki.php.net/rfc/fast_zpp 31