PHP and JavaScript are both renowned to be languages with a lot of quirks. However two major initiatives on both sides, Hack for PHP and ES6 for JavaScript made the languages much better and modern. In this article I’m going to show all the ES6 features that are also in Hack.
Arrow Function
Both languages adopted the same shorter way to write functions. On JavaScript side, the main advantage is the automatic binding of this and for PHP it removes the need to declare all the variables you want to use from outside. ES6, Hack.
// JavaScript var odds = evens.map(v => v + 1); var nums = evens.map((v, i) => v + i); nums.filter(v => { if (v % 5 === 0) { console.log(v); return true; } return false; }); |
// Hack $odds = array_map($v ==> $v + 1, $evens); $nums = array_map(($v, $i) ==> $v + $i, $evens); array_filter($nums, $v ==> { if ($v % 5 === 0) { echo $v; return true; } return false; }); |
Class
JavaScript finally gets a class abstraction with ES6. It is however the bare minimal one to be useful, you cannot define constants, protected/private methods, traits … PHP on this side is much better, without any Hack addition. ES6, PHP5.
// JavaScript class SkinnedMesh extends THREE.Mesh { constructor(geometry, materials) { super(geometry, materials); this.idMatrix = SkinnedMesh.defaultMatrix(); this.bones = []; } update(camera) { super.update(); } static defaultMatrix() { return new THREE.Matrix4(); } } |
// Hack class SkinnedMesh extends THREEMesh { public function constructor($geometry, $materials) { parent::__construct($geometry, $materials); $this->idMatrix = SkinnedMesh::defaultMatrix(); $this->bones = array(); } public function update($camera) { parent::update(); } static private function defaultMatrix() { return new THREEMatrix4(); } } |
Enhanced Object Literal
One long standing issue with object literals in JavaScript is the inability to use an expression as a key. This is fixed with the bracket notation in ES6. PHP 5.4 introduced a short notation for arrays as well. ES6, PHP.
// JavaScript var obj = { [Math.random()]: true }; |
// Hack $obj = [rand() => true]; |
Template Strings
Multiline strings and variable interpolations are something that have always been possible in PHP, yet they only start to work in ES6! ES6, PHP.
// JavaScript var multiline = `In JavaScript this is not legal.` var name = 'Bob', time = 'today'; `Hello ${name}, how are you ${time}?` |
// Hack $multiline = 'In PHP this is legal.'; $name = 'Bob'; $time = 'today'; "Hello $name, how are you $time?"; |
Default Arguments
It was possible to write default arguments in JavaScript but ES6 adds proper support for it right in the function declaration. Guess what, PHP had support for it all along. ES6, PHP.
// JavaScript function f(x, y=12) { return x + y; } f(3) === 15; f(2, 10) === 12; |
// Hack function f($x, $y=12) { return $x + $y; } f(3) === 15; f(2, 10) === 12; |
Iterator + for of
JavaScript has two ways to iterate on collections, either
for (var i = 0; i < array.length; ++i) { var element = array[i]; /* ... */ } for (var key in object) { var element = object[key]; /* ... */ } |
ES6 is now introducing a unified way to do iteration, that PHP always had, as well as a way to write custom collections via the iterator pattern, introduced in PHP5. ES6, PHP, PHP5.
// JavaScript var fibonacci = { [Symbol.iterator]: function() { var previous = 0; var current = 1; return { next: function() { var new_previous = current; current += previous; previous = new_previous; return { value: current, done: false } } } } } for (var n of fibonacci) { if (n > 1000) break; console.log(n); } |
return {
value: current,
done: false
}
}
}
}
}
for (var n of fibonacci) {
if (n > 1000) break;
console.log(n);
}
// Hack class Fibonacci implements Iterator { private $key = 0; private $previous = 1; private $current = 0; public function next() { $new_previous = $this->current; $this->current += $this->previous; $this->previous = $new_previous; $this->key++; } public function current() { return $this->current; } public function valid() { return true; } public function key() { return $this->key; } public function rewind() { $this->previous = 1; $this->current = 0; $this->key = 0; } } foreach (new Fibonacci() as $n) { if ($n > 1000) break; echo $n; } |
public function next() {
$new_previous = $this->current;
$this->current += $this->previous;
$this->previous = $new_previous;
$this->key++;
}
public function current() {
return $this->current;
}
public function valid() {
return true;
}
public function key() {
return $this->key;
}
public function rewind() {
$this->previous = 1;
$this->current = 0;
$this->key = 0;
}
}
foreach (new Fibonacci() as $n) {
if ($n > 1000) break;
echo $n;
}
Generators
Python pioneered generators as another tool to manage control flow. It has originally been designed and promoted as an easier way to write iterators, but really shined as a better way to write asynchronous operations than callbacks. ES6, PHP5.
// JavaScript var fibonacci = { [Symbol.iterator]: function*() { var previous = 1; var current = 0; for (;;) { var new_previous = current; current += previous; previous = new_previous; yield current; } } } for (var n of fibonacci) { if (n > 1000) break; console.log(n); } |
// Hack function fibonacci() { $previous = 1; $current = 0; for (;;) { $new_previous = $current; $current += $previous; $previous = $new_previous; yield $current; } } foreach (fibonacci() as $n) { if ($n > 1000) break; echo $n; } |
function fibonacci() {
$previous = 1;
$current = 0;
for (;;) {
$new_previous = $current;
$current += $previous;
$previous = $new_previous;
yield $current;
}
}
foreach (fibonacci() as $n) {
if ($n > 1000) break;
echo $n;
}
ES7 Async Await
C# introduced the concept of async/await combination to deal with asynchronous programming. The underlying implementation is very similar to generators but has proper syntax support. It is an addition of Hack on-top of PHP. ES7, Hack.
// JavaScript async function chainAnimationsAsync(element, animations) { var result = null; try { for (var animation in animations) { result = await animation(element); } } catch (e) { /* ignore and keep going */ } return result; } |
// Hack async function chainAnimationsAsync($element, $animations) { $result = null; try { foreach ($animations as $animation) { $result = await animation($element); } } catch (Exception $e) { /* ignore and keep going */ } return $result; } |
Map + Set
Both JavaScript and PHP are notorious for attempting to fit all the collection use cases into a single general purpose type. Both ES6 and Hack bring to the table proper support for Map and Set. ES6, Hack
// JavaScript var s = new Set(); s.add('hello').add('goodbye').add('hello'); s.size === 2; s.has('hello') === true; var m = new Map(); m.set('hello', 42); m.get('hello') === 42; |
var m = new Map();
m.set(‘hello’, 42);
m.get(‘hello’) === 42;
// Hack $s = new Set(); $s->add('hello')->add('goodbye')->add('hello'); $s->count() === 2; $s->contains('hello') === true; $m = new Map(); $m->set('hello', 42); $m->get('hello') === 42; |
$m = new Map();
$m->set(‘hello’, 42);
$m->get(‘hello’) === 42;
TypeScript
Last but not least, both languages are getting gradual typing. TypeScript, Hack.
// JavaScript class Greeter { greeting: T; constructor(message: T) { this.greeting = message; } greet() { return this.greeting; } } var greeter = new Greeter("Hello, world"); console.log(greeter->greet()); |
var greeter = new Greeter("Hello, world");
console.log(greeter->greet());
// Hack class Greeter { public function __construct(private T $greeting) {} public function greet() { return $this->greeting; } } $greeter = new Greeter("Hello, world"); echo $greeter->greet(); |
public function __construct(private T $greeting) {}
public function greet() {
return $this->greeting;
}
}
$greeter = new Greeter("Hello, world");
echo $greeter->greet();
Conclusion
With ES6 and Hack efforts, JavaScript and PHP are becoming languages with modern features. If you tried them 5 years ago, you should take another look, they are not as crappy as they once were 🙂
A cyber security provider’s main task is to protect your business from all forms of cyber-attacks. If and when an attack happens, https://www.sapphire.net/ will know exactly what to do.