Save 37% off PRO during our Black Friday Sale! »

PHP 8 and Legacy Code

PHP 8 and Legacy Code

Presented on January 21st 2021 at the PHPcc Online Conference.
https://thephp.cc/dates/2021/01/the-online-php-conference
---------------------------------------------------------------
With the release of PHP 8, unit tests have become more important than ever before as there are numerous changes which can only be detected via tests.

But what if you maintain a legacy project which is still using PHPUnit 5? And what about extensions to this software running integration tests using (parts of) your test set up?

Using WordPress as an example, let's take a look at how a legacy project can prepare for compatibility with PHP 8 and at the problems they run into when paying up some of their technical debt. What are the extra complications they run into? And how to set priorities with the added time pressure of the PHP 8 release being around the corner?
---------------------------------------------------------------

2776198ea9584b6c0d4b494293b8d635?s=128

Juliette Reinders Folmer

January 21, 2021
Tweet

Transcript

  1. PHP 8 and Legacy Code A case-study Juliette Reinders Folmer

    Tweet about it: @jrf_nl #OnlinePHPConference © Sebastian Bergmann
  2. PHP 8 26 November 2020 © FlyClipArt

  3. New in PHP 8.0 Match control structure Attributes Nullsafe object

    operator Trailing comma in closure use Constructor property promotion Non capturing catch Union types Mixed type Static return type Throw expressions Stringable Magic method signature check Stable sorting ::class on objects Syntax tweaks Named arguments Reclassify engine warnings Saner numeric strings Saner string to number comparisons Locale independent float to string cast Stricter type check for arithmetic/ bitwise operators Consistent type errors for internal functions "bug fixes"
  4. An Example <?php declare(strict_types = 1); vprintf( 'The %s', 'dog'

    ); vprintf( 'The %s', ['dog'] ); PHP < 8.0 PHP 8.0 The dog Uncaught TypeError: vprintf(): The dog Argument #2 ($values) must be of type array, string given
  5. “ As a rare exception, this BC break will probably

    hit php-src harder than actual users of PHP "Backward Incompatible Changes" as per the Consistent type errors for internal functions RFC
  6. Another example <?php $sub = substr('abcdef', 4, -4); if ($sub

    === false) { echo 'fail'; } else { echo 'do something with $sub'; } PHP < 8.0 PHP 8.0 fail do something with $sub
  7. test Test TEST

  8. Test Requirements Have tests Strict assertions High code coverage, strictly

    measured Happy & unhappy path
  9. PHP 8 Compatibility Checklist ❑ Wait for PHP 8 compatible

    tooling ❑ Get the test suite running on PHP 8 ❑ Run static analysis ❑ Fix every issue ❑ Update external dependencies ❑ Review public parameter names
  10. WordPress A case-study

  11. WordPress Test Suite Have tests Strict assertions High code coverage,

    strictly measured Happy & unhappy path
  12. Testing WordPress on PHP 8 July August September October November

    December First PHP 8 tickets opened
  13. PHPUnit vs PHP PHPUnit / PHP 5.6 7.0 7.1 7.2

    7.3 7.4 8.0 5.x 6.x 7.x 8.x 9.x 9.3+ void
  14. Testing WordPress on PHP 8 July August September October November

    December First PHP 8 tickets opened Drop PHP < 7.1 ?
  15. Let's Look at the Stats

  16. Let's Look at the Stats

  17. Let's Look at the Stats

  18. Let's Look at the Stats

  19. Let's Look at the Stats

  20. Testing WordPress on PHP 8 July August September October November

    December First PHP 8 tickets opened Drop PHP < 7.1 ? Fixed rolling schedule proposal
  21. Constraints and Roadblocks ▪ Supporting PHP 5.6 + 7.0 still

    required ▪ Plugin tests often extend WP integration test suite ▪ PHPUnit < 9.3 not compatible with PHP 8.0 - Mocking - @runInSeparateProcess ▪ PHPUnit 7 Phar will not run on PHP 8.0 ▪ Committed composer.lock file
  22. Solution "autoload-dev": { "files": [ "tests/includes/MockObject/Builder/NamespaceMatch.php", "tests/includes/MockObject/Builder/ParametersMatch.php", "tests/includes/MockObject/InvocationMocker.php", "tests/includes/MockObject/MockMethod.php" ],

    "exclude-from-classmap": [ "vendor/phpunit/…/MockObject/Builder/NamespaceMatch.php", "vendor/phpunit/…/MockObject/Builder/ParametersMatch.php", "vendor/phpunit/…/MockObject/InvocationMocker.php", "vendor/phpunit/…/MockObject/MockMethod.php" ] }, ▪ Composer, not phar ▪ Lock at PHPUnit 7.5 ▪ Downgrade to PHPUnit 5 in CI for PHP 5.6, 7.0 ▪ Use MockObject classes from PHPUnit 9.3 ▪ Separate process => separate group
  23. Testing WordPress on PHP 8 July August September October November

    December First PHP 8 tickets opened Drop PHP < 7.1 ? Fixed rolling schedule proposal Tests running on PHP 8 Tests passing on PHP 8
  24. WordPress Test Suite Have tests Strict assertions High code coverage,

    strictly measured Happy & unhappy path
  25. Testing WordPress on PHP 8 July August September October November

    December First PHP 8 tickets opened Drop PHP < 7.1 ? Fixed rolling schedule proposal Tests running on PHP 8 Tests passing on PHP 8 WP/ PHP 8 compat report External dependency updates WP.5.6 released "beta" compatible with PHP 8
  26. "beta-compatible" Fix all KNOWN issues Undiscovered issues ? Parameter name

    review Plugins & themes not being compatible Plugins & themes doing it wrong™
  27. WordPress Plugins & Themes

  28. Test Requirements Happy & unhappy path High code coverage, strictly

    measured Strict assertions Have tests
  29. Constraints Support multiple WP versions Support multiple PHP versions No

    control over run environment
  30. Mock-based Tests PHPUnit 5.x composer.lock Platform - php 5.6 PHPUnit

    5.x – 9.x CI: composer update … --ignore-platform-reqs Needs PHPUnit cross-version compatibility layer
  31. WP Integration Tests PHPUnit 5.x composer.lock Platform - php 5.6

    PHPUnit 5.x – 7.x CI: composer update … --ignore-platform-reqs Need PHPUnit cross-version compatibility layer Need custom autoload for MockObject
  32. New Tooling PHPUnit Polyfills WP Test Utils Sponsored by: Alternative:

    Symfony Bridge * Supports PHPUnit 4.8 – 9.x, PHP 5.5 – 8.0
  33. “ The barrier for updating legacy code to use a

    more modern PHP version has gone up exponentially and for some, may even have become insurmountable. Juliette Reinders Folmer "A Perfect Storm"
  34. Further Reading ▪ The 2020 WordPress and PHP 8 Compatibility

    Report https://developer.yoast.com/blog/the-2020-wordpress-and-php-8- compatibility-report/ ▪ A Perfect Storm https://24daysindecember.net/2020/12/21/a-perfect-storm/ ▪ PHPUnit Polyfills https://packagist.org/packages/yoast/phpunit-polyfills ▪ WP Test Utils https://packagist.org/packages/yoast/wp-test-utils
  35. Thanks! Any questions ? Slides: https://speakerdeck.com/jrf Feedback: https://joind.in/talk/dafa1 @jrf_nl @jrfnl