W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
想象一下,你有一個非泛型的類,并有一些不同的extends類。
<?hh
namespace Hack\UserDocumentation\TypeConstants\Intro\Examples\NonParameterized;
abstract class User {
public function __construct(private int $id) {}
public function getID(): int {
return $this->id;
}
}
trait UserTrait {
require extends User;
}
interface IUser {
require extends User;
}
class AppUser extends User implements IUser {
use UserTrait;
}
function run(): void {
$au = new AppUser(-1);
var_dump($au->getID());
}
run();
Output
int(-1)
現(xiàn)在想象一下,你意識到,有時用戶的ID可能是一個string以及一個int。但是你知道具體的類User將確切地知道將返回什么類型。
泛型引入了類型參數(shù)的概念,它基本上允許您將類型占位符關(guān)聯(lián)到一個類或方法,然后在類實例化或方法被調(diào)用后,該類就可以完全關(guān)聯(lián)。
<?hh
namespace Hack\UserDocumentation\TypeConstants\Intro\Examples\Generics;
abstract class User<T as arraykey> {
public function __construct(private T $id) {}
public function getID(): T {
return $this->id;
}
}
trait UserTrait<T as arraykey> {
require extends User<T>;
}
interface IUser<T as arraykey> {
require extends User<T>;
}
// We know that AppUser will only have int ids
class AppUser extends User<int> implements IUser<int> {
use UserTrait<int>;
}
class WebUser extends User<string> implements IUser<string> {
use UserTrait<string>;
}
class OtherUser extends User<arraykey> implements IUser<arraykey> {
use UserTrait<arraykey>;
}
function run(): void {
$au = new AppUser(-1);
var_dump($au->getID());
$wu = new WebUser('-1');
var_dump($wu->getID());
$ou1 = new OtherUser(-1);
var_dump($ou1->getID());
$ou2 = new OtherUser('-1');
var_dump($ou2->getID());
}
run();
Output
int(-1)
string(2) "-1"
int(-1)
string(2) "-1"
請注意,我們必須傳播一個類型參數(shù)的附加到類本身和所有擴展它?,F(xiàn)在想想,如果我們有成百上千個使用特征和接口的地方,我們也必須更新它們。
在類型參數(shù)化方面,Hack引入了泛型稱為類型常量的替代特性。類型常量允許將類型聲明為類成員常量,而不是直接在類本身聲明的類型。
<?hh
namespace Hack\UserDocumentation\TypeConstants\Intro\Examples\TypeConstants;
abstract class User {
abstract const type T as arraykey;
public function __construct(private this::T $id) {}
public function getID(): this::T {
return $this->id;
}
}
trait UserTrait {
require extends User;
}
interface IUser {
require extends User;
}
// We know that AppUser will only have int ids
class AppUser extends User implements IUser {
const type T = int;
use UserTrait;
}
class WebUser extends User implements IUser {
const type T = string;
use UserTrait;
}
class OtherUser extends User implements IUser {
const type T = arraykey;
use UserTrait;
}
function run(): void {
$au = new AppUser(-1);
var_dump($au->getID());
$wu = new WebUser('-1');
var_dump($wu->getID());
$ou1 = new OtherUser(-1);
var_dump($ou1->getID());
$ou2 = new OtherUser('-1');
var_dump($ou2->getID());
}
run();
Output
int(-1)
string(2) "-1"
int(-1)
string(2) "-1"
注意語法abstract const type <name> [ as <constraint> ];。所有類型的常量是,const并使用關(guān)鍵字type。您可以為常量指定一個名稱,以及必須遵守的任何可能的約束條件。有關(guān)語法的信息,請參閱下文。
還要注意,只有類本身和直接的孩子需要更新新的類型信息。
類型常量有點類似于抽象方法,其中基類定義了方法簽名而沒有實體,而子類提供了實際的實現(xiàn)。
類型常量的語法取決于您是處于抽象類還是具體類。
在抽象類中,語法是最簡單的:
abstract const type <name> [as <constraint>]; // constraint optional
例如:
abstract class A {
abstract const type Foo;
abstract const type Bar as arraykey;
}
那么在這個具體的子類中:
class C extends A {
const type Foo = string;
// Has to be int or string since was constrained to arraykey
const type Bar = int;
}
你可以在具體類中聲明一個類型常量,但是它需要不同的語法:
const type <name> [as <constraint>] = <type>; // constraint optional
例如:
class NoChild {
const type Foo = ?string;
}
class Parent {
const type Foo as arraykey = arraykey; // need constraint for child override
}
class Child extends Parent {
const type Foo = string; // a string is an arraykey, so ok
}
假設(shè)類型常量是類的一個常數(shù),那么可以使用它來引用它this。作為一個類型注釋,你注釋一個類型常量,如:
this::<name>
例如,
this::T
你可以this::用類似的方式來考慮this返回類型。
這個例子顯示了類型常量的真正好處。該屬性被定義Base,但可以有不同的類型,取決于它在哪里使用的上下文。
<?hh
namespace Hack\UserDocumentation\TypeConstants\Introduction\Examples\Annotate;
abstract class Base {
abstract const type T;
protected this::T $value;
}
class Stringy extends Base {
const type T = string;
public function __construct() {
// inherits $value in Base which is now setting T as a string
$this->value = "Hi";
}
public function getString(): string {
return $this->value; // property of type string
}
}
class Inty extends Base {
const type T = int;
public function __construct() {
// inherits $value in Base which is now setting T as an int
$this->value = 4;
}
public function getInt(): int {
return $this->value; // property of type int
}
}
function run(): void {
$s = new Stringy();
$i = new Inty();
var_dump($s->getString());
var_dump($i->getInt());
}
run();
Output
string(2) "Hi"
int(4)
還有一些關(guān)于類型常量的其他規(guī)則:
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: