Official website for Linux User & Developer
FOLLOW US ON:
Jul
5

Install Hacklang and build a Hack app

Posted by Rob Zwetsloot

Learn how to install Hacklang, configure the Apache server to talk to the Hack instance and then build a Hack app

A little while ago Facebook unleashed a new programming language unto the world. That language is called Hack and it’s what we’re going to be looking at today. Hack is unique in that, unlike a lot of new languages, it hasn’t been released at or before v1. For the past couple of years Facebook has been working on writing Hack and porting the desktop version of their service to it, meaning that Hack has already proven to be a system that’s fully capable of running huge websites – and these days, it doesn’t get much bigger than Facebook.

Originally Facebook was built with PHP and MySQL, but as time passed and the service grew, these technologies would not be able to handle the data and traffic that Facebook deals with out of the box. Rather than porting their service over to a lower level or more optimised language, Facebook decided to invest time and dollars in making the technologies they already used better. One of the results of the effort is Hack, which reportedly has delivered Facebook a doubled speed increase in the execution of its desktop site without adversely affecting the development time of its products. Hack is the next step in Facebook’s HipHop project, originally an open source tool for converting PHP to C++. Rather than executing compiled C++, Hack is compiled into bytecode with HHVM (HipHop Virtual Machine), a JIT compiler. This time, we’re going to look at installing HHVM and writing a database interface to retrieve blog posts with Hack, PHP5 and MySQL.

Hack has proben itself to be a system that can run huge websites
Hack has proben itself to be a system that can run huge websites

Getting started

The first thing we need to do is grab the HHVM. Thankfully that’s rather simple with the use of Apt. Let’s add the repository for Hack and then have Apt install it.

$ echo deb http://dl.hhvm.com/ubuntu saucy main | sudo tee /etc/apt/sources.list.d/ hhvm.list
$ sudo apt-get update
$ sudo apt-get install hhvm

After a couple of minutes, Hack should be installed. Let’s test that quickly. Create a new file named test.php and insert the following

<?hh

      echo HHVM_VERSION . "\n";

Now, let’s run that code in the terminal with ‘hhvm test.php’. In your terminal, you should now see a version number like 3.x.x appear. If so, you’re ready to crack on and configure Hack to work with Apache.

Before version 3, Hack/HHVM included its own server that could be run as a service. This was removed from version 3, largely because the team over at Facebook felt that its job was to write a language, not a server. As such, Hack now runs alongside either Apache or Nginx, superseding the ordinary PHP interpreter. Hack talks to these servers through a proxy with FCGI, so let’s modify our configurations files to allow that now. The following instructions will be for an Apache server specifically, Not Nginx, although the steps are pretty much the same.

At the end of our Hack installation, there was a dialog that gave us some suggested steps as to what to do next. One of those lines was

$ sudo /usr/share/hhvm/install_fastcgi.sh

Run that script now; it will configure both your server and Hack to use FCGI, but we still need to pass your traffic from your Apache server to our Hack instance. Locate either your httpd.conf or apache.conf file – it should be found somewhere like /etc/apache2 – and open it for editing. Add the following line to the end of the file.

ProxyPass / fcgi://127.0.0.1:9000/var/www/hack

Save and exit. This will redirect all traffic that your server receives to the /var/www/hack folder. If you want to route only certain kinds of traffic to the Hack instance you can modify the ProxyPass statement with a regex, but that’s at your discretion, and we won’t be covering that in this piece. Here it’s assumed that you have a folder at /var/www/hack, if not you can either create it now or change the line in the .conf to wherever you’d like your project folder to be.

We’re almost good to go. Copy the test. php file we wrote a little while ago into your newly created project folder. If you try and access the file through a browser, you may not find that you get the version number you were expecting. This is because HHVM isn’t running yet and we need to run HHVM as a server for it to process Hack language/PHP files and deliver it. When we run HHVM, it will take over the role PHP plays in rendering pages for certain functions – keep in mind that Hack is not fully compatible with PHP, but it’s getting very close to parity with each version’s release. At the time of writing, HHVM is well on its way to start supporting some of the more popular PHP frameworks, such as WordPress or Magento, without a great deal of configuration. To run the Hack server enter the following in your terminal…

hhvm --mode server -vServer.Type=fastcgi -vServer.Port=9000

Now, if you try http://YOUR_PUBLIC_IP_ ADDRESS/test.php, you should once again be presented with the 3.x.x version number of the Hack language. Great! Now we’re ready to start building this blog.

Handling a database

