PHPにも欲しいEnums
PHPにも欲しい!ということで近しい感覚で利用できる様なライブラリを使ったり、
作ったり、定数で頑張ったり・・・。
そんなEnumsがHackで利用できるのは多くのPHPerの方がご存知だと思います。
C#、C++、Javaといった言語で実装経験のある方は
おなじみですので、Hackですぐにそのまんまで使える様になります。
PHPでEnumsといえば、
myclabs/php-enum などを利用することが多いのではないでしょうか。
今回はEnumsについて早速みていきましょう。
Hack Enums
まずはじめに!
HackのEnumsは intとstringのみ 利用できるということをしっかりと覚えておきましょう。
それさえ忘れずにいればあとは利用していくだけです。
書き方
書き方は簡単です。
<?hh
namespace Acme\Enums;
enum Size: int {
SMALL = 0;
MEDIUM = 1;
LARGE = 2;
X_LARGE = 3;
}
enumsはclassではないため、PSR-4などにしたがってディレクトリはそどうしたら、
と思う方もいるかもしれません。
Hackでユニットテスト はじめてのHackTest#hh_autoload.json
でも触れた様にhhvm-autoload を利用するため
心配は無用です。
1ファイルに複数のEnumsやtype aliasなどを書き込んでいきましょう。
php環境でcomposerを動かすと、PHPにはない構文と機能となりますので、
忘れず hhvm でcomposerを動かすように・・。
これまでに紹介した様に、Hackではcomposer.jsonにあまり記述しませんが、
下記の通り登録されます。
PSR-4指定をcomposerやhh-autoloadに記述する必要はありません、
function map(): \Facebook\AutoloadMap\AutoloadMap {
/* HH_IGNORE_ERROR[4110] invalid return type */
return darray[
'class' =>
darray[
// 省略
'acme\\enums\\size' => 'src/types.php',
]
// 省略
これで型が保証される値を利用できる様になりました。
Enums自体は継承ができませんので、よく考えて利用しましょう。
値取得方法
Enumsの値を利用する場合は、定数利用と同じです。
<?hh
namespace Acme\Enums;
enum Language: string {
PHP = 'PHP';
HACK = 'Hack';
}
<?hh
require_once __DIR__ . '/../vendor/hh_autoload.php';
use type Acme\Enums\Language;
var_dump(Language::PHP, Language::HACK);
Enumsにはデフォルト値はありません。
Enumsのキャスト
Enumsの例としてAcme\Enums\Language を利用する例です。
<?hh // strict
namespace Acme;
use type Acme\Enums\Language;
final class Display {
public function render(string $l): string {
return $l;
}
public function renderEnum(Language $l): string {
return (string) $l;
}
}
このクラスのメソッドにEnumsを使う場合は次の通りです。
$d = new \Acme\Display();
\var_dump(
$d->render((string) Language::HACK),
$d->renderEnum(Language::HACK)
);
実はEnumsで記述した型は、通常のクラスで利用する型と互換性がないようです。
このためそれぞれキャストして値を扱う様になっています。
Enumsの型に暗黙の型変換を適用したい場合は、下記の様に記述する必要があります。
enum Language: string as string {
PHP = 'PHP';
HACK = 'Hack';
}
これで文字列型として扱うことができる様になりました。
利用するクラスも次の様に変更できます。
<?hh // strict
namespace Acme;
use type Acme\Enums\Language;
final class Display {
public function render(string $l): string {
return $l;
}
public function renderEnum(Language $l): string {
return $l;
}
}
暗黙の型変換が作用しますので、クラスに記述していたキャストがなくなりました。
Enums Functions
Enumsは当然これだけではありません。
いくつかのメソッドが用意されていますので、少しだけ紹介します。
assert()
文字列やintを渡してEnumsで定義されたものかどうかを確認したい場合に利用します。
Enumsで記述していない値を渡す場合は次の通りです。
public function put(): void {
$o = new \Acme\Display();
\var_dump(
Language::assert('Scala')
);
}
エラーにもしっかりと表示されて、例外が発生します。
存在する値の場合は、そのまま値を返却します。
Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Scala is not a valid value for Acme\Enums\Language' in Path/To/*.php
coerce()
assertと基本的には同じですが、こちらは例外ではなくnullを返却します。
public function put(): void {
$o = new \Acme\Display();
\var_dump(
Language::coerce('Scala') // null返却
);
}
getNames()、getValues()
Enumsで記述した名前、もしくは値を取得します。
それぞれarrayで返却されますので、必要に応じてdictやMapに変換をするなどしましょう。
public function put(): void {
$o = new \Acme\Display();
\var_dump(
dict(Language::getNames()),
dict(Language::getValues())
);
}
isValid()
与えられた値がEnumsで利用できるかどうかを調べます。
public function put(): void {
$o = new \Acme\Display();
\var_dump(
Language::isValid('PHP'),
Language::isValid('Scala')
);
}
それぞれbooleanで返却されます。
今回はEnumsについて簡単に紹介しました。
どれも利用方法は非常に簡単ですので、利用したい場面で使ってみましょう。