HHVM and Hack - Deployment, Testing, and Tuning - Modern PHP (2015)

Modern PHP (2015)

Part III. Deployment, Testing, and Tuning

Chapter 12. HHVM and Hack

Think what you will about the Facebook application, but I have nothing but praise for the brilliant folks working at Facebook. Facebook Open Source has developed several important projects in the last few years, two of which have had significant impact in the PHP community.

The first initiative is HHVM, or the Hip Hop Virtual Machine. This alternative PHP engine was released in October 2013. Its just-in-time (JIT) compiler provides performance many times better than PHP-FPM. In fact, WP Engine recently migrated to HHVM and realized 3.9x faster custom Wordpress installations. MediaWiki also transitioned to HHVM, and it has realized drastic improvements in both response times and throughput.

The second initiative is Hack, a new server-side language that is a modification of the PHP language. Hack is mostly backward-compatible with PHP code, although it extends the PHP language with strict typing, new data structures, and a real-time type checking server. That being said, Hack’s own developers prefer to call Hack a dialect of PHP and not a new language.

HHVM

Since 1994, if you said PHP interpreter you meant the Zend Engine. The Zend Engine was PHP. It was the one and only PHP interpreter. Then Mark Zuckerberg came along and created this little thing called Thefacebook on February 4, 2004. Mr. Zuckerberg and his growing company wrote the Facebook application predominantly with PHP because the language is easy to learn and simple to deploy. The PHP language lets Facebook quickly onboard new developers to grow, innovate, and iterate its platform.

Fast forward, and Facebook is a veritable empire. Its infrastructure is massive. Facebook is so huge that the traditional Zend Engine became a bottleneck for its developers. The Facebook team had a hugely growing user base (by 2007, its user base surpassed 1 in 10 people on the planet), and it had to figure out a way to improve performance without simply building more data centers and buying more servers.

PHP at Facebook

The PHP language is traditionally interpreted, not compiled. This means that your PHP code remains PHP code until it is sent through an interpreter when executed on the command line or requested by a web server. The PHP script is read by the PHP interpreter and converted into a set of existing Zend Opcodes (machine-code instructions), and the Zend Opcodes are executed with the Zend Engine. Unfortunately, interpreted languages execute more slowly than compiled languages because they must be converted to machine code during every execution. This taxes system resources. Facebook realized this performance bottleneck and, in 2010, began working on a PHP-to-C++ compiler called HPHPc.

The HPHPc compiler converts PHP code into C++ code. It then compiles the C++ code into an executable that is deployed to production servers. HPHPc was largely successful; it improved Facebook’s performance and reduced the strain on its servers. However, HPHPc’s potential performance approached a ceiling, it was not 100% compatible with the complete PHP language, and it required a time-consuming compile process that created a lengthy feedback loop for developers. Facebook needed a hybrid solution that delivered superior performance but also allowed for faster development without expensive compile time.

Facebook began working on the next iteration of HPHPc, called HHVM. HHVM converts and caches PHP code into an intermediary bytecode format, and it uses a JIT compiler to translate and optimize its bytecode cache into x86_64 machine code. HHVM’s JIT compiler enables many low-level performance optimizations that are simply not possible by compiling PHP directly to C++ with HPHPc. HHVM also enables a fast feedback loop for developers because it compiles bytecode into machine code only when PHP scripts are requested by a web server—just in time, you might say—much like a traditional interpreted language. What’s more amazing is that HHVM’s performance eclipsed HPHPc’s performance in November 2012, and it continues to improve (Figure 12-1).

HHVM vs. HPHPc Performance

Figure 12-1. HHVM vs. HPHPc Performance

HPHPc was deprecated soon after HHVM’s peformance exceeded its own, and HHVM is currently Facebook’s preferred PHP interpreter.

TIP

Don’t let HHVM intimidate you! Its implementation may be complex, but at the end of the day HHVM is just a replacement for the more familiar php and php-fpm binaries:

§ You execute PHP scripts with the hhvm binary on the command line, just like the php binary.

§ You use the hhvm binary to create a FastCGI server, just like the php-fpm binary.

§ HHVM uses a php.ini configuration file, just like the traditional Zend Engine. It even uses the same INI directives.

