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

[php[world] 2014] Writing Faster PHP with HHVM ...

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!

Davey Shafik

November 13, 2014
Tweet

More Decks by Davey Shafik

Other Decks in Programming

Transcript

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. Proprietary and Confidential • Type hints are trusted but not

    required Declarations Mode <?hh // decl // Code goes here
  17. 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
  18. 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
  19. 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.
  20. Proprietary and Confidential • void — for functions with no

    return value • this — always refers to $this Special Types
  21. 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 } }
  22. 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");
  23. Proprietary and Confidential • Type Aliases (type) • Opaque Types

    (newtype) • Only used for static analysis. Custom Types
  24. 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; } }
  25. Proprietary and Confidential • Allows you to give more appropriate

    names to existing types • e.g. unixtime for int Type Aliases
  26. 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
  27. Proprietary and Confidential <?hh function notFound() { $status = new

    HTTPStatus(); $status->send(HTTPStatus::NOT_FOUND); }
  28. Proprietary and Confidential Constructor Property Assignment <?php class Adder {

    private $left; private $right; public function __construct($left, $right) { $this->left = $left; $this->right = $right; } }
  29. 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
  30. 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
  31. 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); }
  32. 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"); }
  33. 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" }; }
  34. Proprietary and Confidential • Vectors can only use integer keys

    Vectors <?hh // strict function getCommunityEngineers(): Vector<string> { return Vector {"Davey", "PJ", "You?"}; }
  35. 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"}; }
  36. Proprietary and Confidential • Unordered Collection with no keys •

    Unique values <?hh // strict function getTags(): Set<string> { return Set { "php", "hack", "hhvm" }; }
  37. 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
  38. 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); }
  39. 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
  40. 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>
  41. 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 );
  42. 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;
  43. 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>;
  44. 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.)
  45. 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>'; ?>
  46. Proprietary and Confidential The Hack Way <?hh $list = <ul/>;

    foreach ($items as $item) { $list->appendChild(<li>{$item}</li>); }
  47. 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>;
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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.
  54. 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
  55. 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
  56. Proprietary and Confidential • Run the code (tests suites are

    great for this!) • Capture the hhvm log file Verify Soft Type Hints
  57. 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
  58. 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 '{}' ';'
  59. 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