Hacking PHP

Facebook has launched the programming language HACK as neither a subset or superset of PHP but more a dialect. It adds typing, generics, lambdas and some more features to PHP.
In this blog I will show how some trivial PHP can be translated to HACK and some things I encountered while trying it out.

From PHP…

I start with a simple pure PHP5 class with a constructor and one method that echos the current variable $a. Nothing extraordinary but I want to show what have to be done to convert this code into a hack file.

<?php
namespace Core;
class TestClass {
  private $a = 20;
  function __construct($x) {
    $this->a = $x;
  }
  public function bla() {
    echo $this->a;
  }
}
$test = new TestClass(45);
$test->bla();

… to HACK

The first step is changing <?php into <?hh to tell the hhvm that the hack syntax is used. Beter is even to use <?hh //strict, this turns on even stricter type/syntax checking. Although I don’t like comments that are given a meaning I think this is a fair solution. It is almost the same as the Javascript "strict"; solution.

The file will become like this with the changed prelude.

<?hh //strict
... // unchanged lines omitted

When this file is executed with the following command hhvm test.php the output will be 45 as expected and nothing more and nothing less. So normal PHP looks backwards compatible with hack. Hack has a special type/syntax checker that runs separate from the virtual machine that produces a lot of type hinting and other messages. A these things are about making a normal PHP file into a more strict hack file.

Before running the type checker you need to create a file .hhconfig in the directory where the file is located. This file can be empty so touch .hhconfig will do the trick. When you execute hh_client it should produce the following errors.

/home/vagrant/hack/testphp.php:6:9,16: Expected modifier (Parsing[1002])
/home/vagrant/hack/testphp.php:5:17,18: Please add a type hint (Naming[2001])
/home/vagrant/hack/testphp.php:4:17,18: Please add a type hint (Naming[2001])
/home/vagrant/hack/testphp.php:10:25,27: Was expecting a return type hint (Typing[4030])
/home/vagrant/hack/testphp.php:11:22,26: Can't use $this outside of a class (Typing[4095])
/home/vagrant/hack/testphp.php:6:18,28: Was expecting a return type hint (Typing[4030])
/home/vagrant/hack/testphp.php:6:30,31: Was expecting a type hint (Typing[4032])
/home/vagrant/hack/testphp.php:7:10,14: Can't use $this outside of a class (Typing[4095])
/home/vagrant/hack/testphp.php:7:10,14: Can't use $this outside of a class (Typing[4095])

I learnt by doing that you should ignore “Can’t use $this outside of a class” at first, this warning is caused by some other error and will be solved when that error is solved.

When looking at the first error on line 6 “Expected modifier”; it means that the function __construct($x) should have an access modifier. For a __construct we can choose public or protected, private does not make a lot of sense because then we cannot create an instance of that class. When I change the line to public function __construct($x) { and run hh_client again some errors have solved themselves.

/home/vagrant/hack/testphp.php:13:1,5: Remove all toplevel statements except for requires (Parsing[1002])
/home/vagrant/hack/testphp.php:4:17,18: Please add a type hint (Naming[2001])
/home/vagrant/hack/testphp.php:9:25,27: Was expecting a return type hint (Typing[4030])
/home/vagrant/hack/testphp.php:5:37,38: Was expecting a type hint (Typing[4032])
<?hh //strict
namespace Core;
class TestClass {
        private int $a = 20;
        public function __construct(int $x) {
                $this->a = $x;
                //$this->a = "test";
        }
        public function bla() : void {
                echo $this->a;
        }
}
//$test = new TestClass(45);
//$test->bla();

On line 4 and 5 the annotation “int” is added to indicate that $a and $x must be of the type integer. On line 9 “void” is added to indicate that the function will return no result. Returning something will result in the error “You cannot return a value”. Line 13 and 14 are commented out because only a require may be in this file because there is already a class defined. Mixing class definitions with function-call is a bad practice and will result in classes that cannot be shared between other code, every include of that class will execute that function.

The future

HACK is really young but it looks promising. Some more strict and type-safe would be a nice addition to PHP and it is nice to implement this in a gradual way. I wonder if the community will adopt this and if it will be used.