§ HHVM has native support for many common PHP extensions.

HHVM and Zend Engine Parity

Facebook’s original HPHPc compiler was not compatible with the complete PHP language (i.e., the Zend Engine). Complete parity is an aspiration for Facebook because it lets HHVM become a drop-in replacement for the Zend Engine.

Facebook tested HHVM against the most popular PHP frameworks to ensure compatibility with real-world PHP 5 code. Facebook is close to 100% compatibility. However, Facebook has shifted its focus to user-reported issues on the HHVM issue tracker to tackle remaining edge-case issues. HHVM is not yet 100% compatible with the traditional Zend Engine, but it’s getting closer every day. Facebook, Baidu, and Wikipedia already use HHVM in production. HHVM can also run Wordpress, Drupal, and many popular PHP frameworks.

Is HHVM Right for Me?

HHVM isn’t the right choice for everyone. There are far easier ways to improve application performance. Reducing HTTP requests and optimizing database queries are low-hanging fruit that noticeably improve application performance and response time. If you have not made these optimizations, do them first before you consider HHVM. Facebook’s HHVM is for developers who have already made these optimizations and still need faster applications. If you believe you need HHVM, here are some resources to help you make the best decision:

Extensions

View a list of PHP extensions compatible with HHVM.

Framework Parity

Track HHVM parity with the most popular PHP frameworks.

Issue Tracker

Track open HHVM issues.

FAQs

Read HHVM frequently asked questions.

Blog

Follow the latest HHVM news.

Install

HHVM is easy to install on the most popular Linux distributions. It was originally developed for Ubuntu (my preferred Linux distibution), so I use Ubuntu in the following examples.

NOTE

Facebook provides prebuilt packages for other Linux distributions, including Debian and Fedora. You can build HHVM from source on even more Linux distributions.

Per Facebook’s instructions, you can install HHVM on the latest version of Ubuntu with the Aptitude package manager like this:

wget -O - \

http://dl.hhvm.com/conf/hhvm.gpg.key |

sudo apt-key add -;

echo deb \

http://dl.hhvm.com/ubuntu trusty main | sudo tee /etc/apt/sources.list.d/hhvm.list;

sudo apt-get update;

sudo apt-get install hhvm;

If you’re feeling lucky, swap the last line with this one to install the latest nightly build:

sudo apt-get install hhvm-nightly;

The preceding code adds HHVM’s GNU Privacy Guard (GPG) public key for package verification. It adds the HHVM package repository to our local list of repositories. Finally, it installs HHVM with Aptitude like any other software package. The HHVM binary is installed at/usr/bin/hhvm.

Configure

HHVM uses a php.ini configuration file just as the Zend Engine does. This file exists at /etc/hhvm/php.ini by default, and it contains many of the same INI settings used by the Zend Engine. You can find a complete list of HHVM php.ini directives at http://docs.hhvm.com/manual/ini.list.php.

If you run HHVM as a FastCGI server, add server-related INI directives into the /etc/hhvm/server.ini file. You can find a complete list of HHVM server directives at https://github.com/facebook/hhvm/wiki/INI-Settings. The HHVM wiki page is weak on details, so you may want to peruse these HHVM support communities, too:

§ StackOverflow

§ IRC Channel

§ Facebook Page

The default /etc/hhvm/server.ini file should be sufficient to get you started. It looks like this:

; php options

pid = /var/run/hhvm/pid

; hhvm specific

hhvm.server.port = 9000

hhvm.server.type = fastcgi

hhvm.server.default_document = index.php

hhvm.log.use_log_file = true

hhvm.log.file = /var/log/hhvm/error.log

hhvm.repo.central.path = /var/run/hhvm/hhvm.hhbc

The most notable settings are hhvm.server.port = 9000 and hhvm.server.type = fastcgi; they tell HHVM to run as a FastCGI server on local port 9000.

When you execute the hhvm binary, you specify the path to your configuration files with the -c option. If you use hhvm to execute command-line scripts, you only need the /etc/hhvm/php.ini configuration file:

hhvm -c /etc/hhvm/php.ini my-script.php

