Pages

Wednesday, March 26, 2014

Unsupported PHP Features in Hack

Table of Contents 

  • Top-level code
  • Collisions
  • Parent Static Methods
  • Calling Static Methods
Note:
These are features that the Hack language does not support (i.e., the Hack type checker will give you an error if you try to use them). However, HHVM supports these features just fine when using PHP code.
While Hack is quite symbiotic with the PHP language, there are some PHP features that are not supported by Hack and the type checker. Here is a non-exhaustive list:
  • Rarely used language constructs including goto, if:...endif;.
  • AND, OR, XOR operators. Use &&, ||, ^ instead.
  • References (e.g., function foo(&$x))
  • The @ symbol to silence errors.
  • if/else statements without {}. else if is allowed (i.e.if (...) { ... } else if (...) { ... } else { ... } is ok).
  • elseif (without the space between else and if)
  • Mixing static and instance function calls (A::foo() vs. $a->foo() )
  • break N and continue N
  • Dynamic features such as eval and $$x
  • "Undefined" variables
  • Using PHP reserved keywords, constants, classes, parent, true, false as function, names or variable names. Trying to do so will result in a Hack syntax error.
  • Globals (e.g., global $x;)
  • Variable variables (e.g. $a = "hello"; $$a = "world"; echo "$a + $hello";)
  • Writing list(, $b) = array(3,4) is not allowed. Instead use $_, i.e.: list($_, $b) = array(3, 4).
  • Using a string directly as a function is not supported (e.g., $func = 'myFunc'; $func(1,2);). Instead wrap the string with fun() (e.g., $func = fun('myFunc'); $func(1, 2);).
  • ArrayAccess. Hack allows such objects; it just will not recognize them as arrays. Not only is ArrayAccess an "interesting" interface (e.g., having a null key means "append"), but supporting it causes a lot of strange edge cases such as needing more complicated checks around instance variable initialization. Since ArrayAccess is typically used to migrate old code, it is not supported for now; support could happen if a compelling case arose.
  • Case-insensitive function calls (the Hack typechecker is case-sensitive).
  • Mixed HTML and Hack code. Use a templating engine or XHP.

Top-level code 

There is something else to note about what Hack doesn't support: top-level code. This may be surprising, but Hack wants everything in a class or function. The implication here is that Hack will complain when writing certain scripts, for example.
<?hh// Top-level code is not supported in Hackfor ($i=1$i<=5$i++)
{
  echo 
"The number is " $i "\n";
}
Note, though, the above code will run with the HHVM virtual machine (and, of course, Zend). So typing php topCode.phpwill run correctly. The code just will not be type checked.

Collisions 

Unlike PHP, Hack does not allow one to define a function on a class that collides with the class name. For example, this is acceptable in PHP:
<?phpclass Foo {
  public function 
foo() {}
}
However, this is not acceptable in Hack:
<?hhclass Foo {
  public function 
foo() {}
}
The above example will output:
File "c.php", line 3, characters 21-29:
This is a dangerous method name, if you want to define a constructor, use __construct
The reason for Hack disallowing this comes down to constructors. In the above example, foo() behaves like a constructor and gets called upon instantiation using new Foo(). This could be very confusing especially when there is an explicit constructor as well.
<?hhclass Foo {
  
// 2 constructors?
  
public function __construct() {}
  public function 
foo() {}
}

Parent Static Methods 

PHP allows children to call static methods in the parent. For example:
<?phpclass StaticFoo {
  public static function 
staticMethod() {
    return 
"Hello";
  }
}

class 
StaticBar extends StaticFoo {
  public function 
fooStatic() {
    return 
parent::staticMethod();
  }
}
Hack does not currently allow this. The following error will be displayed:
The above example will output:
File "static.php", line 12, characters 24-35:
The method staticMethod is undefined in an object of type StaticFoo
File "static.php", line 4, characters 28-39:
The closest thing is staticMethod but it's a static method

Calling Static Methods 

In PHP, static methods can be called at the class level or the instance level. For example, the following two ways to callbar() are both acceptable:
<?phpclass Foo {
  public static function 
bar() {
    echo 
"Hello";
  }
}
// Instance level$f = new Foo();$f::bar();
// Class levelFoo::bar();
Hack does not allow the instance level static calls in // strict mode (this is allowed in // partial mode). Hack will balk about using "dynamic classes".
<?hh // strictclass Foo {
  public static function 
bar() {
    echo 
"Hello";
  }
}

function 
main_csm() {
  
// Instance level
  
$f = new Foo();
  
// Hack will balk here
  
$f::bar();

  
// Class level
  
Foo::bar();
}
main_csm();
The above example will output:
File "StaticFoo.php", line 11, characters 3-4:
Don't use dynamic classes
Note:
There is debate as to whether this is a bug of Hack or should be by design. Some think static calls shouldn't be done by class instances. Others believe that they should because there are getClass() style methods in other languages that allow for similar functionality.

No comments:

Post a Comment