19. <?hh
// Hack functions are annotated with types.
function my_negation(bool $x): bool {
return !$x;
}
// FIXME: annotate this function parameter
// and return with the type 'int'.
function add_one(/* TODO */ $x): /* TODO */ {
return $x+1;
}
20. <?hh
// Hack functions are annotated with types.
function my_negation(bool $x): bool {
return !$x;
}
// FIXME: annotate this function parameter
// and return with the type 'int'.
function add_one(int $x): int {
return $x+1;
}
22. <?hh
/* Hack errors come in multiple parts.
* Hover over the underlined parts!
*/
function add_one(int $x): int {
return $x+1;
}
function test(): void {
$my_string = 'hello';
// Some clever code ...
add_one($my_string);
}
23. <?hh
/* Hack errors come in multiple parts.
* Hover over the underlined parts!
*/
function add_one(int $x): int {
return $x+1;
}
function test(): void {
$my_string = 'hello';
// Some clever code ...
add_one((int) $my_string);
}
25. <?hh
// Prefixing a type with '?' permits null.
// TODO: fix the type of the parameter $x to permit null.
function f(int $x): void {
var_dump($x);
}
function test(): void {
f(123);
f(null);
}
26. <?hh
// Prefixing a type with '?' permits null.
// TODO: fix the type of the parameter $x to permit null.
function f(?int $x): void {
var_dump($x);
}
function test(): void {
f(123);
f(null);
}
28. <?hh
interface User { public function getName(): string; }
function get_user_name(?User $user): string {
if($user !== null) {
// We checked that $user was not null.
// Its type is now 'User'.
/* TODO: return $user->getName() */
}
return '<invalid name>';
}
function test(User $user) {
$name1 = get_user_name($user);
$name2 = get_user_name(null);
}
29. <?hh
interface User { public function getName(): string; }
function get_user_name(?User $user): string {
if($user !== null) {
// We checked that $user was not null.
// Its type is now 'User'.
return $user->getName();
}
return '<invalid name>';
}
function test(User $user) {
$name1 = get_user_name($user);
$name2 = get_user_name(null);
}
31. <?hh
interface User { public function getName(): string; }
// There are many ways to handle null values.
// Throwing an exception is one of them.
function get_user_name(?User $user): string {
if($user === null) {
throw new RuntimeException('Invalid user name');
}
/* TODO: return $user->getName() */
}
function test(User $user) {
$name1 = get_user_name($user);
$name2 = get_user_name(null);
}
32. <?hh
interface User { public function getName(): string; }
// There are many ways to handle null values.
// Throwing an exception is one of them.
function get_user_name(?User $user): string {
if($user === null) {
throw new RuntimeException('Invalid user name');
}
return $user->getName();
}
function test(User $user) {
$name1 = get_user_name($user);
$name2 = get_user_name(null);
}
37. <?hh
// Hack uses generics for Collection types.
// TODO: fix the return type of the function 'test'
function test(): Vector<string> {
$vector = Vector {1, 2, 3};
return $vector;
}
38. <?hh
// Hack uses generics for Collection types.
// TODO: fix the return type of the function 'test'
function test(): Vector<string> {
$vector = Vector {“1”, “2”, “3”};
return $vector;
}
40. <?hh
function vector_add1(Vector<int> $v): Vector<int> {
// Example of lambda expressions.
return $v->map($x ==> $x + 1);
}
function vector_mult2(Vector<int> $v): Vector<int> {
// TODO: write a function multiplying all the elements by 2
}
41. <?hh
function vector_add1(Vector<int> $v): Vector<int> {
// Example of lambda expressions.
return $v->map($x ==> $x + 1);
}
function vector_mult2(Vector<int> $v): Vector<int> {
// TODO: write a function multiplying all the elements by 2
return $v->map($x ==> $x * 2);
}
45. <?hh
// All the members of a class must be initialized
class Point {
private float $x;
private float $y;
public function __construct(float $x, float $y) {
$this->x = $x;
// FIXME: initalize the member 'y'
}
}
46. <?hh
// All the members of a class must be initialized
class Point {
private float $x;
private float $y;
public function __construct(float $x, float $y) {
$this->x = $x;
// FIXME: initalize the member 'y'
$this->y = $y;
}
}
48. <?hh
// Check out this new syntax!
// It's shorter and does the same thing ...
class Point {
public function __construct(
private float $x,
private float $y
) {}
}
49. <?hh
// Check out this new syntax!
// It's shorter and does the same thing ...
class Point {
public function __construct(
private float $x,
private float $y
) {}
}
// このような新しい書き方で今までより短くなります
51. <?hh
// You can create your own generics!
class Store<T> {
public function __construct(private T $data) {}
public function get(): T { return $this->data; }
public function set(T $x): void { $this->data = $x; }
}
// TODO: fix the return type of the function test
function test(): Store<int> {
$data = 'Hello world!';
$x = new Store($data);
return $x;
}
52. <?hh
// You can create your own generics!
class Store<T> {
public function __construct(private T $data) {}
public function get(): T { return $this->data; }
public function set(T $x): void { $this->data = $x; }
}
// TODO: fix the return type of the function test
function test(): Store<string> {
$data = 'Hello world!';
$x = new Store($data);
return $x;
}
54. <?hh
// You can specify constraints on generics.
interface MyInterface {
public function foo(): void;
}
// TODO: uncomment 'as MyInterface'
// T as MyInterface means any object as long as
// it implements MyInterface
function call_foo<T /* as MyInterface */>(T $x): T {
$x->foo();
return $x;
}
55. <?hh
// You can specify constraints on generics.
interface MyInterface {
public function foo(): void;
}
// TODO: uncomment 'as MyInterface'
// T as MyInterface means any object as long as
// it implements MyInterface
function call_foo<T as MyInterface>(T $x): T {
$x->foo();
return $x;
}
57. <?hh
// The type 'this' always points to the most derived type
class MyBaseClass {
protected int $count = 0;
// TODO: replace 'MyBaseClass' by 'this'
public function add1(): MyBaseClass {
$this->count += 1;
return $this;
}
}
class MyDerivedClass extends MyBaseClass {
public function print_count(): void { echo $this->count; }
}
function test(): void {
$x = new MyDerivedClass();
$x->add1()->print_count();
}
58. <?hh
// The type 'this' always points to the most derived type
class MyBaseClass {
protected int $count = 0;
// TODO: replace 'MyBaseClass' by 'this'
public function add1(): this {
$this->count += 1;
return $this;
}
}
class MyDerivedClass extends MyBaseClass {
public function print_count(): void { echo $this->count; }
}
function test(): void {
$x = new MyDerivedClass();
$x->add1()->print_count();
}
60. <?hh
// When a type is too long, you can use a type alias.
type Matrix<T> = Vector<Vector<T>>;
function first_row<T>(Matrix<T> $matrix): Vector<T> {
return $matrix[0];
}
61. <?hh
// When a type is too long, you can use a type alias.
type Matrix<T> = Vector<Vector<T>>;
function first_row<T>(Matrix<T> $matrix): Vector<T> {
return $matrix[0];
}
// タイプが長い時は別名を指定出来ます
66. <?hh
// Shapes can be used for arrays with constant string keys.
type my_shape = shape(
'field1' => int,
'field2' => bool,
);
function first_shape(): my_shape {
$result = shape('field1' => 1);
// TODO: set 'field2' to the value true
// on $result to complete the shape.
return $result;
}
67. <?hh
// Shapes can be used for arrays with constant string keys.
type my_shape = shape(
'field1' => int,
'field2' => bool,
);
function first_shape(): my_shape {
$result = my_shape(1, true);
// TODO: set 'field2' to the value true
// on $result to complete the shape.
return $result;
}
69. <?hh
// You can specify the types of functions too.
function apply_int<T>((function(int): T) $callback, int $value): T {
// TODO: return $callback($value)
}
70. <?hh
// You can specify the types of functions too.
function apply_int<T>((function(int): T) $callback, int $value): T {
return $callback($value);
}
72. <?hh
// XHP is useful to build html (or xml) elements.
// The escaping is done automatically, it is important to avoid
// security issues (XSS attacks).
function build_paragraph(string $text, string $style): :div {
return
<div style={$style}>
<p>{$text}</p>
</div>;
}
73. <?hh
// XHP is useful to build html (or xml) elements.
// The escaping is done automatically, it is important to avoid
// security issues (XSS attacks).
function build_paragraph(string $text, string $style): :div {
return
<div style={$style}>
<p>{$text}</p>
</div>;
}
// XHP記法でHTMLまたはXMLを構築することにより、クロスサイトスクリプティング対
策が実現できます
75. <?hh
/* Opaque types let you hide the representation of a type.
*
* The definition below introduces the new type 'user_id'
* that will only be compatible with 'int' within this file.
* Outside of this file, 'user_id' becomes "opaque"; it won't
* be compatible with 'int' anymore.
*/
newtype user_id = int;
function make_user_id(int $x): user_id {
// Do some checks ...
return $x;
}
// You should only use this function for rendering
function user_id_to_int(user_id $x): int {
return $x;
}
76. <?hh
/* Opaque types let you hide the representation of a type.
*
* The definition below introduces the new type 'user_id'
* that will only be compatible with 'int' within this file.
* Outside of this file, 'user_id' becomes "opaque"; it won't
* be compatible with 'int' anymore.
*/
newtype user_id = int;
function make_user_id(int $x): user_id {
// Do some checks ...
return $x;
}
// You should only use this function for rendering
function user_id_to_int(user_id $x): int {
return $x;
}
// user_idタイプを作る事により、このファイルで型を管理し、他のファイルではuser_id型になります
78. <?hh
class MyBaseClass {
// TODO: fix the typo in the name of the method.
public function get_uuser(): MyUser {
return new MyUser();
}
}
class MyDerivedClass extends MyBaseClass {
/* <<Override>> is used to specify that get_user has been inherited.
* When that's not the case, Hack gives an error.
*/
<<Override>> public function get_user(): MyUser {
return new MyUser();
}
}
79. <?hh
class MyBaseClass {
// TODO: fix the typo in the name of the method.
public function get_user(): MyUser {
return new MyUser();
}
}
class MyDerivedClass extends MyBaseClass {
/* <<Override>> is used to specify that get_user has been inherited.
* When that's not the case, Hack gives an error.
*/
<<Override>> public function get_user(): MyUser {
return new MyUser();
}
}
81. <?hh
class C { protected function bar(): void {} }
interface I { public function foo(): void; }
// 'require' lets you specify what the trait needs to work properly.
trait T {
// The class using the trait must extend 'C'
require extends C;
// TODO: uncomment the next line to fix the error
// require implements I;
public function do_stuff(): void {
$this->bar(); // We can access bar because we used "require extends"
$this->foo();
}
}
82. <?hh
class C { protected function bar(): void {} }
interface I { public function foo(): void; }
// 'require' lets you specify what the trait needs to work properly.
trait T {
// The class using the trait must extend 'C'
require extends C;
// TODO: uncomment the next line to fix the error
require implements I;
public function do_stuff(): void {
$this->bar(); // We can access bar because we used "require extends"
$this->foo();
}
}