From PHP to Hack as a Stack and Back
PHP CONF ASIA 2016
By Timothy Chandler
A Bit About Me
A Bit About Me• Helped grow the PHP community in
Sydney.• Established the annual PHP
Phunconference in Sydney.
A Bit About Me
How I got started with HPHP, HHVM & Hack• Back in 2009 I started work on a large project.• PHP 5.3 was new at the time.• None of the frameworks were using it yet.
2009
How I got started with HPHP, HHVM & Hack• The team and I wanted to take advantage of the new
features which PHP 5.3 offered.
How I got started with HPHP, HHVM & Hack• So we decided to roll our
own framework.
How I got started with HPHP, HHVM & Hack• Around that time,
Facebook was showing off HPHP (Hip-Hop PHP).• I played around with it
and it was Fast.• Really fast.
How I got started with HPHP, HHVM & Hack• HPHP was a PHP Transpiler.• It converted PHP to C++ and then compiled that into
binary to run as highly-optimized executable machine code.
How I got started with HPHP, HHVM & Hack• We wanted our new
framework to support HPHP.• Gaps in PHP support.• SPL was incomplete.• We filled them in
ourselves.
How I got started with HPHP, HHVM & Hack• Nutshell was born.
How I got started with HPHP, HHVM & Hack• Fast Forward 4 years.• It’s now 2013.• Facebook has just released HHVM (Hip-Hop Virtual
Machine).• Now I live and work in Malaysia.
2009
2013
How I got started with HPHP, HHVM & Hack• Introducing Nuts n Bolts.• Our CMS built on top of
Nutshell.• There is a bit of a story
behind this…
How I got started with HPHP, HHVM & Hack• Don’t drunk code in production!
How I got started with HPHP, HHVM & Hack• Eventually Nuts n Bolts was a solid CMS.• We used it for dozens of projects.• But it was a CMS.• It was never architected to be anything more than that.• But we had started pushing it well beyond it’s
architecture.
How I got started with HPHP, HHVM & Hack
How I got started with HPHP, HHVM & Hack• Wasn’t handling high traffic.• Wasn’t handling big data.
How I got started with HPHP, HHVM & Hack• It’s now 2015.• We had larger projects coming up.• So it was time for a new solution.
2009
2013
2015
How I got started with HPHP, HHVM & Hack• Our goal wasn’t to build another CMS.
How I got started with HPHP, HHVM & Hack• New development team.• New goals.• New methodologies and practices.
How I got started with HPHP, HHVM & Hack• Focus on writing new code, not fixing quirks and bugs.• Better insight into the code.• Strongly typed.
How I got started with HPHP, HHVM & Hack• Hack was written by
Facebook for Facebook.• Runs on HHVM.• It’s PHP, with a lot more
features.
How I got started with HPHP, HHVM & Hack• In the end we chose
Hack.• It met our requirements
for what we wanted moving forward.• Simple stepping stone
from PHP.
How I got started with HPHP, HHVM & Hack• It’s now 2016.• Our new framework has a 1.0.0 pre release.• Our new application platform is getting close.
2009
2013
2015
2016
How I got started with HPHP, HHVM & Hack• But wait…
How I got started with HPHP, HHVM & Hack• This isn’t a presentation
about building frameworks.• This isn’t a presentation
about our new platform.• Come back next year for
that!
Successes• Every team member has become a better developer.• Our products are more solid and robust.• We can do more with less.• We have a great framework and an amazing platform.
• Can use pre-baked Images or bake scriptsInstallation
Getting Started with HHVM & Hack
• Manual installation is simple with pre-built packages.• Ubuntu is as simple as “sudo apt-get install hhvm”.• Alternatively build from source.• https://github.com/facebook/hhvm
InstallationGetting Started with HHVM & Hack
• Analyses source code before run time for typing errors.• Catches issues with code before they become bugs!
The Type CheckerGetting Started with HHVM & Hack
• Type Checking is performed with the hh_client program which comes with HHVM.• It also integrates with various editors.
The Type CheckerGetting Started with HHVM & Hack
The Type CheckerGetting Started with HHVM & Hack
<?hh //strictclass App{ public function exec():void { $this->run(['bar']); } public function run(array<string,mixed> $array):void { var_dump($array); }}
Top Level Code Example
• Read The Manual!• http://docs.hhvm.com/ - Everything you need in one place.
• A great series on getting started available on Engine Yard.• https://blog.engineyard.com/2014/hhvm-hack
LearningGetting Started with HHVM & Hack
• Hack looks like PHP.• Often feels like PHP• But it’s not PHP.• There are quite a number of differences.
What’s the Difference?
• Hack opens with a different tag.• Instead of <?php, hack opens with <?hh instead.• Hack does not permit a closing tag. ?> will cause an
error.• Hack will not process the file as a Hack file if the first 4
characters does not match the Hack opening tag.• Hack files end with the .hh extension.
What’s the Difference?Opening Tag
• Top level code is not permitted.• This is often known as procedural or objectless code.• In most situations, Hack does not permit this.
What’s the Difference?Unsupported – Top Level Code
<?hh //strictfunction foo(int $x, int $y):int{
return $x+$y;} foo(1,3);
Top Level Code Example
• The previous example will cause the type checker to throw an error.• The method foo() was called at the top level.
What’s the Difference?Unsupported – Top Level Code
• Sometimes it’s unavoidable.• Small changes make the type checker happy.
What’s the Difference?Unsupported – Top Level Code
What’s the Difference?Unsupported – Top Level Code
<?hh //strictfunction foo(int $x, int $y):int{
return $x+$y;}
topLevel.hh
<?hh //strictrequire_once('topLevel.hh');class Bar{
public function __construct(){
foo(1,3);}
}
index.hh
• The previous example works because there is no unsupported top level code.• The require statement is allowed.
What’s the Difference?Unsupported – Top Level Code
require, require_onceinclude, include_oncenamespaceuseclass, trait, interfacefunction
• References are common practice in PHP.• Hack doesn’t permit them.• The type checker cannot do proper analysis of the code
if it uses references.• References violate the rules that the type checker
follows to properly analyze code.
What’s the Difference?Unsupported – References
• PHP’s roots are in HTML.• Mixing HTML and PHP has always been possible.• Hack doesn’t allow this.• The HHVM runtime cannot recognize files like this when
used as a Hack file (.hh).
What’s the Difference?Unsupported – HTML
• But wait...! There is a way!
What’s the Difference?Unsupported – HTML
• Hack also has something like React built in.• It’s called XHP and it looks something like this:
What’s the Difference?Unsupported – HTML
<?hh //strict$name='John Doe';print <p>Hello {$name}</p>;
XHP Example
• Some PHP intrinsic (or language constructs) are not supported in Hack.
What’s the Difference?Unsupported – Intrinsics
isset()empty()unset()
• Dynamic creation of code is not allowed.• eval and create_function are not supported.• Dynamic syntax like the following isn’t supported.
What’s the Difference?Unsupported – Dynamic Code
$this->$foo;$this->$foo();$$foo;
Unsupported Dynamic Syntax
• Variable variables.• Variable methods.• Variable properties.• All not supported because it’s impossible for the type
checker to guarantee what the results will be.
What’s the Difference?Unsupported – Dynamic Code
• PHP4 style constructors.• Template-style PHP syntax – if…endif and family.• Incrementing and Decrementing a string with ++ and --.• Word literal operators. Use “&&” instead of “and” etc.• “break x” and family are no longer allowed.• Hack is case sensitive. So if the class name is “Foo”, you
cannot instantiate it with “new foo()”.• Hack is more strict when calling methods in classes. Use
“$this”, “self” and “static” appropriately.
What’s the Difference?Unsupported – Other
• Start with Types.• Explore some other features along the way.
What’s the Difference?New Stuff
• PHP has been lacking types for a long time.• Recently introduced into PHP 7.0.• Slightly improved in PHP 7.1.• Will continue to improve.
What’s the Difference?New Stuff
• Type Annotations are what makes Hack so great.• They can be defined on:• Class Properties• Method and Function Parameters• Method and Function returns• Constants• And you can type some of the new types.
What’s the Difference?New Stuff
What’s the Difference?
<?phpclass DB{
public function upsert($record,$condition=[],$options=[]){
//...}
}
Basic PHP Example
• Consider the following example:
• An imaginary method.• Can insert or update a record in a database.
What’s the Difference?
<?phpclass DB{
public function upsert(Array $record, Array $condition=[],$options=[]){
//...}
}
PHP 5 Example
What’s the Difference?<?phpdeclare(strict_types=1);class DB{
public function upsert(
array $record,array $condition=[],array $options=[]
):array{
//...}
}
PHP 7.0 Example
What’s the Difference?<?phpdeclare(strict_types=1);class DB{
public function upsert(
array $record,array $condition=[],array $options=[]
):?array{
//...}
}
PHP 7.1 Example
What’s the Difference?<?hh //strictclass DB{
public function upsert(
array<string,mixed> $record,array<string,mixed> $condition=[],array<string,mixed> $options=[]
):?array<string,mixed>{
//...}
}
Hack Example
What’s the Difference?<?hh //stricttype CommonStringKeyArray=array<string,mixed>; class DB{
public function upsert(
CommonStringKeyArray $record,CommonStringKeyArray $condition=[],CommonStringKeyArray $options=[]
):?CommonStringKeyArray{
//...}
}
Hack Aliases Example
What’s the Difference?<?hh //stricttype CommonStringKeyArray =array<string,mixed>;type DBRecord =CommonStringKeyArray;type DBQuery =CommonStringKeyArray;type DBQueryOptions =CommonStringKeyArray;class DB{
public function upsert(
DBRecord $record,DBQuery $condition=[],DBQueryOptions $options=[]
):?DBRecord{
//...}
}
Hack Aliasing Alias Example
What’s the Difference?<?hh //stricttype CommonStringKeyArray =array<string,mixed>;type DBRecord =CommonStringKeyArray;type DBQuery =CommonStringKeyArray;type DBQueryOptions =shape(
'order' =>int,'limit' =>int,'offset‘ =>int
);class DB{
public function upsert(
DBRecord $record,DBQuery $condition=[],DBQueryOptions $options=[]
):?DBRecord{
//...}
}
Hack Shape Example
What’s the Difference?<?hh //strictrequire_once('types.hh');class DB{
private ?DBConnection $connection;private bool $connected=false;private DBQuery $lastQuery;
public function upsert(
DBRecord $record,DBQuery $condition=[],DBQueryOptions $options=[]
):?DBRecord{
//...}
}
Hack Typed Properties Example
What’s the Difference?<?hh //strictrequire_once('types.hh');class DB{
private ?DBConnection $connection;private bool $connected=false;private DBQuery $lastQuery;
public function upsert(
DBRecord $record,DBQuery $condition=[],DBQueryOptions $options=[]
):?DBRecord{
//...}
}
Hack Typed Properties Example
What’s the Difference?Hack Types
boolintfloatstringarrayresource
What’s the Difference?Hack Types
void Used for methods which don't return anything.
noreturnUsed for functions and static methods indicating that the function can never return because it either exists or throws an exception.
mixed A catch all which includes null and void.
<object> Any predefined class.
this For methods which return $this.
num A union type of int and float.
arraykey A union type of string and int.
• Most types can be prefixed with “?”.• This makes it acceptable for a method to return null in
addition to the stated type.• This does not apply to void or noreturn.• mixed already includes null.
Hack TypesWhat’s the Difference?
• Hack doesn’t allow the “callable” type in strict mode.• Instead, you need to express the shape of the callable.
Hack TypesWhat’s the Difference?
Hack TypesWhat’s the Difference?
function send(
Map<arraykey,mixed> $payload,(function(Map<arraykey,mixed>):bool) $callback
):this{
//...}
Callable Example
• Hack supports Tuples.• Tuples are considered as arrays.• But they have restrictions.
Hack TypesWhat’s the Difference?
• Tuples have a fixed size and fixed types.• Values may be changed. But must be the same type.
Hack TypesWhat’s the Difference?
function findFirst(array<string> $arr, string $likeRegex):(string, int){
//...}
Tuple Example
• Enum is another type supported by hack.Hack Types
What’s the Difference?
enum Size:int{
SMALL =0;MEDIUM =1;LARGE =2;XLARGE =3;
}
Enum Example
• Collections are provided to as specialized classes.• They implement specific container patterns.• Almost always better to use.• Better optimization results from HHVM.
CollectionsWhat’s the Difference?
• Hack provides 4 types of collections.Collections
What’s the Difference?
MapVectorSetPair
• A collection of values with strings or integers as index keys.• This collection is the most similar in functionality to
when comparing with a PHP array.
Collections – MapWhat’s the Difference?
• A collection of values which only supports integer indexed keys.
Collections – VectorWhat’s the Difference?
• A special collection.• It is keyless.• It only supports strings and integers as values.
Collections – SetWhat’s the Difference?
• Another special collection.• It only supports 2 values.• It has 2 indexed keys – 0 and 1.• It is immutable.
Collections – PairWhat’s the Difference?
• Each type of collection has an immutable counterpart.• Except Pair because it is already immutable.
Collections – ImmutablesWhat’s the Difference?
ImmMapImmVectorImmSet
• Each type of collection has a literal syntax that can be used in place of “new X()”.
Collections – Literal SyntaxWhat’s the Difference?
Map{'foo'=>1,'bar'=>2};Vector{1,2,3}Set{'a',1,'b',2}Pair{0.21455657,123.25366212}
Literal Collection Syntax
• Attributes• Allow you to apply metadata to things like classes and
methods.• This is reflectable.
Many Other New FeaturesWhat’s the Difference?
Many Other New FeaturesWhat’s the Difference?<< command('encryptString'),arguments(
[['--config','-c'],'Path to config files.'
],[
['--input','-i'],'The string to encrypt.'
],[
['--syslock','-s'],'Enable this option to restrict the output to only work on this server.' se
])
>> public function encryptString(Command $command){
//...}
Attributes
• Pipe Operator• The Pipe operator allows for a more concise, fluid syntax
for chaining together expressions.
Many Other New FeaturesWhat’s the Difference?
$path=implode('/',explode('\\',$this->getPath()));
The Old Way
$path =$this->getPath()|>explode('\\',$$)|>implode('/',$$);
The New Way
• Constructor Promotion• Trait and Interface Requirements• Async• Lambdas• And many other small ones…
Many Other New FeaturesWhat’s the Difference?
Pitfalls• Some tips to help you avoid common traps.• Remember that this is not PHP.• In many ways it looks like PHP, but its behaviour can be
very different.
Pitfalls• Always use the type checker.• It’s not an accessory which you boot up sometimes.• It’s your pre-emptive strike against the infectious bug
overlords.
Pitfalls• Don’t try and trick the type checker!• This === Dragons
Pitfalls• PHP allows for some very dynamic code.• It’s very forgiving.• HHVM does not allow this and trying to trick the type
checker can cause unforeseen behaviours in your code.
Pitfalls• Sometimes HHVM forgives.• This leads to WTF moments.• It works! But… wait what???• Side effects can be caused by bad code.• Mostly happens when the type checker is used
incorrectly or not at all.• Sometimes it’s a bug in HHVM.
Pitfalls• Partial mode is NOT your friend.• Don’t write your code against partial mode.• There are many benefits to writing strict Hack.
Pitfalls• HHVM will run PHP code with Hack code and Hack code
with PHP code.• Great for code migration.• Bad for achieving a 100% strict codebase.
Pitfalls• Sometimes you’ll be developing against a third party
library.• It could be from composer (Yes, everything from
composer will run on HHVM!)• In this case, you can use a HHI definition file to explain
to the type checker, all the methods and types which come from those libraries.
Stuck? Help is Easy!• Sometimes you’ll get stuck.• Try these:• Stack Overflow• Google• Github
• The Facebook developers are friendly and helpful.
Returning to PHP• You can try, but returning to PHP is unavoidable.• Sometimes you’ll be working with third party PHP
libraries.• Other times, what you need isn’t available in Hack but is
in PHP.• This is OKAY.
Returning to PHP• HHVM fully supports PHP and will continue to do so
moving forward.• The tools available for PHP also work with Hack.
Thank You!