Introduction: PHP Extensions

Introduction: PHP Extensions

PHPUG FFM, 2017-03-16
Web Engineering Düsseldorf, 2017-02-21
Symfony User Group Cologne, 2017-05-31 (Part I)

3f2fb8bbcd44609346e1cc0c06d0a39b?s=128

Thomas Weinert

May 31, 2017
Tweet

Transcript

  1. INTRODUCTION: PHP EXTENSIONS @ThomasWeinert 1

  2. PART I: BASICS 2

  3. REASONS Performance Memory Library Access 3 . 1

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

  5. CORE CONTRIBUTORS Forks: 3891 Contributors: 444 in 2016: 52 >

    10 commits: 34 3 . 3
  6. DISCLAIMER This slides contain C code But this is NOT

    a talk about C I am not a core developer, yet. 3 . 4
  7. 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
  8. 4 . 2

  9. 4 . 3

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

  11. 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
  12. 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
  13. 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
  14. COMPILE 6 . 1

  15. PHPIZE > phpize 6 . 2

  16. PHPIZE > phpize 6 . 3

  17. CONFIGURE > ./configure 6 . 4

  18. MAKE > make > make test > sudo make install

    6 . 5
  19. 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
  20. 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‐reports@lists.php.net Do you want to send this report now? [Yns]: > export NO_INTERACTION=1 6 . 7
  21. TESTS FAILED qa.php.net/write-test.php 6 . 8

  22. CLEAN > phpize ‐‐clean 6 . 9

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

    10
  24. > php ‐‐re sample Extension [ extension #26 sample version

    1.0 ] { } 6 . 11
  25. PHPINFO() 7 . 1

  26. 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
  27. 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
  28. OUTPUT 7 . 4

  29. > php ‐‐ri sample sample sample support => enabled 1.

    => Basic extension 7 . 5
  30. FUNCTION echo \sample\helloWorld(); PHP 8 . 1

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

  32. 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
  33. 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
  34. 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
  35. > php ‐‐re sample Extension [ extension #26 sample version

    1.0 ] { ‐ Functions { Function [ function sample\helloWorld ] { } } } 8 . 6
  36. GLOBAL VARIABLE 9 . 1

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

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

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

  40. 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
  41. INITIALIZE VARIABLE sample.c PHP_RINIT_FUNCTION(sample) { SAMPLE_G(sample_value) = 21; } C

    9 . 6
  42. 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
  43. FUNCTION ARGUMENT \sample\hello('Universe'); PHP 10 . 1

  44. 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
  45. 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
  46. 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
  47. 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
  48. FUNCTION RETURN VALUE echo \sample\answer(); PHP 11 . 1

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

  50. TEMPLATES

  51. 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
  52. 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
  53. ARGUMENT INFO 12 . 1

  54. 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
  55. 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
  56. > php ‐‐re sample Extension [ <persistent> extension #26 sample

    version 1.0 ] { ‐ Functions { Function [ <internal:sample> function sample\hello ] { ‐ Parameters [1] { Parameter #0 [ <required> string $name ] } } } } 12 . 4
  57. 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
  58. > php ‐‐re sample Extension [ <persistent> extension #26 sample

    version 1.0 ] { ‐ Functions { Function [ <internal:sample> function sample\multiply ] { ‐ Parameters [2] { Parameter #0 [ <required> integer $first ] Parameter #1 [ <optional> integer $second ] } ‐ Return [ integer ] } } } 12 . 6
  59. 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
  60. TEMPLATES (2/2) 12 . 8

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

    PHP 13 . 1
  62. 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
  63. FUNCTION ARGUMENT: MIXED echo \sample\output(42), "\n"; echo \sample\output(FALSE), "\n"; echo

    \sample\output("Hello World"), "\n"; PHP 14 . 1
  64. FETCH ZVAL zval *value; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); C 14

    . 2
  65. 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
  66. CONVERT case IS_LONG : convert_to_string(value); php_printf("Integer: %s", Z_STRVAL_P(value)); break; C

    14 . 4
  67. 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
  68. MORE TEMPLATES Zend/zend_types.h Zend/zend_operators.h 14 . 6

  69. ZVAL 15 . 1

  70. _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
  71. _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
  72. _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
  73. 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

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

  75. 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
  76. 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
  77. FUNCTION ARGUMENT: VARIADICS echo \sample\hello('World', 'Universe', 42); PHP 17 .

    1
  78. IN PHP USERLAND function foo(...$bar) { foreach ($bar as $drink)

    { ... } } foo('Cola', 'Beer', 'Gin Tonic'); PHP 17 . 2
  79. 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
  80. 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
  81. CONSTANT echo Sample\SAMPLE_INT; PHP 18 . 1

  82. VALUE TEMPLATE #define SAMPLE_INT 42 C 18 . 2

  83. 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
  84. 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
  85. FLAGS CONST_CS - case sensitive CONST_PERSISTENT - persistent CONST_CT_SUBST -

    compile time substitution 18 . 5
  86. 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
  87. RESOURCE $r = sample\createResource(); sample\useResource($r); PHP 19 . 1

  88. DEFINE STRUCT php_sample.h typedef struct { zend_long number; } sample_resource;

    C 19 . 2
  89. 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
  90. 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
  91. 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
  92. 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
  93. FUNCTION ARGUMENT: CALLABLE echo \sample\hello( function() { return 'Universe'; }

    ); PHP 20 . 1
  94. 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
  95. 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
  96. GOAL 21

  97. PART II: OOP 22

  98. EXCEPTIONS 23 . 1

  99. SPL EXCEPTION try { echo \sample\trigger(); } catch (\LogicException $e)

    { echo $e­>getCode(), ' ­> ', $e­>getMessage(); } PHP 23 . 2
  100. THROW SPL EXCEPTION #include <zend_exceptions.h> #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
  101. CATCH EXCEPTION try { \sample\triggerException(); } catch (\Sample\ExceptionName $e) {

    echo $e­>getCode(), ' ­> ', $e­>getMessage(); } PHP 23 . 4
  102. 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
  103. THROW EXCEPTION PHP_FUNCTION(sample_trigger_exception) { zend_throw_exception_ex( sample_exception, 42, "Sample Exception Message"

    ); } C 23 . 6
  104. DEFINE CLASS 24 . 1

  105. 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
  106. 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
  107. FUNCTION ARGUMENT: CLASS Todo: validate argument 24 . 4

  108. FUNCTION ARGUMENT: OBJECT Todo: validate argument 24 . 5

  109. ARGUMENT INFO: OBJECT 24 . 6

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

    7
  111. ARGUMENT INFO: OBJECT OF CLASS 24 . 8

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

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

    } C 25 . 2
  114. 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
  115. 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
  116. CALL A METHOD class Hello { public function do($name) {

    printf("Hello %s!\n", $name); } } \sample\greet(new Hello("World")); PHP 26 . 1
  117. PREPARE PHP_FUNCTION(sample_greet) { zval fname, params[1], *greeting; ZVAL_STRING(&fname, "do"); ZVAL_STRING(&params[0],

    "World"); ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT(greeting) ZEND_PARSE_PARAMETERS_END(); C 26 . 2
  118. 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
  119. CLEANUP zval_dtor(&fname); zval_dtor(&params[0]); } C 26 . 4

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

  121. 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
  122. 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
  123. 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
  124. 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
  125. 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
  126. 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
  127. IMPLEMENT AN INTERFACE echo json_encode(new Sample\HelloWorld(), JSON_PRETTY_PRINT); PHP 29 .

    1
  128. 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
  129. 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
  130. 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
  131. INTERNAL DATA 30 . 1

  132. 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
  133. 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
  134. 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
  135. 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
  136. 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
  137. 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
  138. 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
  139. 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