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

Getting started with PHP core development - Dutch PHP Conference 2018

Getting started with PHP core development - Dutch PHP Conference 2018

Joind.in: https://joind.in/talk/4783a

While PHP’s open source community is thriving, only a relatively small number of PHP developers contribute to the number one tool they use on a daily basis: PHP itself. Although it may seem daunting to help out on a project written in C, requiring compilation and linking, getting started is actually pretty easy. In this talk I would like to share my own recent experiences of beginning to contribute to PHP itself. We will see different ways to contribute and cover some practical tips, workflows and resources, so you can start giving back to your programming language straight away!

8dfcb5f1b3cd5397f19780e2319694da?s=128

Arnout Boks

June 08, 2018
Tweet

Transcript

  1. Getting started with PHP core development @arnoutboks Arnout Boks #dpc18

    08-06-2018
  2. @arnoutboks #dpc18 PHP Open Source projects

  3. @arnoutboks #dpc18 PHP Open Source projects 4175 contributors 418 contributors

    689 contributors 1497 contributors
  4. @arnoutboks #dpc18 PHP Open Source projects 4175 contributors 418 contributors

    689 contributors 1497 contributors
  5. @arnoutboks #dpc18 PHP Open Source projects 4175 contributors 418 contributors

    689 contributors 1497 contributors 497 contributors?
  6. @arnoutboks #dpc18 We all use PHP intensively Why not contribute

    something back?
  7. @arnoutboks #dpc18 The catch

  8. @arnoutboks #dpc18 The catch

  9. @arnoutboks #dpc18 The core

  10. @arnoutboks #dpc18 The core

  11. @arnoutboks #dpc18 My own journey to the core

  12. @arnoutboks #dpc18 Once upon a time… <something xmlns:foo="http://www.example.com"> <foo:bar />

    <bar /> </something> <?php $doc = /* … (DOMDocument) */; $doc->getElementsByTagName( "bar" )->length;
  13. @arnoutboks #dpc18 Once upon a time… <something xmlns:foo="http://www.example.com"> <foo:bar />

    <bar /> </something> <?php $doc = /* … (DOMDocument) */; $doc->getElementsByTagName( "bar" )->length; // returns 2
  14. @arnoutboks #dpc18 Once upon a time… <something xmlns:foo="http://www.example.com"> <foo:bar />

    <bar /> </something> <?php $doc = /* … (DOMDocument) */; $doc->getElementsByTagNameNS( "http://www.example.com", "bar" )->length;
  15. @arnoutboks #dpc18 Once upon a time… <something xmlns:foo="http://www.example.com"> <foo:bar />

    <bar /> </something> <?php $doc = /* … (DOMDocument) */; $doc->getElementsByTagNameNS( "http://www.example.com", "bar" )->length; // returns 1
  16. @arnoutboks #dpc18 Once upon a time… <something xmlns:foo="http://www.example.com"> <foo:bar />

    <bar /> </something> <?php $doc = /* … (DOMDocument) */; $doc->getElementsByTagNameNS( "", "bar" )->length;
  17. @arnoutboks #dpc18 Once upon a time… <something xmlns:foo="http://www.example.com"> <foo:bar />

    <bar /> </something> <?php $doc = /* … (DOMDocument) */; $doc->getElementsByTagNameNS( "", "bar" )->length; // returns 0!
  18. @arnoutboks #dpc18 Once upon a time…

  19. Reporting bugs Gotta squash them all

  20. @arnoutboks #dpc18 bugs.php.net PHP bug tracker

  21. @arnoutboks #dpc18 Write good bug reports https://bugs.php.net/how-to-report.php

  22. @arnoutboks #dpc18 Search for existing bugs

  23. @arnoutboks #dpc18 Sharpen bug details Report different platform/version: Don’t post

    “me too” comments – Do post other relevant details
  24. @arnoutboks #dpc18 Help triaging bugs! https://bugs.php.net/random

  25. Building PHP from git Living on the edge

  26. @arnoutboks #dpc18 1. Install dependencies • git • build-essential •

    autoconf • automake • libtool • re2c • bison • libxml2-dev Using apt-get, yum or similar
  27. @arnoutboks #dpc18 2. Clone php-src $ git clone https://github.com/php/php- src.git

  28. @arnoutboks #dpc18 3. Generate ./configure script $ ./buildconf Uses autoconf

    to build ./configure from: • configure.ac • acinclude.m4 • sapi/*/config.m4 • ext/*/config.m4
  29. @arnoutboks #dpc18 4. Run ./configure script $ ./configure Configure a

    default PHP build: $ ./configure --disable-cgi --disable-dom --enable-opcache --with-sqlite3=/path /to/sqlite3 Customize extensions/SAPIs: $ ./configure --help See all options
  30. @arnoutboks #dpc18 5. Compile $ make $ make –j`nproc` To

    use all available cores (faster):
  31. @arnoutboks #dpc18 6. Run! $ sapi/cli/php --version Binaries are in

    sapi/cli/php and sapi/cgi/php-cgi:
  32. @arnoutboks #dpc18 Subsequent builds $ make Just run Recompiles only

    files that have changed
  33. @arnoutboks #dpc18 Cleanup scripts $ make clean # try again

    $ make distclean # try again $ ./buildconf –force $ ./configure # try again If compilation fails, try (subsequently): Might be needed after git pull/git checkout
  34. @arnoutboks #dpc18 https://wiki.php.net/ internals/windows/stepbystepbuild Building for Windows

  35. @arnoutboks #dpc18

  36. @arnoutboks #dpc18 • ramsey/vagrant-php-src- dev • rlerdorf/php7dev Vagrant boxes for

    compiling PHP
  37. @arnoutboks #dpc18 Or use Docker: aboks/php-src-devtools

  38. @arnoutboks #dpc18 Using php-src-devtools $ composer global require aboks/php-src- devtools

    $ git clone https://github.com/php/php- src.git && cd php-src $ php-src-devtools build
  39. Running tests for PHP Human-driven CI

  40. @arnoutboks #dpc18 Running tests $ sapi/cli/php run-tests.php –p `pwd`/sapi/cli/php

  41. @arnoutboks #dpc18 Running tests $ sapi/cli/php run-tests.php –p `pwd`/sapi/cli/php $

    sapi/cli/php run-tests.php -P
  42. @arnoutboks #dpc18 Running tests $ sapi/cli/php run-tests.php –p `pwd`/sapi/cli/php $

    sapi/cli/php run-tests.php -P $ make test # (or, with php-src-devtools) $ php-src-devtools test
  43. @arnoutboks #dpc18 Running tests $ make test […] PASS Trivial

    "Hello World" test [tests/basic/001.phpt] SKIP Check libcurl config on windows [ext/curl/tests/check_win_config.phpt] reason: for windows only FAIL Compiled regex cache limit [ext/pcre/tests/cache_limit.phpt] XFAIL Inconsistencies when accessing protected members [Zend/tests/access_modifiers_008.phpt] XFAIL REASON: Discussion: http://marc.info/?l=php- internals&m=120221184420957&w=2 […10000 more lines of output…]
  44. @arnoutboks #dpc18 Running tests $ make test […] ========================================= TEST

    RESULT SUMMARY ----------------------------------------- Number of tests : 14896 12520 Tests skipped : 2376 ( 16.0%) -------- Tests warned : 2 ( 0.0%) ( 0.0%) Tests failed : 175 ( 1.2%) ( 1.4%) Expected fail : 44 ( 0.3%) ( 0.4%) Tests passed : 12299 ( 82.6%) ( 98.2%) ----------------------------------------- Time taken : 2937 seconds
  45. @arnoutboks #dpc18 Running tests $ make test […] You may

    have found a problem in PHP. 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 later. Do you want to send this report now? [Yns]:|
  46. @arnoutboks #dpc18 Options for running tests $ make test TESTS=path/to/my/test.phpt

    $ make test TESTS=ext/dom $ make test TESTS="--verbose ext/dom" $ make test TESTS=--help
  47. Writing tests for PHP “the best bug report”

  48. @arnoutboks #dpc18 Steps to reproduce for bug #67474 Test script:

    --------------- $doc = new DOMDocument(); $doc->loadXML('<root xmlns:x="x"><a/><x:a/></root>'); $list = $doc->getElementsByTagNameNS('', 'a'); echo $list->length; Expected result: ---------------- 1 Actual result: -------------- 0
  49. @arnoutboks #dpc18 Testing tools Typical PHP project: • Written in

    PHP • Tests written in PHP (PHPUnit, PHPSpec, CodeCeption) The PHP core: • Written in C • Tests written in …
  50. @arnoutboks #dpc18 PHP is tested using PHPT tests No C

    skills required
  51. @arnoutboks #dpc18 PHPT tests • Basically plaintext with sections •

    Some sections (can) contain PHP code • Let PHP print some output… • …and check against expected output
  52. @arnoutboks #dpc18 Very simple PHPT test --TEST-- Basic arithmetic -

    addition --FILE-- <?php var_dump(42 + 1); ?> --EXPECT-- int(43)
  53. @arnoutboks #dpc18 Very simple PHPT test --TEST-- Basic arithmetic -

    addition --FILE-- <?php var_dump(42 + 1); ?> --EXPECT-- int(43)
  54. @arnoutboks #dpc18 PHPT test for bug #67474 --TEST-- Bug #67474

    getElementsByTagNameNS and default namespace --FILE-- <?php $doc = new DOMDocument(); $doc->loadXML('<root xmlns:x="x"><a/><x:a/></root>'); $list = $doc->getElementsByTagNameNS('', 'a'); var_dump($list->length); ?> --EXPECT-- int(1)
  55. @arnoutboks #dpc18 Running our PHPT test $ make test TESTS=ext/dom/tests/bug67474.phpt

    […] ============================================= FAILED TEST SUMMARY --------------------------------------------- Bug #67474 getElementsByTagNameNS and default namespace [ext/dom/tests/bug67474.phpt] =============================================
  56. @arnoutboks #dpc18 Running our PHPT test Files generated for our

    failing test: bug67474.php contents of the FILE section bug67474.sh shell script for running the .php file bug67474.exp expected output bug67474.out actual output bug67474.diff diff between expected and actual bug67474.log log file, including the expected and actual output
  57. @arnoutboks #dpc18 Running our PHPT test $ cat ext/dom/tests/bug67474.log ----

    EXPECTED OUTPUT int(1) ---- ACTUAL OUTPUT int(0) ---- FAILED
  58. @arnoutboks #dpc18 Running our PHPT test

  59. @arnoutboks #dpc18 Sections in PHPT files GET, POST, PUT, COOKIE,

    HEADERS: Simulate HTTP input to the PHP script in FILE --GET-- foo=bar&baz=qux --COOKIE-- foo=bar;baz=qux --FILE-- <?php var_dump($_GET['foo'] . $_COOKIE['foo']); ?> --EXPECT-- string(6) "barbar"
  60. @arnoutboks #dpc18 Sections in PHPT files EXPECTF, EXPECTREGEX: Expect the

    output to match a certain format --FILE-- <?php $fp = fopen(__FILE__, 'r'); var_dump($fp); ?> --EXPECTF-- resource(%d) of type (stream)
  61. @arnoutboks #dpc18 More sections in PHPT files SKIPIF: Skips the

    test if the code in SKIPIF generates output containing ‘skip’ somewhere CLEAN: Cleans up after the test INI: Specifies custom php.ini directives for the test XFAIL: Indicates the test is expected to fail, and gives an explanation why
  62. @arnoutboks #dpc18 Easy way to get started without C skills

  63. @arnoutboks #dpc18 Finding untested code gcov.php.net

  64. @arnoutboks #dpc18 Resources • https://qa.php.net/write-test.php • https://www.sammyk.me/compiling-php-from-source- writing-tests-for-php-source • https://phptestfest.org/tutorials/

    • http://www.phpinternalsbook.com/#testing-php- source • https://github.com/PHPTestFestBrasil/phptt • https://gist.github.com/SammyK/4a5cf70d0973731d0c 85b151a323ea2d
  65. Editing the PHP source Your own custom PHP

  66. @arnoutboks #dpc18 A shot at fixing #67474: recap <something xmlns:foo="http://www.example.com">

    <foo:bar /> <bar /> </something> <?php $doc = /* … (DOMDocument) */; $doc->getElementsByTagNameNS( "", "bar" )->length; // returns 0!
  67. @arnoutboks #dpc18 A shot at fixing #67474 php-src/ext/dom/ • attr.c

    • document.c • dom_ce.h • dom_fe.h • element.c • node.c • php_dom.c • xpath.c • …
  68. @arnoutboks #dpc18 A shot at fixing #67474 const zend_function_entry php_dom_document_class_functions[]

    = { // ... PHP_FALIAS(createAttributeNS, dom_document_create_attribute_ns, arginfo_dom_document_create_attribute_ns) PHP_FALIAS(getElementsByTagNameNS, dom_document_get_elements_by_tag_name_ns, arginfo_dom_document_get_elements_by_tag_name_ns) PHP_FALIAS(getElementById, dom_document_get_element_by_id, arginfo_dom_document_get_element_by_id) // ... PHP_ME(domdocument, __construct, arginfo_dom_document_construct, ZEND_ACC_PUBLIC) PHP_FE_END };
  69. @arnoutboks #dpc18 C macros

  70. @arnoutboks #dpc18 C macros #define MIN(a,b) a < b ?

    a : b int c = MIN(42,7) // ^ is converted into // int c = 42 < 7 ? 42 : 7
  71. @arnoutboks #dpc18 A shot at fixing #67474 const zend_function_entry php_dom_document_class_functions[]

    = { // ... PHP_FALIAS(createAttributeNS, dom_document_create_attribute_ns, arginfo_dom_document_create_attribute_ns) PHP_FALIAS(getElementsByTagNameNS, dom_document_get_elements_by_tag_name_ns, arginfo_dom_document_get_elements_by_tag_name_ns) PHP_FALIAS(getElementById, dom_document_get_element_by_id, arginfo_dom_document_get_element_by_id) // ... PHP_ME(domdocument, __construct, arginfo_dom_document_construct, ZEND_ACC_PUBLIC) PHP_FE_END };
  72. @arnoutboks #dpc18 A shot at fixing #67474 PHP_FUNCTION(dom_document_get_elements_by_tag_name_ns) { //

    ... if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss", &id, dom_document_class_entry, &uri, &uri_len, &name, &name_len) == FAILURE) { return; } // ... local = xmlCharStrndup(name, name_len); nsuri = xmlCharStrndup(uri, uri_len); dom_namednode_iter(intern, 0, namednode, NULL, local, nsuri); }
  73. @arnoutboks #dpc18 zend_parse_parameters (‘ZPP’) PHP_FUNCTION(dom_document_get_elements_by_tag_name_ns) { // ... if (zend_parse_method_parameters(ZEND_NUM_ARGS(),

    getThis(), "Oss", &id, dom_document_class_entry, &uri, &uri_len, &name, &name_len) == FAILURE) { return; } // ... local = xmlCharStrndup(name, name_len); nsuri = xmlCharStrndup(uri, uri_len); dom_namednode_iter(intern, 0, namednode, NULL, local, nsuri); } s: string s: string O: object of given class
  74. @arnoutboks #dpc18 zend_parse_parameters (‘ZPP’) Specifier Type a array b boolean

    d double/float l long/int o object (any type) O object (specific type) r resource s string z mixed
  75. @arnoutboks #dpc18 zend_parse_parameters (‘ZPP’) Modifier Effect * variable number of

    arguments (0 or more) + variable number of arguments (1 or more) ! optional argument | remaining arguments are optional See README.PARAMETER_PARSING_API
  76. @arnoutboks #dpc18 A shot at fixing #67474 PHP_FUNCTION(dom_document_get_elements_by_tag_name_ns) { //

    ... if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss", &id, dom_document_class_entry, &uri, &uri_len, &name, &name_len) == FAILURE) { return; } // ... local = xmlCharStrndup(name, name_len); nsuri = xmlCharStrndup(uri, uri_len); dom_namednode_iter(intern, 0, namednode, NULL, local, nsuri); }
  77. @arnoutboks #dpc18 A shot at fixing #67474 xmlNode *dom_get_elements_by_tag_name_ns_raw( xmlNodePtr

    nodep, char *ns, char *local /* ... */ ) { // ... if ( ns == NULL || (nodep->ns != NULL && ( xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns) )) ) { /* namespace matches */ } // ... } Eventually:
  78. @arnoutboks #dpc18 A shot at fixing #67474 xmlNode *dom_get_elements_by_tag_name_ns_raw( xmlNodePtr

    nodep, char *ns, char *local /* ... */ ) { // ... if ( ns == NULL || (nodep->ns != NULL && ( xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns) )) ) { /* namespace matches */ } // ... } Eventually: element to ‘test’ filter namespace and local name
  79. @arnoutboks #dpc18 A shot at fixing #67474 xmlNode *dom_get_elements_by_tag_name_ns_raw( xmlNodePtr

    nodep, char *ns, char *local /* ... */ ) { // ... if ( ns == NULL || (nodep->ns != NULL && ( xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns) )) ) { /* namespace matches */ } // ... } Eventually: “no namespace filter”
  80. @arnoutboks #dpc18 A shot at fixing #67474 xmlNode *dom_get_elements_by_tag_name_ns_raw( xmlNodePtr

    nodep, char *ns, char *local /* ... */ ) { // ... if ( ns == NULL || (nodep->ns != NULL && ( xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns) )) ) { /* namespace matches */ } // ... } Eventually: “node has a namespace”, and “it matches the filter” or “filter is a wildcard”
  81. @arnoutboks #dpc18 A shot at fixing #67474 xmlNode *dom_get_elements_by_tag_name_ns_raw( xmlNodePtr

    nodep, char *ns, char *local /* ... */ ) { // ... if ( ns == NULL || (nodep->ns == NULL && !strcmp(ns, "")) || (nodep->ns != NULL && ( xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns) )) ) { /* namespace matches */ } // ... } Fix: “node has empty namespace”, and “filter is empty namespace”
  82. @arnoutboks #dpc18 A shot at fixing #67474 $ make test

    TESTS=ext/dom/tests/bug67474.phpt […] ============================================= Running selected tests. PASS Bug #67474 getElementsByTagNameNS and default namespace [ext/dom/tests/bug67474.phpt] ============================================= Number of tests : 1 1 Tests passed : 1 (100.0%) (100.0%)
  83. @arnoutboks #dpc18 PR for #67474 Submit bug fixes to the

    oldest supported branch: http://php.net/supported-versions.php
  84. @arnoutboks #dpc18 The Release Managers PHP 7.1 Davey Shafik @dshafik

    Joe Watkins @krakjoe PHP 7.2 Remi Collet @RemiCollet Sara Golemon @SaraMG PHP 7.3 Christoph M. Becker @cmbecker69 Stanislav Malyshev @smalyshev
  85. @arnoutboks #dpc18 PR for #67474: 2 hours later…

  86. @arnoutboks #dpc18 It’s not THAT difficult • Read past the

    C details and macros • Focus on the logic • See where variables come from and go to • Try and see what happens • Rely on the tests
  87. @arnoutboks #dpc18 You can do this!

  88. @arnoutboks #dpc18 Bug fixes vs. features • Bug fixes •

    PR against oldest supported branch • No RFC needed • Refer to bug in bug tracker • Features • PR against master • Formal RFC needed
  89. @arnoutboks #dpc18 RFC Process • Introduce idea, measure initial reaction

    • Formal proposal • Discussion period • Voting See https://wiki.php.net/rfc/howto & https://benramsey.com/talks/2015/06/dpc-contributing-core/
  90. @arnoutboks #dpc18 Resources • http://php.net/internals • https://wiki.php.net/internals • https://wiki.php.net/internals/references •

    http://www.phpinternalsbook.com/ • http://blog.jpauli.tech/ • https://nikic.github.io/ • https://blog.ircmaxell.com/search/label/PHP-Internals • https://www.sammyk.me/how-to-find-and-patch-a- bug-in-php-source-php-internals • https://externals.io
  91. @arnoutboks #dpc18 Some time later…

  92. Documentation for PHP Contributing to the manual

  93. @arnoutboks #dpc18 edit.php.net PHP Docbook Online Editor ‘Easiest’ way to

    get started (if you can figure out how it works)
  94. @arnoutboks #dpc18 edit.php.net

  95. @arnoutboks #dpc18 edit.php.net

  96. @arnoutboks #dpc18 edit.php.net

  97. @arnoutboks #dpc18 1. Find the correct file Under “All files”

    in the left menu Top-level directory per language • reference/<ext|group>/ • functions/<function>.xml • <class>.xml • <class>/<method>.xml • language/<feature>.xml
  98. @arnoutboks #dpc18 1. Find the correct file Tip: Use the

    “edit” link from the documentation itself
  99. @arnoutboks #dpc18 2. Make your changes Documentation is written using

    DocBook XML http://tdg.docbook.org/tdg/5.2/
  100. @arnoutboks #dpc18 2. Make your changes Documentation is written using

    DocBook XML (or just peek in other docs)
  101. @arnoutboks #dpc18 3. Preview changes Seems broken at the moment

  102. @arnoutboks #dpc18 4. Submit as patch

  103. @arnoutboks #dpc18 Tip: submit a docs patch instead of user

    note
  104. @arnoutboks #dpc18 Don’t like edit.php.net? Make it better!

  105. @arnoutboks #dpc18 Don’t like edit.php.net? Or set up your own

    development environment: https://www.sammyk.me/how-to-contribute-to-php- documentation
  106. @arnoutboks #dpc18 Where to help? • Bugs of type “Doc”

    in bug tracker • check-missing-docs.php • “Failures to meet strict standards” (in edit.php.net sidebar) • Translations • Missing translations • Out-of-date translations • Translations needing review • Translations with errors
  107. @arnoutboks #dpc18 Where to help?

  108. Recap Ways to contribute to PHP

  109. @arnoutboks #dpc18 Numerous ways to contribute • Bug reports •

    Bug triaging • Running tests • Writing tests • Bug fixes • New features • Documentation patches • Documentation translations • Tools
  110. @arnoutboks #dpc18 Why contribute? • Get ‘own’ bugs fixed •

    Fix ‘own’ bugs • Make PHP better • Make PHP more popular • Learn PHP • Learn C • Give back to the community
  111. @arnoutboks #dpc18 You don’t have to be an expert to

    contribute to the PHP core
  112. @arnoutboks #dpc18 Feedback & Questions @arnoutboks @arnoutboks @aboks Arnout Boks

    Please leave your feedback on joind.in: https://joind.in/talk/4783a
  113. @arnoutboks #dpc18 Image Credits • https://photojournal.jpl.nasa.gov/jpeg/PIA19058.jpg • https://www.flickr.com/photos/vivianejl/22990832 • https://www.flickr.com/photos/dhuiz/13609080315/

    • https://www.flickr.com/photos/gotovan/8671348572 • https://www.flickr.com/photos/sidelong/246816211 • https://www.flickr.com/photos/pezon64/23764268828 • https://www.flickr.com/photos/crdot/6855538268/ • https://www.flickr.com/photos/borkurdotnet/9682277597