mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-08-18 20:41:29 +02:00
Merge pull request #4439 from AndrewDiMola/update-stale-hack-docs
[hack/en] Overhaul Hack in Y Minutes
This commit is contained in:
@@ -1,308 +1,420 @@
|
|||||||
---
|
---
|
||||||
language: Hack
|
language: Hack
|
||||||
contributors:
|
contributors:
|
||||||
|
- ["Andrew DiMola", "https://github.com/AndrewDiMola"]
|
||||||
- ["Stephen Holdaway", "https://github.com/stecman"]
|
- ["Stephen Holdaway", "https://github.com/stecman"]
|
||||||
- ["David Lima", "https://github.com/davelima"]
|
- ["David Lima", "https://github.com/davelima"]
|
||||||
filename: learnhack.hh
|
filename: learnhack.hh
|
||||||
---
|
---
|
||||||
|
|
||||||
Hack is a superset of PHP that runs under a virtual machine called HHVM. Hack
|
[Hack](https://hacklang.org/) lets you write code quickly, while also having safety features built in, like static typechecking.
|
||||||
is almost completely interoperable with existing PHP code and adds a bunch of
|
|
||||||
useful features from statically typed languages.
|
|
||||||
|
|
||||||
|
To run Hack code, [install HHVM](https://docs.hhvm.com/hhvm/installation/introduction), the open-source virtual machine.
|
||||||
|
|
||||||
Only Hack-specific features are covered here. Details about PHP's syntax are
|
```Hack
|
||||||
available in the [PHP article](http://learnxinyminutes.com/docs/php/) on this site.
|
/* ==================================
|
||||||
|
* READ THE DOCS!
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
```php
|
/* For more information on the Hack language:
|
||||||
<?hh
|
* - About Hack: https://hacklang.org/
|
||||||
|
* - Documentation: https://docs.hhvm.com/hack/
|
||||||
|
*/
|
||||||
|
|
||||||
// Hack syntax is only enabled for files starting with an <?hh marker
|
/* ==================================
|
||||||
// <?hh markers cannot be interspersed with HTML the way <?php can be.
|
* A NOTE ON PHP
|
||||||
// Using the marker "<?hh //strict" puts the type checker in strict mode.
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The Hack language began as a superset of PHP.
|
||||||
|
// Since then, the languages have (largely) diverged.
|
||||||
|
// You may encounter the .php extension, which is no longer recommended.
|
||||||
|
|
||||||
// Scalar parameter type hints
|
/* ==================================
|
||||||
function repeat(string $word, int $count)
|
* COMMENTS
|
||||||
{
|
* ==================================
|
||||||
$word = trim($word);
|
*/
|
||||||
return str_repeat($word . ' ', $count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type hints for return values
|
// Hack has single-line comments...
|
||||||
function add(...$numbers) : int
|
|
||||||
{
|
|
||||||
return array_sum($numbers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions that return nothing are hinted as "void"
|
/* Multi-line comments...
|
||||||
function truncate(resource $handle) : void
|
*
|
||||||
{
|
*/
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type hints must explicitly allow being nullable
|
/**
|
||||||
function identity(?string $stringOrNull) : ?string
|
* ... and a special syntax for doc comments.
|
||||||
{
|
*
|
||||||
return $stringOrNull;
|
* Use doc comments to summarize the purpose of a definition, function, class or method.
|
||||||
}
|
*/
|
||||||
|
|
||||||
// Type hints can be specified on class properties
|
/* ==================================
|
||||||
class TypeHintedProperties
|
* NAMESPACES
|
||||||
{
|
* ==================================
|
||||||
public ?string $name;
|
*/
|
||||||
|
|
||||||
protected int $id;
|
// Namespaces contain definitions of classes, interfaces, traits, functions, and constants.
|
||||||
|
|
||||||
private float $score = 100.0;
|
namespace LearnHackinYMinutes {
|
||||||
|
|
||||||
// Hack's type checker enforces that typed properties either have a
|
/* ==================================
|
||||||
// default value or are set in the constructor.
|
* TYPES
|
||||||
public function __construct(int $id)
|
* ==================================
|
||||||
{
|
*/
|
||||||
$this->id = $id;
|
|
||||||
|
function demo_hack_types(): void {
|
||||||
|
|
||||||
|
// Hack has five primitive types: bool, int, float, string, and null.
|
||||||
|
$is_helpful = true; // bool
|
||||||
|
$int_value = 10; // int
|
||||||
|
$precise_value = 2.0; // float
|
||||||
|
$hello_world = "Hello World!"; // string
|
||||||
|
$null_string = null; // null
|
||||||
|
|
||||||
|
// Create a `shape` with the shape keyword, with a series of field names and values.
|
||||||
|
$my_point = shape('x' => -3, 'y' => 6, 'visible' => true);
|
||||||
|
|
||||||
|
// Create a `tuple` with the tuple keyword, with a series of two or more types as values.
|
||||||
|
$apple_basket = tuple("apples", 25); // different types are OK
|
||||||
|
|
||||||
|
// Use `arraykey` to represent either an integer or string.
|
||||||
|
$the_answer = 42;
|
||||||
|
$is_answer = process_key($the_answer);
|
||||||
|
|
||||||
|
// Similarly, `num` represents either an int or float.
|
||||||
|
$lucky_number = 7;
|
||||||
|
$lucky_square = calculate_square($lucky_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
function process_key(arraykey $the_answer): bool {
|
||||||
|
if ($the_answer is int) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
} // true
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculate_square(num $arg)[]: float {
|
||||||
|
return ((float)$arg * $arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enums are limited to int or string (as an Arraykey), or other enum values.
|
||||||
|
enum Permission: string {
|
||||||
|
Read = 'R';
|
||||||
|
Write = 'W';
|
||||||
|
Execute = 'E';
|
||||||
|
Delete = 'D';
|
||||||
|
}
|
||||||
|
|
||||||
|
// In contrast, an enum class can be of any value type!
|
||||||
|
enum class Random: mixed {
|
||||||
|
int X = 42;
|
||||||
|
string S = 'foo';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* HACK ARRAYS
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The following line lets us use functions in the `C\` namespace.
|
||||||
|
use namespace HH\Lib\C; // the `C` library operates on containers
|
||||||
|
|
||||||
|
function demo_hack_arrays(): void {
|
||||||
|
|
||||||
|
// vec: ordered
|
||||||
|
$v = vec[1, 2, 3];
|
||||||
|
$letters = vec['a', 'b', 'c'];
|
||||||
|
|
||||||
|
$letters[0]; // returns 'a'
|
||||||
|
$letters[] = 'd'; // appends 'd'
|
||||||
|
|
||||||
|
// `inout` provides pass-by-reference behavior
|
||||||
|
C\pop_back(inout $letters); // removes 'd'
|
||||||
|
C\pop_front(inout $letters); // removes 'a'
|
||||||
|
|
||||||
|
// keyset: ordered, without duplicates
|
||||||
|
$k = keyset[1, 2, 3]; // values must be int or string
|
||||||
|
$colors = keyset['red', 'blue', 'green'];
|
||||||
|
|
||||||
|
// keyset keys are identical to their values
|
||||||
|
$colors['blue']; // returns 'blue'.
|
||||||
|
|
||||||
|
$colors[] = 'yellow'; // appends 'yellow'
|
||||||
|
unset($colors['red']); // removes 'red'
|
||||||
|
|
||||||
|
// dict: ordered, by key-value
|
||||||
|
$d = dict['a' => 1, 'b' => 3]; // keys must be int or string
|
||||||
|
$alphabet = dict['a' => 1, 'b' => 2];
|
||||||
|
|
||||||
|
$alphabet['a']; // indexing at 'a' returns `1`
|
||||||
|
$alphabet['c'] = 3; // adds a new key-value pair of `c => 3`
|
||||||
|
|
||||||
|
unset($alphabet['b']); // removes 'b'
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* THE HACK STANDARD LIBRARY (HSL)
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The Hack Standard Library is a set of functions and classes for the Hack language.
|
||||||
|
// Namespace use declarations are ideally at the top of your file but are placed here for instruction purposes.
|
||||||
|
|
||||||
|
use namespace HH\Lib\Str; // The `Str` library operates on strings
|
||||||
|
|
||||||
|
function demo_hack_standard_library(): void {
|
||||||
|
|
||||||
|
$letters = vec['a', 'b', 'c'];
|
||||||
|
$colors = keyset['red', 'blue', 'green'];
|
||||||
|
$alphabet = dict['a' => 1, 'b' => 2];
|
||||||
|
|
||||||
|
C\contains($letters, 'c'); // checks for a value; returns 'true'
|
||||||
|
C\contains($colors, 'purple'); // checks for a value; returns 'false'
|
||||||
|
C\contains_key($alphabet, 'a'); // checks for a key; returns 'true'
|
||||||
|
C\contains($alphabet, 'd'); // checks for a value; returns 'false'
|
||||||
|
|
||||||
|
Str\length("foo"); // returns `3`
|
||||||
|
Str\join(vec['foo', 'bar', 'baz'], '!'); // returns `foo!bar!baz`
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* HELLO WORLD!
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
use namespace HH\Lib\IO; // the `IO` library is a standard API for input / output
|
||||||
|
|
||||||
|
<<__EntryPoint>> // required attribute for the typical entry/main function
|
||||||
|
async function main(): Awaitable<
|
||||||
|
void,
|
||||||
|
> { // does not need to be named 'main' / is an asynchronous function
|
||||||
|
await IO\request_output()->writeAllAsync(
|
||||||
|
"Hello World!\n",
|
||||||
|
); // prints 'Hello World'!
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* FUNCTIONS
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Functions are defined globally.
|
||||||
|
// When a function is defined in a class, we refer to the function as a method.
|
||||||
|
|
||||||
|
// Functions have return types (here: `int`) and must return a value of
|
||||||
|
// that type or return no value when a void return type annotation was used.
|
||||||
|
|
||||||
|
function add_one(int $x): int {
|
||||||
|
return $x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions can also have defined, default values.
|
||||||
|
function add_value(int $x, int $y = 1): int {
|
||||||
|
return $x + $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions can be variadic (unspecified length of arguments).
|
||||||
|
function sum_ints(int $val, int ...$vals): int {
|
||||||
|
$result = $val;
|
||||||
|
|
||||||
|
foreach ($vals as $v) {
|
||||||
|
$result += $v;
|
||||||
}
|
}
|
||||||
}
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions can also be anonymous (defined with the `==>` arrow).
|
||||||
|
// $f = (int $x): int ==> $x + 1;
|
||||||
|
|
||||||
// Concise anonymous functions (lambdas)
|
/* ==================================
|
||||||
$multiplier = 5;
|
* PIPE OPERATOR
|
||||||
array_map($y ==> $y * $multiplier, [1, 2, 3]);
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The pipe operator, `|>`, evaluates the result of a left-hand expression
|
||||||
|
// and stores the result in `$$`, the predefined pipe variable.
|
||||||
|
|
||||||
// Generics
|
use namespace HH\Lib\Vec;
|
||||||
class Box<T>
|
|
||||||
{
|
|
||||||
protected T $data;
|
|
||||||
|
|
||||||
public function __construct(T $data) {
|
function demo_pipe_operator(): void {
|
||||||
$this->data = $data;
|
|
||||||
|
Vec\sort(Vec\map(vec[2, 1, 3], $a ==> $a * $a)); // vec[1,4,9]
|
||||||
|
|
||||||
|
// the same result, but using the pipe operator and pipe variable:
|
||||||
|
$x = vec[2, 1, 3]
|
||||||
|
|> Vec\map($$, $a ==> $a * $a) // $$ with value vec[2,1,3]
|
||||||
|
|> Vec\sort($$); // $$ with value vec[4,1,9]
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* ATTRIBUTES
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Hack provides built-in attributes that can change runtime or static type checking behavior.
|
||||||
|
// For example, we used the `__EntryPoint` attribute earlier in the "Hello World!" example.
|
||||||
|
|
||||||
|
// As another example, `__Memoize` caches the result of a function.
|
||||||
|
<<__Memoize>>
|
||||||
|
async function do_expensive_task(): Awaitable<string> {
|
||||||
|
$site_contents = await \HH\Asio\curl_exec("http://hacklang.org");
|
||||||
|
return $site_contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* CONTEXTS
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Hack functions are attached to different contexts and capabilities.
|
||||||
|
// A context is a grouping of capabilities; that is, a grouping of permissions.
|
||||||
|
|
||||||
|
// To declare allowed contexts (and capabilities), use the Context List `[]`.
|
||||||
|
// If contexts are not defined, your function includes permissions defined in Hack's `defaults` context.
|
||||||
|
|
||||||
|
// Because the context list is NOT defined, the `defaults` context is implicitly declared.
|
||||||
|
async function implicit_defaults_context(): Awaitable<void> {
|
||||||
|
await IO\request_output()->writeAllAsync(
|
||||||
|
"Hello World!\n",
|
||||||
|
); // prints 'Hello World'!
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the function below, the context list is defined to have the `defaults` context.
|
||||||
|
// A function can have multiple contexts [context1, context2, ...].
|
||||||
|
// `defaults` includes most of the capabilities defined by the Hack language.
|
||||||
|
async function explicit_defaults_context()[defaults]: Awaitable<void> {
|
||||||
|
await IO\request_output()->writeAllAsync("Hello World!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can also specify zero contexts to create a pure function (no capabilities).
|
||||||
|
async function empty_context()[]: Awaitable<void> {
|
||||||
|
// The following line is an error, as the function does not have IO capabilities.
|
||||||
|
// await IO\request_output()->writeAllAsync("Hello World!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* GENERICS
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Generics allow classes or methods to be parameterized to any set of types.
|
||||||
|
// That's pretty cool!
|
||||||
|
|
||||||
|
// Hack typically passes by value: use `inout` to pass by reference.
|
||||||
|
function swap<T>(inout T $input1, inout T $input2): void {
|
||||||
|
$temp = $input1;
|
||||||
|
$input1 = $input2;
|
||||||
|
$input2 = $temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* CLASSES
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Classes provide a way to group functionality and state together.
|
||||||
|
// To define a class, use the `class` keyword. To instantiate, use `new`.
|
||||||
|
// Like other languages, you can use `$this` to refer to the current instance.
|
||||||
|
|
||||||
|
class Counter {
|
||||||
|
private int $i = 0;
|
||||||
|
|
||||||
|
public function increment(): void {
|
||||||
|
$this->i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getData(): T {
|
public function get(): int {
|
||||||
return $this->data;
|
return $this->i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openBox(Box<int> $box) : int
|
// Properties and Methods can be static (not requiring instantiation).
|
||||||
{
|
class Person {
|
||||||
return $box->getData();
|
public static function favoriteProgrammingLanguage(): string {
|
||||||
}
|
return "Hack";
|
||||||
|
|
||||||
|
|
||||||
// Shapes
|
|
||||||
//
|
|
||||||
// Hack adds the concept of shapes for defining struct-like arrays with a
|
|
||||||
// guaranteed, type-checked set of keys
|
|
||||||
type Point2D = shape('x' => int, 'y' => int);
|
|
||||||
|
|
||||||
function distance(Point2D $a, Point2D $b) : float
|
|
||||||
{
|
|
||||||
return sqrt(pow($b['x'] - $a['x'], 2) + pow($b['y'] - $a['y'], 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
distance(
|
|
||||||
shape('x' => -1, 'y' => 5),
|
|
||||||
shape('x' => 2, 'y' => 50)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// Type aliasing
|
|
||||||
//
|
|
||||||
// Hack adds a bunch of type aliasing features for making complex types readable
|
|
||||||
newtype VectorArray = array<int, Vector<int>>;
|
|
||||||
|
|
||||||
// A tuple containing two integers
|
|
||||||
newtype Point = (int, int);
|
|
||||||
|
|
||||||
function addPoints(Point $p1, Point $p2) : Point
|
|
||||||
{
|
|
||||||
return tuple($p1[0] + $p2[0], $p1[1] + $p2[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
addPoints(
|
|
||||||
tuple(1, 2),
|
|
||||||
tuple(5, 6)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// First-class enums
|
|
||||||
enum RoadType : int
|
|
||||||
{
|
|
||||||
Road = 0;
|
|
||||||
Street = 1;
|
|
||||||
Avenue = 2;
|
|
||||||
Boulevard = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRoadType() : RoadType
|
|
||||||
{
|
|
||||||
return RoadType::Avenue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Constructor argument promotion
|
|
||||||
//
|
|
||||||
// To avoid boilerplate property and constructor definitions that only set
|
|
||||||
// properties, Hack adds a concise syntax for defining properties and a
|
|
||||||
// constructor at the same time.
|
|
||||||
class ArgumentPromotion
|
|
||||||
{
|
|
||||||
public function __construct(public string $name,
|
|
||||||
protected int $age,
|
|
||||||
private bool $isAwesome) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WithoutArgumentPromotion
|
|
||||||
{
|
|
||||||
public string $name;
|
|
||||||
|
|
||||||
protected int $age;
|
|
||||||
|
|
||||||
private bool $isAwesome;
|
|
||||||
|
|
||||||
public function __construct(string $name, int $age, bool $isAwesome)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->age = $age;
|
|
||||||
$this->isAwesome = $isAwesome;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function demo_hack_classes(): void {
|
||||||
|
// Use `new` to instantiate a class.
|
||||||
|
$c1 = new Counter();
|
||||||
|
|
||||||
// Co-operative multi-tasking
|
// To call a static property or method, use `::`
|
||||||
//
|
$typical_person = tuple("Andrew", Person::favoriteProgrammingLanguage());
|
||||||
// Two new keywords "async" and "await" can be used to perform multi-tasking
|
}
|
||||||
// Note that this does not involve threads - it just allows transfer of control
|
|
||||||
async function cooperativePrint(int $start, int $end) : Awaitable<void>
|
|
||||||
{
|
|
||||||
for ($i = $start; $i <= $end; $i++) {
|
|
||||||
echo "$i ";
|
|
||||||
|
|
||||||
// Give other tasks a chance to do something
|
// Abstract class can be defined, but not instantiated directly.
|
||||||
await RescheduleWaitHandle::create(RescheduleWaitHandle::QUEUE_DEFAULT, 0);
|
abstract class Machine {
|
||||||
|
public function openDoors(): void {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
public function closeDoors(): void {
|
||||||
|
return;
|
||||||
// This prints "1 4 7 2 5 8 3 6 9"
|
|
||||||
AwaitAllWaitHandle::fromArray([
|
|
||||||
cooperativePrint(1, 3),
|
|
||||||
cooperativePrint(4, 6),
|
|
||||||
cooperativePrint(7, 9)
|
|
||||||
])->getWaitHandle()->join();
|
|
||||||
|
|
||||||
|
|
||||||
// Attributes
|
|
||||||
//
|
|
||||||
// Attributes are a form of metadata for functions. Hack provides some
|
|
||||||
// special built-in attributes that introduce useful behaviour.
|
|
||||||
|
|
||||||
// The __Memoize special attribute causes the result of a function to be cached
|
|
||||||
<<__Memoize>>
|
|
||||||
function doExpensiveTask() : ?string
|
|
||||||
{
|
|
||||||
return file_get_contents('http://example.com');
|
|
||||||
}
|
|
||||||
|
|
||||||
// The function's body is only executed once here:
|
|
||||||
doExpensiveTask();
|
|
||||||
doExpensiveTask();
|
|
||||||
|
|
||||||
|
|
||||||
// The __ConsistentConstruct special attribute signals the Hack type checker to
|
|
||||||
// ensure that the signature of __construct is the same for all subclasses.
|
|
||||||
<<__ConsistentConstruct>>
|
|
||||||
class ConsistentFoo
|
|
||||||
{
|
|
||||||
public function __construct(int $x, float $y)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function someMethod()
|
/* ==================================
|
||||||
{
|
* INTERFACES
|
||||||
// ...
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// A class can implement a set of requirements via an interface.
|
||||||
|
// An interface is a set of method declarations and constants.
|
||||||
|
|
||||||
|
interface Plane {
|
||||||
|
// A constant is a named value. Once defined, the value cannot be changed.
|
||||||
|
const MAX_SPEED = 300;
|
||||||
|
public function fly(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================
|
||||||
|
* TRAITS
|
||||||
|
* ==================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// A trait defines properties and method declarations.
|
||||||
|
// Traits are recommended when abstracting code for reuse.
|
||||||
|
// Traits are included in code via the `use` keyword.
|
||||||
|
|
||||||
|
trait Airplane {
|
||||||
|
// Introduce a class or interface requirement with the following syntax:
|
||||||
|
require extends Machine; // abstract class
|
||||||
|
require implements Plane; // interface
|
||||||
|
|
||||||
|
public function takeOff(): void {
|
||||||
|
$this->openDoors();
|
||||||
|
$this->closeDoors();
|
||||||
|
$this->fly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConsistentBar extends ConsistentFoo
|
class Spaceship extends Machine implements Plane {
|
||||||
{
|
use Airplane;
|
||||||
public function __construct(int $x, float $y)
|
|
||||||
{
|
|
||||||
// Hack's type checker enforces that parent constructors are called
|
|
||||||
parent::__construct($x, $y);
|
|
||||||
|
|
||||||
// ...
|
public function fly(): void {
|
||||||
|
// fly like the wind
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The __Override annotation is an optional signal for the Hack type
|
/* ==================================
|
||||||
// checker to enforce that this method is overriding a method in a parent
|
* KEEP READING!
|
||||||
// or trait. If not, this will error.
|
* ==================================
|
||||||
<<__Override>>
|
*/
|
||||||
public function someMethod()
|
|
||||||
{
|
/* This is a simplified guide!
|
||||||
// ...
|
* There's much more to learn, including:
|
||||||
}
|
* - Asynchronous Operations: https://docs.hhvm.com/hack/asynchronous-operations/introduction
|
||||||
|
* - Reified Generics: https://docs.hhvm.com/hack/reified-generics/reified-generics
|
||||||
|
* - XHP: https://docs.hhvm.com/hack/XHP/setup
|
||||||
|
* - ... and more!
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
class InvalidFooSubclass extends ConsistentFoo
|
|
||||||
{
|
|
||||||
// Not matching the parent constructor will cause a type checker error:
|
|
||||||
//
|
|
||||||
// "This object is of type ConsistentBaz. It is incompatible with this object
|
|
||||||
// of type ConsistentFoo because some of their methods are incompatible"
|
|
||||||
//
|
|
||||||
public function __construct(float $x)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Using the __Override annotation on a non-overridden method will cause a
|
|
||||||
// type checker error:
|
|
||||||
//
|
|
||||||
// "InvalidFooSubclass::otherMethod() is marked as override; no non-private
|
|
||||||
// parent definition found or overridden parent is defined in non-<?hh code"
|
|
||||||
//
|
|
||||||
<<__Override>>
|
|
||||||
public function otherMethod()
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Traits can implement interfaces (standard PHP does not support this)
|
|
||||||
interface KittenInterface
|
|
||||||
{
|
|
||||||
public function play() : void;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait CatTrait implements KittenInterface
|
|
||||||
{
|
|
||||||
public function play() : void
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Samuel
|
|
||||||
{
|
|
||||||
use CatTrait;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$cat = new Samuel();
|
|
||||||
$cat instanceof KittenInterface === true; // True
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## More Information
|
## More Information
|
||||||
|
|
||||||
Visit the [Hack language reference](http://docs.hhvm.com/manual/en/hacklangref.php)
|
Visit the [Hack language reference](http://docs.hhvm.com/hack/) to learn more about the Hack language.
|
||||||
for detailed explanations of the features Hack adds to PHP, or the [official Hack website](http://hacklang.org/)
|
|
||||||
for more general information.
|
|
||||||
|
|
||||||
Visit the [official HHVM website](http://hhvm.com/) for HHVM installation instructions.
|
For more information on HHVM, including installation instructions, visit the [official HHVM website](http://hhvm.com/).
|
||||||
|
|
||||||
Visit [Hack's unsupported PHP features article](http://docs.hhvm.com/manual/en/hack.unsupported.php)
|
|
||||||
for details on the backwards incompatibility between Hack and PHP.
|
|
||||||
|
Reference in New Issue
Block a user