[phpDay 2015] Writing Faster PHP with HHVM and Hack

[phpDay 2015] Writing Faster PHP with HHVM and Hack

HHVM is the new hotness, a super-fast alternative PHP runtime from Facebook it can take your existing PHP code base and run it at blazing fast speeds... but is there more?

HHVM also introduces Hack. Hack adds numerous features to the PHP language that help speed up both development time and runtime performance.

Get the most out of your human and technical resources by using HHVM and Hack today!

Fee39f0c0ffb29d9ac21607ed188be6b?s=128

Davey Shafik

May 16, 2015
Tweet

Transcript

  1. Writing Faster PHP with HHVM and Hack

  2. Proprietary and Confidential •Community Engineer at Engine Yard •Author of

    Zend PHP 5 Certification Study Guide, Sitepoints PHP Anthology: 101 Essential Tips, Tricks & Hacks & PHP Master: Write Cutting Edge Code •A contributor to Zend Framework 1 & 2, phpdoc, & PHP internals • Original creator of PHAR/ PHP_Archive •@dshafik Davey Shafik
  3. Let’s start a conversation about mental health in tech mhprompt.org

  4. Proprietary and Confidential

  5. Proprietary and Confidential

  6. Proprietary and Confidential

  7. Proprietary and Confidential

  8. Proprietary and Confidential

  9. Proprietary and Confidential

  10. A Brief History of HipHop VM Better known as HHVM

  11. HPHPc 2009 - 2012

  12. Proprietary and Confidential • Cross-compiler: PHP -> C++ • Needed

    to compile for every change, which took hours • Created huge binaries (approaching 2GB Linux “limit”) • PHP 5.2 (ish) feature-set • Missing support for large parts of the language (e.g. all 5.3+ features including namespaces, closures, and dynamic features like create_function(), and eval()) • Broke the developer workflow HPHPc — 2009 - 2012
  13. HipHop VM (HHVM) 2013 -

  14. Proprietary and Confidential • Alternate interpreted runtime with JIT compiler

    • No compiling process • Twice as fast as PHP in interpreted mode. • Ludicrous speed for JITed code • Bug-for-bug compatible with PHP • 5.6 feature set (e.g. support for variadics, splat) • Working on PHP 7 support HHVM
  15. Hack A super-set of PHP

  16. Proprietary and Confidential • AKA Hacklang (because “Hack” is un-google-able)

    • A syntactic super-set of PHP that allows for strong typing via static analysis. Adds support for: • type hinting • generics • async functions • annotations • more… • A language sub-set of PHP that disallows a number of bad practices • variable-variables • globals • mixing HTML & PHP • more… Hack
  17. Performance

  18. Proprietary and Confidential 0 75 150 225 300 Wordpress 3.9

    SugarCRM CE 6.5.16 - login page Drupal 7.28 homepage Symfony 2.5 ACME app home page ZF 2.3.1 Skeleton App Magento 1.9 Homepage Magento 1.9 item page PHP 5.4 (no OPcache) PHP 5.5 PHP 5.6 hhvm 3.1 (prebuilt binaries) hhvm 3.2-dev(src) PHPNG Source: Zeev Suraski http://zsuraski.blogspot.com/2014/07/benchmarking-phpng.html
  19. Proprietary and Confidential • Facebook (#2) • Baidu (#5, #1

    Search Engine in China) • Wikimedia (incl. Wikipedia, #6) • Etsy (for their API) That’s 3 of the top 4 PHP sites in the world, and ~1/3 of the top 10 overall. (Yahoo! is the outlier, FYI) Actual Users
  20. Repo Authoritative Mode Ludicrous Speed!

  21. Proprietary and Confidential • When code “never” changes (e.g. production)

    • Extra 20-25% performance increase (similar to apc.stat = 0) • Spends extra time on caching/JITing for maximum performance Repo Authoritative Mode
  22. HHVM Setup

  23. Proprietary and Confidential login.php HHVM Setup Nginx php-fpm mysql,pgsql,mongo,
 gearman,redis,

    etc. index.php
  24. Proprietary and Confidential login.php HHVM Setup Nginx mysql,pgsql,mongo,
 gearman,redis, etc.

    index.php HHVM
  25. Proprietary and Confidential server { server_name _; root /var/www; index

    index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/hhvm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /var/www$fastcgi_script_name; include fastcgi_param; } } HHVM Setup
  26. Proprietary and Confidential hhvm.server.file_socket = /var/run/hhvm.sock hhvm.server.type = fastcgi hhvm.server.source_root

    = /var/www hhvm.log.level = Error hhvm.log.user_log_file = true hhvm.log.file = /var/log/hhvm-error.log hhvm.log.access.0.file = /var/log/hhvm-access.log hhvm.log.access.0.format=%h %l %u %t \"%r\" %>s %b HHVM Setup $ hhvm -m daemon -c /etc/hhvm/hhvm.ini -u www-data
  27. Long Term Support

  28. Proprietary and Confidential Long Term Support Version name Intended release

    date LTS? End of support 3.3 11 19 Sep 2014 yes 13 Aug 2015 3.4 6 Nov 2014 3.5 1 Jan 2015 3.6 26 Feb 2015 yes 28 Jan 2016 3.7 23 Apr 2015 3.8 18 Jun 2015 3.9 13 Aug 2015 yes 14 Jul 2016 3.10 8 Oct 2015 3.11 3 Dec 2015 3.12 28 Jan 2016 yes 29 Dec 2016 3.13 24 Mar 2016 3.14* 19 May 2016 3.15* 14 Jul 2016 yes 15 Jun 2017
  29. Hack A better PHP

  30. Proprietary and Confidential • Not a new language • Runs

    through the same HHVM runtime • Strongly typed… but thrown away at run time (type erasure) • Super-fast static analysis • Strict typing informs the runtime to enable better performance Hack A primary goal of hack is to not [negatively] impact the developers workflow — especially the REPL; whereby we can edit code and refresh our browser to immediately see changes. “ ” - Davey Shafik
  31. Editor Support

  32. Editor Support Supports any editor (so long it’s vim or

    emacs)
  33. Coming Soon: phpStorm Yay!

  34. File Semantics

  35. Proprietary and Confidential • To promote best practices, you cannot

    mix Hack with HTML (or other non-code text) • All hack files must start with <?hh • There is no closing tag for hack files • Hack also has multiple modes • XHTML can be embedded using XHP, which makes XHTML tags into language constructs File Semantics
  36. Hack Modes

  37. Partial Mode

  38. Proprietary and Confidential • Default • Gradual Typing • Types

    are strictly adhered to however: • Not everything must be typed • May call into regular PHP code without error Partial Mode <?hh // Code goes here
  39. Strict Mode

  40. Proprietary and Confidential • All code must be typed •

    Cannot call into non-Hack code • No top-level code • This means your codebase cannot be 100% strict • Arrays must be type hinted • Collections (Vector, Set, Map, Tuple) are preferred Strict Mode <?hh // strict // Code goes here
  41. Declarations Mode AKA Decl

  42. Proprietary and Confidential • Type hints are trusted but not

    required Declarations Mode <?hh // decl // Code goes here
  43. Ignoring Errors

  44. Proprietary and Confidential • You can ignore errors by marking

    code as UNSAFE • Applied from the comment to the end of the current block: typically the next curly brace “}” • Should be the last resort • May result in run-time errors due to the lack of validation Ignoring Errors // UNSAFE
  45. Type Hints

  46. Proprietary and Confidential • Method Arguments • Return Values •

    Class Properties Type Hints
  47. Proprietary and Confidential Types Type bool Boolean true/false Type Name

    int Integer numbers float Floating Point numbers string Strings array Arrays (that can be typed) resource Resources (e.g. file streams) Class/Interface Name An object type-hint
  48. Proprietary and Confidential Types (Cont.) Type Name mixed Any (not

    recommended) Vector Numerical contiguously indexed Arrays Map A typed (both keys and values) associative array Set An unindexed collection of typed unique values Tuple A fixed size set of typed values Pair A fixed size set of typed values restricted to two values, indexed as 0 and 1.
  49. Proprietary and Confidential • void — for functions with no

    return value • this — always refers to $this Special Types
  50. Nullable Types

  51. Proprietary and Confidential • Allows for nulls to be passed

    in addition to the specified type • Prefix the type with a ? • e.g. ?int or ?\DateTime. Nullable Types <?hh
 class DBAdapter { public function connect(?string $dsn): ?\PDO { // $dsn may be null // may return an instance of \PDO or null on error } }
  52. Soft Types

  53. Proprietary and Confidential • You can denote the a type-failure

    should not error by using soft types. • This is great for migrating codebases • To do this precede the type with an @ • e.g. @int or @\DateTime. Soft Types <?hh class Calculator { public function add(@int $a, @int $b): @int { // Both $a and $b may not be ints // May not return an int } } $calc = new Calculator(); $calc->add("1", "2");
  54. Custom Types

  55. Proprietary and Confidential • Type Aliases (type) • Opaque Types

    (newtype) • Only used for static analysis. Custom Types
  56. Proprietary and Confidential <?hh // strict type HTTPStatusCode = int;

    class HTTPStatus { const HTTPStatusCode OK = 200; const HTTPStatusCode FOUND = 302; const HTTPStatusCode NOT_FOUND = 404; protected Map<HTTPStatusCode, string> $status = Map { self::OK => "200 OK", self::FOUND => "302 Found", self::NOT_FOUND => "404 Not Found", }; public function send(HTTPStatusCode $code): bool { if (isset($this->status[$code])) { header('HTTP/1.1 ' .$this->status[$code]); return true; } return false; } }
  57. Proprietary and Confidential <?hh function notFound() { $status = new

    HTTPStatus(); $status->send(404); }
  58. Proprietary and Confidential • Allows you to give more appropriate

    names to existing types • e.g. unixtime for int Type Aliases
  59. Proprietary and Confidential • Opaque types hide their underlying implementation

    outside of the file in which the type is defined. • This means they become immutable except when called in code defined in that file • This restriction is not enforced at runtime Opaque Types
  60. Proprietary and Confidential newtype HTTPStatusCode = int;

  61. Proprietary and Confidential <?hh function notFound() { $status = new

    HTTPStatus(); $status->send(HTTPStatus::NOT_FOUND); }
  62. Constructor Argument Promotion

  63. Proprietary and Confidential Constructor Property Assignment <?php class Adder {

    private $left; private $right; public function __construct($left, $right) { $this->left = $left; $this->right = $right; } }
  64. Proprietary and Confidential • Automatically create properties from constructor arguments

    • Just precede the argument with a visibility keyword: public, private, protected Constructor Argument Promotion <?hh class Adder { public function __construct(private int $left, private int $right): void { } public function get(): int { return $this->left + $this->right; } } $adder = new Adder(1, 3); $result = $adder->get(); // 4
  65. Collections

  66. Proprietary and Confidential • Arrays — must be typed in

    strict mode • Tuples — typed arrays • Pairs — can only contain 2 pieces of data • Vectors — numerically, consecutively keyed only • Maps — ordered dictionaries that allow int or string keys • Sets — unordered collection of unique values • Immutable variants Collections
  67. Arrays

  68. Proprietary and Confidential • array — Untyped (only allowed in

    partial mode) • array<[type]> — [type] typed values, with integer keys • array<[type1], [type2]> — [type1] typed keys, with [type2] typed values. Arrays <?hh // strict function createArray(): array<int> { return array(1, 2, 3); }
  69. Tuples

  70. Proprietary and Confidential • Internally identical to arrays • Fixed

    size • Implicitly Type hinted by the values used to define it or • Explicitly Type hinted using the literal syntax Tuples <?hh
 function createTuple(): void { $foo = tuple(1, 2, "3"); // Do more with the tuple } function createTuple(): (int, int, string) { return tuple(1, 2, "3"); }
  71. Pairs

  72. Proprietary and Confidential • Can contain only two values, keyed

    as 0 and 1 • Immutable Pairs <?hh // strict function getTask(): Pair<string, string> { return Pair { "C039D17D", "checkPing" }; }
  73. Vectors

  74. Proprietary and Confidential • Vectors can only use integer keys

    Vectors <?hh // strict function getCommunityEngineers(): Vector<string> { return Vector {"Davey", "PJ", "You?"}; }
  75. Maps

  76. Proprietary and Confidential • Maps are an ordered dictionary, which

    can have integer or string keys. • Must specify both key and values types when type hinting. Maps <?hh // strict function getTags(): Map<string, string> { return Map {"php" => "PHP", "hack" => "Hack"}; }
  77. Sets

  78. Proprietary and Confidential • Unordered Collection with no keys •

    Unique values <?hh // strict function getTags(): Set<string> { return Set { "php", "hack", "hhvm" }; }
  79. Immutability

  80. Proprietary and Confidential • Simply prefix the class name with

    Imm Immutability <?hh // strict function getTags(): ImmMap<string, string> { $map = ImmMap {"php" => "PHP", "hack" => "Hack"}; $map["hhvm"] = "HHVM"; } <file>|13 col 6 error| You cannot mutate this <file>|12 col 13 error| This is an object of type ImmMap
  81. Appending Elements

  82. Proprietary and Confidential • Only Vectors allow $foo[] = "bar"

    syntax • Pairs and Tuples do not allow additional elements • Maps allow appending of Pairs. First value is key, second value is value Appending Elements <?hh // strict function appendToMap(): void { $m = Map { 0 => "foo", 1 => "bar" }; $m[] = Pair { 5, "bat" }; var_dump($m); }
  83. Object Oriented Interface

  84. Proprietary and Confidential • Based on the SPL • Allows

    adding/removing/manipulation methods • Allows you to use them as objects, rather than just “better” arrays Object Oriented Interface
  85. Breaking Iteration

  86. Proprietary and Confidential • Because collections are objects, you cannot

    modify them during iteration. Breaking Iteration Fatal error: Uncaught exception 'InvalidOperationException' with message 'Collection was modified during iteration' in <file>
  87. Shapes

  88. Proprietary and Confidential • Tuples with a pre-defined structure •

    Can be used as a form of validation • Ensures integrity Shapes newtype HTTPRequest = shape( 'status' => HTTPStatusCode, 'headers' => Map<string, string>, 'data' => shape ( 'GET' => ?Map<string, mixed>, 'POST' => ?Map<string, mixed>, 'COOKIE' => ?Map<string, mixed>, 'SERVER' => Map<string, mixed> ), 'body' => ?string );
  89. Anonymous Functions

  90. Proprietary and Confidential • Like closures but they inherit parent

    scope • Much more concise • Multiple Expressions Anonymous Functions $fn = $args ==> expression; $fn = ($arg1, $arg2) ==> { expression; return ...; }; $list = <ul/>; array_walk($items, $item ==> $list->appendChild(<li>{$item}</li>); echo $list;
  91. XHP — XML Fragments as Expressions

  92. Proprietary and Confidential • Makes XML syntax a top-level syntax

    • No longer strings • Auto-escapes for security • Allows for OO semantics, for composable widgets, for tempting • Must be XML, e.g. <br /> XHP — XML Fragments as Expression echo <p>Hello World</p>;
  93. Proprietary and Confidential • Classes are defined by prefixing the

    class name with a colon • Classes extend the :x:element base class which has DOM-like methods: • appendChild() • prependChild() • replaceChildren() • getChildren() • getFirstChild() • getLastChild() • getAttribute(), getAttributes() • setAttribute(), setAttributes() • isAttributeSet() • removeAttribute() XHP (Cont.)
  94. Proprietary and Confidential The PHP Way <?php echo '<ul>'; foreach

    ($items as $item) { echo '<li>'; echo htmlentities($item, ENT_QUOTES, 'UTF-8'); echo '</li>'; } echo '</ul>'; ?>
  95. Proprietary and Confidential The Hack Way <?hh $list = <ul/>;

    foreach ($items as $item) { $list->appendChild(<li>{$item}</li>); }
  96. Proprietary and Confidential XHP-Bootstrap <?hh print <bootstrap:dropdown> <bootstrap:button> Dropdown <bootstrap:caret

    /> </bootstrap:button> <bootstrap:dropdown:menu> <bootstrap:dropdown:item href="#"> Foo </bootstrap:dropdown:item> <bootstrap:dropdown:item href="#"> Bar </bootstrap:dropdown:item> <bootstrap:dropdown:item disabled="true" href="#"> Disabled </bootstrap:dropdown:item> </bootstrap:dropdown:menu> </bootstrap:dropdown>;
  97. Proprietary and Confidential XHP-Bootstrap

  98. Proprietary and Confidential • Validation — invalid tags are errors,

    attribute values (e.g. class names) are validated • Semantic Markup — tags are more descriptive • Encapsulation — create re-usable complex components • Future Proof — Change the underlying implementation XHP-Bootstrap
  99. Other Features

  100. Proprietary and Confidential • Async MySQL, memcached and Curl (3.6+)

    Other Features
  101. Command Line Tools

  102. Static Analysis

  103. hh_server

  104. Proprietary and Confidential • Monitors files for changes using inotify

    • Validates the files using static analysis • Analyses .php and .hh files with the <?hh open tag Static Analysis: hh_server
  105. hh_client

  106. Proprietary and Confidential • Starts hh_server if necessary • Retrieves

    the results of the static analysis from hh_server • Displays them in the CLI • Integrates with Vim/Emacs Static Analysis
  107. Proprietary and Confidential 1.<?hh // strict 2.function greeting(string $who):void {

    3. return "Hello $who"; 4.} 5. 6.function sayHello() { 7. echo greeting(1.0); 8.} Static Analysis
  108. Proprietary and Confidential 1.<?hh // strict 2.function greeting(string $who):void {

    3. return "Hello $who"; 4.} 5. 6.function sayHello() { 7. echo greeting(1.0); 8.} Static Analysis
  109. Proprietary and Confidential Static Analysis

  110. Proprietary and Confidential Vim Integration

  111. Refactoring

  112. Proprietary and Confidential • hh_client check --refactor • Can rename

    classes, functions, or methods • Does not yet support namespaces :( • Static analysis makes these changes much less prone to error Refactoring $ hh_client check --refactor WARNING: This tool will only refactor references in typed, hack code. Its results should be manually verified. Namespaces are not yet supported. What would you like to refactor: 1 - Class 2 - Function 3 - Method Enter 1, 2, or 3: 2 Enter function name: sayHello Enter a new name for this function: sayHi Rewrote 2 files.
  113. Hackificating

  114. Converting from PHP to Hack

  115. Proprietary and Confidential – Change the opening tag – Add

    soft type hints – Run the code with soft type hints and gather the logs – Feed the logs back into HHVM to remove invalid hints (ensures there is no invalid inference) – Harden the type hints Hackificating
  116. Proprietary and Confidential • Hackificator changes the opening tag from

    PHP to Hack: • $ hackificator . Hackificator
  117. Proprietary and Confidential • Uses static analysis to figure out

    and add soft type hints: • $ hh_server --convert ./ ./ Add Soft Type Hints public static function makeBarcode(
 $barcode, 
 $barcodeConfig = array()
 ) public static function makeBarcode(
 @?string $barcode, 
 @array $barcodeConfig = array()
 ) : @\Zend\Barcode\Object\ObjectInterface
  118. Proprietary and Confidential • Run the code (tests suites are

    great for this!) • Capture the hhvm log file Verify Soft Type Hints
  119. Proprietary and Confidential • Feed the log file into hack_remove_soft_types

    to remove invalid types: • $ hack_remove_soft_types --delete-from-log hhvm.log • Note: This tool is dumb and requires paths to be identical Remove Invalid Soft Type Hints
  120. Proprietary and Confidential • Finally: Harden all the left over

    types • $ hack_remove_soft_types --harden FILE • Run it over all files in a directory: • Harden Soft Types $ find ./ -type f -name '*.php' -exec hack_remove_soft_types --harden '{}' ';'
  121. Proprietary and Confidential • Hack Lang: http://hacklang.org • HHVM: http://hhvm.com

    • Building a Better PHP: https://blog.engineyard.com/2014/hhvm-hack (Engine Yard Blog) Resources
  122. Proprietary and Confidential Feedback & Questions: 
 Feedback: https://joind.in/
 Twitter:

    @dshafik Email: davey@engineyard.com Slides: http://daveyshafik.com/slides 14540