Carrying on from Part 3 of our series, we are going to take a look at some of the more complex (and in my opinion, cooler) parts of Hack.

Custom Types

While hack supports the creation of custom types, it’s important to understand that these are only used by the static analysis — at runtime, they are seen as their original underlying types.

Hack supports two different ways of defining new types, aliases, and opaque types. These are defined using the type and newtype keywords respectively.

Type aliases are just that — aliases. They simply allow you to give a more appropriate name for an existing type, or complex type — the static analyzer will permit you to use values of those types in the same way as the underlying type.

Opaque types on the other hand hide their underlying implementation outside of the file in which they are defined — this means that you cannot use them as standard types, and effectively they become immutable except when calling code defined within the file in which the type itself is defined. This restriction is not enforced at runtime.

Here we have a class to handle HTTP Status codes. We have defined a type alias HTTPStatusCode which is a simple int.

Within our class, we have defined constants for each status code, type hinted using our type alias.

We then define a property, $status that is a Map with HTTPStatusCode keys, and string values.

Finally, we have our send() method that accepts a HTTPStatusCode argument.

We then call this code using:

<?hhfunctionnotFound(){$status=newHTTPStatus();$status->send(404);}

Because we use a type alias, we are allowed to pass any int to the send() method. This means that it’s possible to pass in an unknown status code, which requires that we validate it before trying to access it by checking isset().

At this point, any place a HTTPRequest type hint is used, we can guarantee that all of these keys will exist, and have data of certain types.

XHP: XML fragments as expressions

One of the bigger changes to syntax is the introduction of XHP — and yet, it was originally released as an extension for PHP (also by Facebook), which you can still install and use with PHP today to get much of the same functionality.

Essentially, what XHP does is allow for XML tags to be top-level syntax, for example, note the lack of quotes as the markup is not a string.

<?hhecho<p>HelloWorld</p>;

Now, as this is XML, it must be valid — this means all tags must be closed (or empty e.g. <br/>).

Each tag is mapped to a class, whose name starts with a colon, for example the <p> class would be named :p. As this is XML, namespaces are also supported, for a tag named <hal:resource> it would be the :hal:resource class.

Each of these classes extends the :x:element base class, which in turn supports a number of DOM-like methods:

appendChild()

prependChild()

replaceChildren()

getChildren()

getFirstChild()

getLastChild()

getAttribute(), getAttributes()

setAttribute(), setAttributes()

isAttributeSet()

removeAttribute()

Whenever you use an XHP element it instantiates an instance of the associated class.

Traditionally, we might do something like this to output a list of items:

One other thing you might notice here is we have removed the call to htmlentities(). Because our markup is no longer just part of a larger string, the engine is able to distinguish between markup and content — allowing it to automatically escape content.

Installing XHP

While the syntax is supported out of the box, the tags are not defined. To “install” XHP, you will need to grab the hackbranch of the php-lib from the xhp repository.

Then simply include init.hh in any application that wants to use XHP.

Anonymous Functions

While Hack supports PHP-style closures, it also supports anonymous functions otherwise known as lambda expressions.

There are two reasons the Hack team decided to add this new form of anonymous functions:

Anonymous functions have a much more compact syntax, which is also helped by the fact that:

Scope is inherited by the anonymous function — this means that it inherits variables from its defining scope (by value)

Lambda expressions at their simplest use the syntax:

<?hh$fn=$args==>expression;?>

However, there is an expanded syntax that allows for multiple expressions within the function, and optionally parenthesis to distinguish arguments:

<?hh$fn=($arg1,$arg2)==>{expression;return...;};?>

Even with the expanded syntax, especially with scope capture, these are much more concise.

About Davey Shafik

Davey Shafik is a full time PHP Developer with 12 years experience in PHP and related technologies. A Community Engineer for Engine Yard, he has written three books (so far!), numerous articles and spoken at conferences the globe over.