If you use the hhvm binary to start a FastCGI server, you need both the /etc/hhvm/php.ini and /etc/hhvm/server.ini files:

hhvm -m server -c /etc/hhvm/php.ini -c /etc/hhvm/server.ini

Extensions

HHVM cannot use PHP extensions that are compiled for the Zend Engine unless the extensions use Facebook’s Zend Extension Source Compatibility Layer. Fortunately, most of the PHP extensions we take for granted are supported by HHVM out of the box. Other third-party PHP extensions (e.g., the GeoIP extension) can be compiled separately and loaded into HHVM as a dynamic extension. You can find a list of PHP extensions compatible with HHVM on GitHub.

Monitor HHVM with Supervisord

HHVM is just fine for your production server, but it’s not infallible. I recommend you keep tabs on HHVM’s master process with Supervisord, a process monitor that starts the HHVM process on boot and automatically restarts the HHVM process if HHVM fails.

TIP

If you are unfamiliar with Supervisord, Chris Fidao has an excellent tutorial.

Install Supervisord with this command if you haven’t already:

sudo apt-get install supervisor

Next, make sure the /etc/supervisor/supervisord.conf configuration file has these two lines:

[include]

files = /etc/supervisor/conf.d/*.conf

These two lines let us create a configuration file in the /etc/supervisor/conf.d/ directory for each supervised application. Next, create the /etc/supervisor/conf.d/hhvm.conf file with this content:

[program:hhvm]

command=/usr/bin/hhvm -m server -c /etc/hhvm/php.ini -c /etc/hhvm/server.ini

directory=/home/deploy

autostart=true

autorestart=true

startretries=3

stderr_logfile=/home/deploy/logs/hhvm.err.log

stdout_logfile=/home/deploy/logs/hhvm.out.log

user=deploy

The most important settings are:

command

Supervisord runs this command to kick off the HHVM process. We use the -m option to run HHVM in server mode. We also use the -c option to provide the path to HHVM’s php.ini and server.ini configuration files.

autostart

This causes the HHVM process to start when the Supervisord process starts (e.g., on system boot).

autorestart

This prompts Supervisord to restart the HHVM process if it fails.

startretries

This is the number of times Supervisord should try to start the HHVM process before Supervisord considers this process a failure.

user

This is the user that owns the HHVM process. I recommend you use an unprivileged user for security purposes. In this example, I use the same unprivileged deploy user we created in Example 7-1.

WARNING

Make sure you manually create the /home/deploy/logs directory, because Supervisord does not create it for you.

After you finish editing the Supervisord configuration files, run these two commands to reload and apply your changes:

sudo supervisorctl reread;

sudo supervisorctl update;

You can review all processes managed by Supervisord with this command:

sudo supervisorctl

You can start, stop, or restart a single Supervisord program as shown in the example below. In this example, hhvm is the program name specified at the top of the /etc/supervisor/conf.d/hhvm.conf file:

sudo supervisorctl start hhvm;

sudo supervisorctl stop hhvm;

sudo supervisorctl restart hhvm;

So far we’ve installed HHVM, and we monitor the HHVM process with Supervisord. We still need a web server to proxy requests to HHVM. Remember, HHVM runs a FastCGI server exactly as we do in Chapter 7 with PHP-FPM. We’ll use the HHVM FastCGI server to handle PHP requests sent from nginx.

HHVM, FastCGI, and Nginx

HHVM communicates with a web server (e.g., nginx) with the FastCGI protocol. We need to create an nginx virtual host that proxies PHP requests to the HHVM FastCGI server. Here’s an example nginx virtual host definition that does that:

server {

listen 80;

server_name example.com;

index index.php;

client_max_body_size 50M;

error_log /home/deploy/apps/logs/example.error.log;

access_log /home/deploy/apps/logs/example.access.log;

root /home/deploy/apps/example.com/current/public;

location / {

try_files $uri $uri/ /index.php$is_args$args;

}

location ~ \.php {

include fastcgi_params;

fastcgi_index index.php;

fastcgi_param SCRIPT_FILENAME ument_root$fastcgi_script_name;

fastcgi_pass 127.0.0.1:9000;

}

}

TIP

From this point forward, I assume nginx is installed and running on your server. Refer to Chapter 7 for nginx installation instructions.

Assuming you followed the nginx installation instructions in Chapter 7, create a file at /home/deploy/apps/example.com/current/public/index.php with this content:

<?php

phpinfo();

Make sure the example.com domain points to your server’s IP address and visit http://example.com/index.php in a web browser. You should see the word “HipHop” appear in your browser window.

TIP

You can force your computer to point any domain name to any IP address by updating your local /etc/hosts file. For example, this line points the domain name example.com to IP address 192.168.33.10:

192.168.33.10 example.com

Congratulations! You’ve installed HHVM as a FastCGI server that can run your PHP application. But a FastCGI server isn’t cool. You know what’s cool? Hack. HHVM can run that, too.

The Hack Language

Hack is a server-side language that is similar to and seamless with PHP. Hack’s developers even call Hack a dialect of PHP. Why did Facebook create something so similar to PHP? Facebook created the Hack language for several reasons. The Hack language adds new time-saving data structures and interfaces that are unavailable in PHP. More important, Hack introduces static typing to help us write more predictable and stable code. Static typing surfaces errors earlier in the development process using a near-realtime type checking server.

Are new data structures, interfaces, and static typing worth the time required to learn a new(ish) language and toolchain? Maybe. You have to remember that Facebook is Facebook. It has thousands of developers all working on a gargantuan codebase. If Facebook can optimize even the smallest part of its development process, it reaps a large reward in both developer efficiency and a more stable, well-performing codebase.

I do not recommend you drop what you’re doing and immediately port your existing applications from PHP to Hack. However, if you are starting a new project and have time to install and learn Hack, then—by all means—go wild. You’ll certainly benefit from Hack’s data structures and static typing.

Convert PHP to Hack

To convert code from PHP to Hack, change <?php to <?hh. That’s it. This is PHP code:

<?php

echo "I'm PHP";

And this is equivalent Hack code:

<?hh

echo "I'm Hack";

Facebook makes it super-easy to go from PHP to Hack because it understands that converting a large, existing codebase is not a quick task. Start your codebase migration by only changing <?php to <?hh. Next, introduce a few static types. Later on, explore some Hack data structures. The transition to Hack is gradual and painless, and it happens on your schedule; this is by design.

What is a Type?

Before we compare dynamic and static typing, it’s probably helpful to define type. Most PHP programmers think a type is the form of data assigned to a variable. For example, the expression $foo = "bar" implies the $foo variable’s value is a string. The expression $bar = 14 implies the $bar variable’s value is an integer. These examples demonstrate types, yes, but they betray the full definition of a type.

A type is a nebulous label that we assign to properties of an application to prove that certain behaviors exist and, to our own expectations, are fundamentally correct. I’m paraphrasing Chris Smith’s excellent explanation of programming types.

We can expand our definition of a type to a syntactical annotation that clarifies the identity of program variables, arguments, or return values. Type annotations (or hints) are used in both PHP and Hack. You’ve probably seen code like this:

<?php

class WidgetContainer

{

protected $widgets;

public function __construct($widgets = array())

{

$this->widgets = array_values($widgets);

}

public function addWidget(Widget $widget)

{

$this->widgets[] = $widget;

return this;

}

public function getWidget($index)

{

if (isset($this->widgets[$index]) === false) {

throw new OutOfRangeException();

}

return $this->widgets[$index];

}

}

This is an arbitrary example, but it uses syntax hints to enforce specific application properties. For example, in the addWidget() method signature we use a Widget hint before the $widget argument to tell PHP we expect the method argument to be an instance of class Widget. The PHP interpreter enforces this expecation. If an argument is provided that is not an instance of class Widget, the code fails. In this example, the type is our annotated expectation that the addWidget() method accepts arguments only of class Widget.

Our earlier naive examples (e.g., $foo = "bar") and this WidgetContainer example both demonstrate types. The first example demonstrates a type that proves a variable is a string, even though we don’t explicitly annotate the expectation. The PHP interpreter is smart enough to inferthe string type in this example based on the code syntax. The second example creates a type with an annotation that explicitly defines the expected behavior of the addWidget() method, and the PHP interpreter enforces this behavior based on our explicit hint rather than making an inferrence.

TIP

Types are more than inferred identities and annotations. However, these are the two manifestations you’ll see and use most often when writing PHP and Hack code. You can learn more about programming types in Benjamin C. Pierce’s book “Types and Programming Languages.”

If you thought that PHP type hints are static types, you’re probably scratching your head right about now because I just burst your bubble. Both static and dynamic typing help us write code that behaves correctly according to our expectations, and both employ their own type systems. The main differences between static and dynamic typing are when program types are checked and how a program is tested for correctness.

Static Typing

The correct behavior of a statically typed program is implied by the code, via inferences, annotations, or other language-specific types. If a statically typed program compiles successfully, we can be confident the program is proven to behave as written. The program’s types become our tests, and they ensure that the program satisfies our basic expectations.

Did you notice I used the word compiles? Statically typed languages are often compiled. Type checking and error reporting are delegated to the language compiler. This is nice, because the compiler surfaces type-related program errors at compile time before the application is deployed into production. Unfortunately, compiled languages imply a lengthy feedback loop. A program must be compiled to reveal errors, and complicated programs take a long time to compile. This decelerates development.

The upside to statically typed programs is that they are usually more stable because their behavior is proven by the compiler’s type checker. However, we should still write separate tests to verify that the program behavior is correct. If a program compiles, that only means the program does what the code says it should do. That does not mean the program does what we intend it to do. That being said, static typing saves us from writing type-related unit tests as we do for dynamically typed programs.

Dynamic Typing

Unlike static typing, dynamic typing cannot enforce code behavior at compile time, because the program types are not checked until runtime. Dynamically typed programs are often interpreted, too. PHP is a dynamically typed and interpreted language. This means that every time you execute a PHP script—either directly on the command line or indirectly via a web server—the PHP code is read by an interpreter, converted into a set of preexisting opcodes codes, and executed.

So how do you find errors if PHP is not compiled? Errors are surfaced during runtime. This is both a blessing and a curse. It’s good because we can iterate quickly. We write code and run it. Feedback is near-instantaneous. Unfortunately, we lose the inherent accuracy and tests provided by static type checking. Separate unit tests become far more important to ensure both proper types and intended behavior. Our tests must cover all possible behaviors. This works for the behavior we anticipate, but it fails miserably for the behavior we do not anticipate. Unanticipated behaviors gnash their teeth during runtime as PHP errors, and we must handle them gracefully with friendly messages and appropriate logging.

Hack Goes Both Ways

Static typing is Hack’s biggest selling point. Even more interesting is that Hack does static and dynamic typing. Remember, Hack is mostly backward-compatible with regular PHP. This means Hack supports all of PHP’s dynamic typing features that you expect. This is possible because Hack is run with HHVM’s JIT compiler. The Hack code is type checked as it is written with a standalone type checker. The Hack code is read, optimized, and cached into an intermediary bytecode by HHVM. A Hack file is only converted into x86_64 machine code and executed on demand. It’s really the best of both worlds. We get the accuracy and safety of static typing with Hack’s type checker (more on this next) and the flexibility and quick iteration of dynamic typing thanks to HHVM’s JIT compiler.

NOTE

There are a few PHP features not supported by Hack. They are listed at http://docs.hhvm.com/manual/hack.unsupported.php. These features are supported by HHVM when executing normal PHP code.

Hack Type Checking

Hack comes with a standalone type-checking server that runs in the background and type-checks your code in realtime. This is huge. This is also the main reason why Facebook created the Hack language. Hack’s instantaneous type checking provides the accuracy and safety of static typing without the lengthy feedback loop. If you are using Hack without its type checker, you’re holding it wrong.

Here’s how to set up Hack’s type checker for your application. First, I assume HHVM is installed and running. If not, refer to the HHVM section for installation instructions. Next, create an empty file named .hhconfig in your project’s topmost directory. This tells the Hack type checker which directory to analyze. The type checker watches files beneath this directory and type-checks the appropriate files whenever it detects filesystem changes. Start the Hack type checker by executing the hh_client command in or beneath your project’s topmost directory.

Hack’s type checker does have a few limitations. Per Hack’s online documentation:

The type checker assumes that there is a global autoloader that can load any class on demand. This means that it insists that all class and function names are unique, and has no notion of checking imports or anything of that nature. Futhermore, it does not support conditional definitions of functions or classes — it must be able to statically know what is and what is not defined. It is of course perfectly possible to have a project that meets these requirements without a global autoloader, and the type checker will work fine on such a project, but a project using an autoloader was the intended use case.

Mixing HTML and Hack code are not supported by the type checker. Following and statically analyzing these complicated mode switches is unsupported, particularly since much modern code doesn’t make use of this functionality. Hack code can output markup to the browser in a simple way via echo, or using a templating engine or XHP for more complex scenarios.

Hack Modes

Hack code can be written in three modes: strict, partial, or decl. If you are starting a project with Hack, I recommend you use strict mode. If you are migrating existing PHP code to Hack, or if your project uses both PHP and Hack code, you may want to use partial mode. Thedecl mode lets you integrate legacy, untyped PHP code into an otherwise strict Hack codebase. You declare the mode at the very top of the file, after and adjacent to the opening Hack or PHP tag (see the following examples). Mode names are case-sensitive:

<?hh // strict

Strict mode requires all code to be appropriately annotated. The Hack type checker will catch all possible type-related errors. This mode also prevents your Hack code from using non-Hack code (e.g., legacy PHP code). Be sure you read up on Hack type annotations before you commit tostrict mode. Among other requirements, all Hack arrays must be typed; you cannot use an untyped array in Hack. You must also annotate return types for functions and methods.

<?hh // partial

Partial mode (the default) allows Hack code to use PHP code that has not been converted to Hack. Partial mode also does not require you to annotate all of a function or method’s arguments. You can annotate a subset of the arguments without angering the Hack type checker. If you are just getting started with Hack, or if you are converting an existing PHP codebase, this is probably the best mode for you.

<?php // decl

decl mode lets strict Hack code call untyped code. This is often the case when newer Hack code depends on a legacy, untyped PHP class. In this scenario, the legacy PHP code should declare itself in decl mode before the newer Hack code can use it.

Hack Syntax

Hack supports type annotations for class properties, method arguments, and return types. These annotations are checked with Hack’s standalone type checker in accordance with each file’s mode.

TIP

Read a complete list of available type annotations.

Let’s revisit our earlier WidgetContainer example and introduce type annotations. The updated Hack code looks like this:

01. <?hh // strict

02. class WidgetContainer

03. {

04. protected Vector<Widget> $widgets;

05.

06. public function __construct(array<Widget> $widgets = array())

07. {

08. foreach ($widgets as $widget) {

09. $this->addWidget($widget);

10. }

11. }

12.

13. public function addWidget(Widget $widget) : this

14. {

15. $this->widgets[] = $widget;

16.

17. return this;

18. }

19.

20. public function getWidget(int $index) : Widget

21. {

22. if ($this->widgets->containsKey($index) === false) {

23. throw new OutOfRangeException();

24. }

25.

26. return $this->widgets[$index];

27. }

28. }

Property annotations

On line 4, we declare the $widgets class property with the Vector<Widget> annotation. This annotation tells us two things:

§ This property is a Vector (similar to a numerically indexed array).

§ This property must contain only Widget instances.

Argument annotations

This is probably familiar to those of you who already use PHP type hints. On line 6, we annotate the __construct() method’s argument with the array<Widget> annotation. This annotation tells us two things:

§ The argument must be an array.

§ The argument must contain only Widget instances.

Unlike the property annotation on line 4, this argument can be either a numeric or an associative array. We iterate the array argument’s values and add them to the Vector data structure. If you did want the argument to be either a numeric or an associative array, you could use thearray<int, Widget> or array<string, Widget> annotations respectively.

Return-type annotations

On lines 13 and 20, we annotate the methods’ return types. The addWidget() method returns itself (more on this soon). The getWidget() method returns a Widget instance. Return-type annotations are declared after the method signature’s closing parenthesis and before the method body’s opening bracket.

WARNING

The exception to this rule is the __construct() method. One might think the constructor’s return value is void; it’s not. You should not annotate the constructor method’s return type.

Some developers like to enable method chaining. This means that a class method returns itself so that multiple method calls can be chained together like this:

$object->methodOne()->methodTwo();

Hack lets you annotate this behavior with the this return type. We use the this annotation with the addWidget() method on line 13.

Hack Data Structures

The Hack language’s headline feature is static typing. However, Hack also provides new data structures and interfacs that are not found in PHP. These can potentially save you development time versus implementing similar workarounds in vanilla PHP. Some of Hack’s new data structures and interfaces are:

§ Collections (vectors, maps, sets, and pairs)

§ Generics

§ Enums

§ Shapes

§ Tuples

Many of these data structures complement, clarify, or supplement PHP’s functionality. For example, Hack’s Collection interfaces clarify PHP’s array ambiguity. Generics let you create data structures to handle homogenous values of a given type that is inferred only when an instance of the generic class is created; this alleviates the need to manually enforce type checking inside a class with PHP’s instanceof method. Enums are helpful for creating a set of named constants without resorting to abstract classes. Shapes help you type-check data structures that should have a fixed set of keys. And tuples let you use arrays of an immutable length.

Please don’t feel like you need to rush out and implement all of these data structures. I admit, some of them are of limited and niche utility. Some data structures duplicate (and extend) functionality found in other data structures. I suggest you read up on which data structures are available and only use them if and when you need them.

TIP

I believe the most useful Hack data structures are the various Collection interfaces. These provide more appropriate and predictable behavior than PHP’s array data structure. It’s best to use a Collection instead of a PHP array.

HHVM/Hack vs. PHP

If HHVM and Hack are so awesome, why should you use PHP? I’m asked this question a lot. I’m also asked if and when PHP will meet its demise. The answer is not black-and-white. It’s more a muddy neutral gray.

HHVM is the first true competitor to the traditional Zend Engine PHP runtime. As of PHP 5.x, HHVM is proven to perform better and be more memory-efficient than the Zend Engine on many real-world benchmarks. I think this caught the PHP core development team by surprise. In fact, HHVM’s mere existence is probably responsible for PHP’s renewed interest in increased performance and reduced memory usage. The PHP core development team is already working on PHP 7, which is scheduled for release in late 2015. The PHP 7 codebase promises to be competitive with, if not better than, HHVM. Whether that will be true or not is anyone’s guess. However, the point is that HHVM creates competition, and competition helps everyone. Both HHVM and the Zend Engine will improve, and PHP developers will reap the benefits. Neither HHVM nor the Zend Engine is going to win or lose. I believe they will coexist and feed off of their competitive energies.

The Hack language, in my opinion, is head-and-shoulders better than PHP. There are several reasons for this. First, the Hack language was built by Facebook to answer specific needs. It is focused. It has purpose. And it is not developed by committee. The PHP language, in contrast, has evolved piecemeal over a longer period of time. PHP answers many different needs, and it is controlled by a committee that is not known for its cordial agreements. As of PHP 5.x, the Hack language is the better option for its strict type checking and support for legacy PHP code. I believe a lot of Hack’s best features will eventually find their way into PHP. And vice versa. In fact, the Hack language team has said it intends to maintain future compatibility with the Zend Engine. Again, I believe competition will improve both languages and they’ll enjoy a symbiotic relationship.

An example of this symbiosis is the official PHP specification. Until recently, the PHP language was the Zend Engine for lack of alternative implementations. The introduction of HHVM prompted several developers at Facebook to announce a PHP language specification. This specification is an amazing development in the PHP community, and it ensures that current and future PHP implementations (Zend Engine, HHVM, and so on) all support the same fundamental language.

NOTE

You can read the official PHP implementation on GitHub at https://github.com/php/php-langspec.

Further Reading

We’ve touched on a lot of HHVM and the Hack language in a very short period of time. There are simply not enough pages to cover everything these two initiatives have to offer. Instead, I’ll point you to these helpful resources:

§ http://hhvm.com

§ http://hacklang.org

§ @ptarjan on Twitter

§ @SaraMG on Twitter

§ @HipHopVM on Twitter

§ @HackLang on Twitter