Aside from how it executes code, perhaps the biggest difference between Hack and PHP is how it interacts with HTML – that is, Hack doesn’t interact with HTML at all. Even if you’re delivering ordinary PHP with the Hack server, you will be lucky if any of the PHP code is executed in the document before it crashes and if you try to intersperse Hack code with HTML, you’ll likely be rewarded with an error message. Where Hack shines is in its a ability to optimise data and processing, so we’re going to use Hack to retrieve, order and then encode to JSON posts in a SQL database.

In your project folder create a file called connect.php and we’ll create a database connection by inserting the following…

<?hh
   $connection = mysqli_connect("SQL SERVER ADDRESS", "USERNAME", "PASSWORD", "DATABASE") or die("DB Error: " . mysqli_error($connection));

…and then head back to the ‘index.php’ file and insert the code below:

<?hh

   echo " " . HHVM_VERSION . "\n";

   require_once('connect.php');

   $query = "SELECT * FROM posts" or die("DB Query error: " . mysqli_error($connection));

   $result = $connection->query($query);

   while($row = mysqli_fetch_array($result)) {
      echo $row["name"] . "<br>";
   }

If you run this code now, nothing will happen because we haven’t set up an SQL database. Included on the disc for this project is an SQL database dump with some demo content, import this into your SQL database and then run the index.php file. You should now see a list of all of the named column printed out in your browser. This is all well and good but it’s just bog-standard PHP (although thanks to HHVM, slightly optimised). Let’s tear this apart and turn in into a good little bit of Hack script.

Re-edit index.php and remove everything after the require_once statement as we won’t need that here. Then, head back into connect. php and remove everything after <?hh, then code as below:

class Database{

   private boolean $connected = False;
   private Object $connection;

   public function connect(string $addr, string $user, ?string $pw, ?string $db): ?int {

      if($db == null){
         return 0;
      }

      $this->connection = mysqli_connect($addr, $user, $pw, $db) or die("DB Error: " . mysqli_error($connection));

      if($this->connection != null){
         $this->connected = True;
         return 1;
      } else {
         $this->connected = False;
         return 0;
      }
   }
}

Let’s look at what we have here. This is a Hacklang class declaration, it has private and public members and functions that we can access and execute at will. Let’s first pay attention to our line where we declare our connect() function, there are a couple of little things going on differently here, so we’re going to step through them. If you’re not unfamiliar with C++, this might actually look like something you would do day to day, if you’re more from the PHP side of things, maybe not.

First, take note of the parameters we’ve passed; we’ve declared the data types that we expect those parameters to be (string/int/ float/object/etc). If we try to call the connect function with the wrong datatypes, it will either crash or throw an error depending on your Hack warning level. Why is this now a feature? Part of Hack’s ability to execute code really fast is its interpreter. PHP is a dynamic ‘weak’ type language, which means we can create variables on the fly without worrying too greatly about what the variable is going to contain. $x can be ‘Hello, World’ one minute and five the next. Hack still allows this flexibility, but if we declare the types of data we’re expecting, HHVM can begin to optimise that code and execute it faster than is typical (up to six times faster) with no further developer input.

The $pw and $db variables have a ‘?’ before their data types, this tells Hack that although we’re expecting a string/int/float/etc we can also potentially expect a null value. We can use this anywhere that we may need to exercise lenience when passing data around and you can see we’ve done the same at the end of the line with our :?int. This is the data type we’re expecting to return, in this case an integer or a null.

The last little thing that’s worth noticing here before we move on is the $this function. If we’re accessing members of a class, we have to initialise them, but only if we haven’t set a value when we declared those variables – and that is what $this does. If we had written $connection instead of $this->connection, it would exist only within the scope that it was called in, and therefore it would be unavailable to other functions that might need to access the object.

Add the function from the code below to our Database class in connect.php; this lovely little snippet of code will handle any SQL queries to our database using the connection that we will have created when we first initialise the class.

public function makeQuery(string $q): void{

   if($this->connected == True){

   $result = $this->connection->query($q);

   return $result;

   }

}

Making the first request

So let’s get on with making that happen now. Head back over to index.php and add the code below after our require_once statement:

$db = new Database();

$db->connect("127.0.0.1", "USER", "PASSWORD", "DATABASE NAME");

//var_dump($db);

$q = $db-> makeQuery("SELECT * FROM posts");

$data = array();

while($row = mysqli_fetch_array($q)) {

   $object = array("name" => $row["name"], "tag" => $row["tagline"], "content" => $row["content"], "date" => $row["date"]);
   array_push($data, $object);

}

echo json_encode($data);

If you hit index.php on your server, you should once again see the content of the posts in our database. Hurrah! But this still all a little bit static. Let’s change things up a little with some GET and POST parameters.

Handling GET and POST

