Pro Yearly is on sale from $80 to $50! »

[php[world] 2014] Writing Faster PHP with HHVM & Hack

Fee39f0c0ffb29d9ac21607ed188be6b?s=47 Davey Shafik
November 13, 2014

[php[world] 2014] Writing Faster PHP with HHVM & 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

November 13, 2014
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 • Lead for PHPWomen US •@dshafik Davey Shafik
  3. $30 (Includes Taxes & Shipping)

  4. Let’s start a conversation about mental health in tech prompt.engineyard.com

  5. About These Slides

  6. Proprietary and Confidential Two slides per “slide” Title Slide (for

    when I’m talking) Details slide (for later) Nobody likes it when you can read the slide just as well as the speaker can I like slides that are useful About These Slides
  7. A Brief History of HipHop VM Better known as HHVM

  8. HPHPc 2009 - 2012

  9. 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
  10. HipHop VM (HHVM) 2013 -

  11. 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 • Almost up-to 5.6 feature set (e.g. support for variadics, splat) HHVM
  12. Hack A super-set of PHP

  13. 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
  14. Performance

  15. 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
  16. Agenda • Facebook (#2) • Baidu (#5, #1 Search Engine

    in China) • Wikimedia (incl. Wikipedia, #6) 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
  17. Repo Authoritative Mode Ludicrous Speed!

  18. 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
  19. HHVM Setup

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

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

    index.php HHVM
  22. 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
  23. 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
  24. Long Term Support

  25. 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
  26. Hack A better PHP

  27. 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
  28. Editor Support

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

    emacs)
  30. File Semantics

  31. 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
  32. Hack Modes

  33. Partial Mode

  34. 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
  35. Strict Mode

  36. 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
  37. Declarations Mode AKA Decl

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

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

  40. 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
  41. Type Hints

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

    Class Properties Type Hints
  43. 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
  44. 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.
  45. Proprietary and Confidential • void — for functions with no

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

  47. 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 } }
  48. Soft Types

  49. 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");
  50. Custom Types

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

    (newtype) • Only used for static analysis. Custom Types
  52. 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; } }
  53. Proprietary and Confidential <?hh function notFound() { $status = new

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

    names to existing types • e.g. unixtime for int Type Aliases
  55. 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
  56. Proprietary and Confidential newtype HTTPStatusCode = int;

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

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

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

    private $left; private $right; public function __construct($left, $right) { $this->left = $left; $this->right = $right; } }
  60. 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
  61. Collections

  62. 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
  63. Arrays

  64. 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); }
  65. Tuples

  66. 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"); }
  67. Pairs

  68. 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" }; }
  69. Vectors

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

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

  72. 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"}; }
  73. Sets

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

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

  76. 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
  77. Appending Elements

  78. 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); }
  79. Object Oriented Interface

  80. 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
  81. Breaking Iteration

  82. 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>
  83. Shapes

  84. 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 );
  85. Anonymous Functions

  86. 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;
  87. XHP — XML Fragments as Expressions

  88. 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>;
  89. 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.)
  90. 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>'; ?>
  91. Proprietary and Confidential The Hack Way <?hh $list = <ul/>;

    foreach ($items as $item) { $list->appendChild(<li>{$item}</li>); }
  92. 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>;
  93. Proprietary and Confidential XHP-Bootstrap

  94. 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
  95. Command Line Tools

  96. Static Analysis

  97. hh_server

  98. 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
  99. hh_client

  100. 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
  101. 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
  102. 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
  103. Proprietary and Confidential Static Analysis

  104. Proprietary and Confidential Vim Integration

  105. Refactoring

  106. 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.
  107. Hackificating

  108. Converting from PHP to Hack

  109. 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
  110. Proprietary and Confidential • Hackificator changes the opening tag from

    PHP to Hack: • $ hackificator . Hackificator
  111. 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
  112. Proprietary and Confidential • Run the code (tests suites are

    great for this!) • Capture the hhvm log file Verify Soft Type Hints
  113. 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
  114. 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 '{}' ';'
  115. Proprietary and Confidential Feedback & Questions: 
 Feedback: https://joind.in/
 Twitter:

    @dshafik Email: davey@engineyard.com Slides: http://daveyshafik.com/slides 11924
  116. 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 http://ey.io/hhvm-hack