Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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)

Thomas Weinert

May 31, 2017
Tweet

More Decks by Thomas Weinert

Other Decks in Programming

Transcript

  1. INTRODUCTION:
    PHP EXTENSIONS
    @ThomasWeinert
    1

    View Slide

  2. PART I: BASICS
    2

    View Slide

  3. REASONS
    Performance
    Memory
    Library
    Access
    3 . 1

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  8. 4 . 2

    View Slide

  9. 4 . 3

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  14. COMPILE
    6 . 1

    View Slide

  15. PHPIZE
    > phpize
    6 . 2

    View Slide

  16. PHPIZE
    > phpize
    6 . 3

    View Slide

  17. CONFIGURE
    > ./configure
    6 . 4

    View Slide

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

    View Slide

  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

    View Slide

  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‐[email protected]
    Do you want to send this report now? [Yns]:
    > export NO_INTERACTION=1
    6 . 7

    View Slide

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

    View Slide

  22. CLEAN
    > phpize ‐‐clean
    6 . 9

    View Slide

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

    View Slide

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

    View Slide

  25. PHPINFO()
    7 . 1

    View Slide

  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

    View Slide

  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

    View Slide

  28. OUTPUT
    7 . 4

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  36. GLOBAL VARIABLE
    9 . 1

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  50. TEMPLATES

    View Slide

  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

    View Slide

  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

    View Slide

  53. ARGUMENT INFO
    12 . 1

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  58. > 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

    View Slide

  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

    View Slide

  60. TEMPLATES (2/2)
    12 . 8

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  69. ZVAL
    15 . 1

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  81. CONSTANT
    echo Sample\SAMPLE_INT;
    PHP
    18 . 1

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    PHP
    20 . 1

    View Slide

  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

    View Slide

  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

    View Slide

  96. GOAL
    21

    View Slide

  97. PART II: OOP
    22

    View Slide

  98. EXCEPTIONS
    23 . 1

    View Slide

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

    View Slide

  100. 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

    View Slide

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

    View Slide

  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

    View Slide

  103. THROW EXCEPTION
    PHP_FUNCTION(sample_trigger_exception)
    {
    zend_throw_exception_ex(
    sample_exception, 42, "Sample Exception Message"

    }
    C
    23 . 6

    View Slide

  104. DEFINE CLASS
    24 . 1

    View Slide

  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

    View Slide

  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

    View Slide

  107. FUNCTION ARGUMENT: CLASS
    Todo: validate argument
    24 . 4

    View Slide

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

    View Slide

  109. ARGUMENT INFO: OBJECT
    24 . 6

    View Slide

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

    View Slide

  111. ARGUMENT INFO: OBJECT OF CLASS
    24 . 8

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  119. CLEANUP
    zval_dtor(&fname);
    zval_dtor(&params[0]);
    }
    C
    26 . 4

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  131. INTERNAL DATA
    30 . 1

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide