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;
}); |
// 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;
}); |
// 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();
}
} |
// 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 THREE\Mesh {
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 THREE\Matrix4();
}
} |
// Hack
class SkinnedMesh extends THREE\Mesh {
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 THREE\Matrix4();
}
}
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 }; |
// JavaScript
var obj = { [Math.random()]: true };
// Hack
$obj = [rand() => 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}?` |
// 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?"; |
// 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; |
// 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; |
// 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]; /* ... */ } |
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);
} |
// 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);
}
// 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;
} |
// 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;
}
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);
} |
// 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;
} |
// 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;
}
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;
} |
// 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;
} |
// 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; |
// 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;
// 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; |
// 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;
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()); |
// 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());
// Hack
class Greeter {
public function __construct(private T $greeting) {}
public function greet() {
return $this->greeting;
}
}
$greeter = new Greeter("Hello, world");
echo $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();
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.