1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Hack and HHVMAdvent Calendar 2018

Day 14

HackでEnumsを使いこなそう!

Posted at

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について簡単に紹介しました。
どれも利用方法は非常に簡単ですので、利用したい場面で使ってみましょう。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?