Mentioned previously is the missing interoperability with certain PHP features. $_GET and $_POST fall into this category. Hack code is unaware of $_GET and $_POST (although, if you’re not running Hack in strict mode you can still tinker with it). Here, we’re going to assume that we are running in strict mode, and map GET and POST so Hack can make use of them.

It’s time for another new file. Once again, in your project folder, create a new file called requests.php and then insert and save the code below:

function fetchGET(): Map {
   return Map::fromArray($_GET);
}

function fetchPOST(): Map {
   return Map::fromArray($_POST);
}

function postType(): string {

   if($_SERVER['REQUEST_METHOD'] === 'GET'){
      return "GET";
   } else {
      return "POST";
   } 

}

These functions expose the $_SERVER, $_GET and $_POST globals to our Hack code, so if we were to call fetchGET(), we would have returned to us the newly mapped $_GET object. Now, we can start dealing with requests, although there is one slight caveat…

Typechecking parameters

Hack loves to know what type the data is (that old chestnut) and simply accessing the GET variable in this manner won’t do much to help us. All we’ll be able to receive are the parsed strings, and while we can work with strings, we lose the gains brought by HHVM’s typechecker. So, let’s write a quick parser to handle integer values. Add the code below to requests.php:

abstract class ServerRequest {

abstract public function getParams(): Map;

public function intParam(string $name): ?int {

$params = $this->getParams();
if (!$params->contains($name)) {
return null;
}

$param = $params[$name];

if (!is_numeric($param)) {
return null;
}

return (int)$param;

}
}

final class getRequest extends ServerRequest {
public function getParams(): Map {
return fetchGET();
}

}

function int_check_for_parameter(string $parameter): int {
if (postType() == “GET”) {
return (new getRequest())->intParam($parameter);
}
}

Then, head back into index.php and amend it so that it looks like this code:

$db->connect(“127.0.0.1″, “USERNAME”, “PASSWORD”, “DATABASE NAME”);

$limit = int_check_for_parameter(“limit”);

$q;

if($limit > 0){
$q = $db->makeQuery(“SELECT * FROM posts LIMIT ” . $limit);
} else {
$q = $db->makeQuery(“SELECT * FROM posts”);
}worx
while($row = mysqli_fetch_array($q)) {
echo $row["name"] . “
“;
}

Let’s look at the ServerRequest class, it differs from the Database class we wrote in connections.php in that we declared it as an abstract class. This is one of the features introduced in PHP5; an abstract class is one that cannot be instantiated, it can only be used as a template of sorts for other classes to extend upon. This ties in quite nicely with our getRequest class. Notice how the keyword before the definition is ‘final’. A final class is one that has extended the abstract class but itself cannot be extended any further, if we were to try to do so Hack would suffer a fatal error.

Now if you add ?limit=5 to the end of your query string, you should only see the first five results – that’s nothing special in itself, but what we’re looking at here is the intParam() call. First, we want to know if the parameter we’re looking for was passed in our GET request, Once we’ve determined that it has, we then check whether it’s numeric and cast it to an integer if the value passed our checks. If not, it will return null. This may seem overly pedantic when it comes to handling a GET parameter, but then we’d be forgetting the power of the Hack JIT compiler.

When first fired up, HHVM/Hack offer very little in the way of an immediate speed bump, but as time goes on and usage increases, HHVM optimises the processes called most often and caches the byte code it generates to complete said process. This is part of the beauty of Hack: it’s more verbose than PHP – which, let’s admit, doesn’t have a great reputation for brevity – but thanks to this extra effort, we can squeeze out every bit of power PHP has to offer.

Round up

And those are the basics of Hack. Hack can be a little tricky to set up and if you’re the sort of developer who likes to learn from code examples, there aren’t a great deal floating around at the moment – but don’t let that deter you! Hack is still in its infancy; barely a year old and already the speed gains are nothing short of phenomenal. True, there are sacrifices that have been made for those performance boosts, but it’s key to remember that Hack isn’t for rendering HTML (although it can generate HTML or other Node-like structures with XHP, Hack’s rendering engine). Instead, it’s for crunching data super-fast so that the rest of the web service can execute as fast as possible. This puts Hack in a great place to enhance or even replace current services that deal with large datasets, the most obvious among these being scalable APIs.

  • Tell a Friend
  • Follow our Twitter to find out about all the latest Linux news, reviews, previews, interviews, features and a whole more.
    • Lovelina Sweet

      Congratulations on your site! It really is great and as I saw in the first positions it is true that sharing and interface of the site are really a boon for work style. Really a big thank you!

      voyance gratuite par mail ; voyance par mail gratuite