Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
再考:列挙型
2017/08/30
第117回 PHP勉強会@東京
do_aki
@do_aki
@do_aki
http://do-aki.net/
列挙型
http://qiita.com/Hiraku/items/71e385b56dcaa37629fe
// こんなクラスを用意しておけば
final class GameDifficulty extends Enum {
const HARD = 'hard';
const NORMAL = 'normal';
const EASY = 'ea...
改善したい項目
1. IDE 等で補完したい
2. 同じ定数値であっても異なる列挙型なら
ば別物としたい
1.IDE 等で補完したい
• Enum の 生成をする static メソッドは
__callStatic
• __callStatic は静的解析できない
• IDE で `GameDifficulty::NORMAL()`
が補完されない
• 人間の想像力による解決
– `GameDifficulty::NORMAL` が補完される
からいいじゃん -> IDE 問題は未解決
• DocComment による解決
– `@method static GameDifficulty ...
まぁ、それでもいいか
同じ定数値であっても異なる列挙
型ならば別物としたい
• GameDifficulty::HARD と
CheeseType::HARD は区別したい
// 現状の列挙型だと……
final class CheeseType extends E...
• オブジェクトの緩い比較による解決
• 比較メソッドによる解決
$hard = new GameDifficulty(GameDifficulty ::HARD);
var_dump($hard == CheeseType::HARD());...
なんかイマイチ……
と、いろいろ考えてみたので、
せっかくならと
ぼくのかんがえたさいきょうの
列挙型を作ってみた
trait EnumTrait
{
private $value;
private function __construct($value)
{
$ref = new ReflectionObject($this);
$cons = $ref-...
private static $instance;
/**
* @return self
*/
private static function constant()
{
static $name = null;
if ($name === nu...
final class GameDifficulty {
const HARD = 'hard';
const NORMAL = 'normal';
const EASY = 'easy';
use EnumTrait {
constant a...
Point
• trait を利用することで、`self` タイ
プヒンティング(型宣言)が、use され
たクラスを表すことになる (is)
• use … as でメソッドを複数指定するこ
とで、メソッドが複製され、 static 変
数が...
private static $instance; // use したクラスごとに個別に存在
/**
* @return self
*/
private static function constant()
{
static $name = n...
trait EnumTrait
{
private $value;
public function __construct($value)
{
$ref = new ReflectionObject($this);
$cons = $ref->...
PhpStorm のバグ
• https://youtrack.jetbrains.com/iss
ue/WI-34277
• use … as で生成したメソッドから利用
個所を追跡(find usage)できない
• 2013年から存在する...
以上
• 自分なりに考えた より良い列挙型を作って
みた
• 意見もらえると嬉しいです
• (php なんだからもっとゆるふわでいー
じゃんという気もする)
• EnumTrait の完全版は
https://gist.github.com/d...
Upcoming SlideShare
Loading in …5
×

再考:列挙型

2017/08/30 第117回php勉強会

  • Login to see the comments

  • Be the first to like this

再考:列挙型

  1. 1. 再考:列挙型 2017/08/30 第117回 PHP勉強会@東京 do_aki
  2. 2. @do_aki @do_aki http://do-aki.net/
  3. 3. 列挙型
  4. 4. http://qiita.com/Hiraku/items/71e385b56dcaa37629fe
  5. 5. // こんなクラスを用意しておけば final class GameDifficulty extends Enum { const HARD = 'hard'; const NORMAL = 'normal'; const EASY = 'easy'; } // こんな感じにインスタンスの生成ができて $difficulty = GameDifficulty::NORMAL(); // 必要とするところでは、 難易度のいずれかであることが保証される function hoge(GameDifficulty $difficulty) { // 値は value メソッド で取り出せる if ($difficulty->value() === GameDifficulty::NORMAL) { ... } }
  6. 6. 改善したい項目 1. IDE 等で補完したい 2. 同じ定数値であっても異なる列挙型なら ば別物としたい
  7. 7. 1.IDE 等で補完したい • Enum の 生成をする static メソッドは __callStatic • __callStatic は静的解析できない • IDE で `GameDifficulty::NORMAL()` が補完されない
  8. 8. • 人間の想像力による解決 – `GameDifficulty::NORMAL` が補完される からいいじゃん -> IDE 問題は未解決 • DocComment による解決 – `@method static GameDifficulty NORMAL()`
  9. 9. まぁ、それでもいいか
  10. 10. 同じ定数値であっても異なる列挙 型ならば別物としたい • GameDifficulty::HARD と CheeseType::HARD は区別したい // 現状の列挙型だと…… final class CheeseType extends Enum { const HARD = 'hard'; .... } $hard = new GameDifficulty(GameDifficulty ::HARD); var_dump($hard->value() === CheeseType::HARD); // bool(true)
  11. 11. • オブジェクトの緩い比較による解決 • 比較メソッドによる解決 $hard = new GameDifficulty(GameDifficulty ::HARD); var_dump($hard == CheeseType::HARD()); // bool(false) public function is(Enum $lhs) { return get_class($this) === ($lhs) && $this->value() === $lhs->value(); } var_dump($d->is(GameDifficulty::NORMAL()));
  12. 12. なんかイマイチ……
  13. 13. と、いろいろ考えてみたので、 せっかくならと ぼくのかんがえたさいきょうの 列挙型を作ってみた
  14. 14. trait EnumTrait { private $value; private function __construct($value) { $ref = new ReflectionObject($this); $cons = $ref->getConstants(); if (!in_array($value, $cons, true)) { throw new InvalidArgumentException("invalid constant value"); } $this->value = $value; } final public function value() { return $this->value; } final public function is(self $lhs) { return $this === $lhs; }
  15. 15. private static $instance; /** * @return self */ private static function constant() { static $name = null; if ($name === null) { $name = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['function']; } if (!isset(self::$instance[$name])) { $cls = __CLASS__; self::$instance[$name] = new $cls(constant("{$cls}::{$name}")); } return self::$instance[$name]; } }
  16. 16. final class GameDifficulty { const HARD = 'hard'; const NORMAL = 'normal'; const EASY = 'easy'; use EnumTrait { constant as public HARD; constant as public NORMAL; constant as public EASY; } } // ↓ DocComment なしに補完できる! $difficulty = GameDifficulty::NORMAL(); var_dump($difficulty->is(GameDifficulty::NORMAL())); // bool(true) var_dump($difficulty->is(CheeseType::HARD())); // Type Error // ↑ PhpStorm ならば警告表示される!
  17. 17. Point • trait を利用することで、`self` タイ プヒンティング(型宣言)が、use され たクラスを表すことになる (is) • use … as でメソッドを複数指定するこ とで、メソッドが複製され、 static 変 数がメソッド分用意される (constant) • Singleton にすることで、オブジェクト 自身の比較が定数値の比較と同じことに なる
  18. 18. private static $instance; // use したクラスごとに個別に存在 /** * @return self */ private static function constant() { static $name = null; // use … as したメソッドごとに個別に存在 if ($name === null) { $name = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0][‘function’]; } if (!isset(self::$instance[$name])) { $cls = __CLASS__; // これは use した クラス名に置き換わる self::$instance[$name] = new $cls(constant("{$cls}::{$name}")); } return self::$instance[$name]; } }
  19. 19. trait EnumTrait { private $value; public function __construct($value) { $ref = new ReflectionObject($this); $cons = $ref->getConstants(); if (!in_array($value, $cons, true)) { throw new InvalidArgumentException(“invalid constant value”); } $this->value = $value; } final public function value() { return $this->value; } final public function is(self $lhs) // この self は use したクラスを表す { return $this === $lhs; }
  20. 20. PhpStorm のバグ • https://youtrack.jetbrains.com/iss ue/WI-34277 • use … as で生成したメソッドから利用 個所を追跡(find usage)できない • 2013年から存在するバグ(解消されず) • 仕方ないので、 @method も併用してる
  21. 21. 以上 • 自分なりに考えた より良い列挙型を作って みた • 意見もらえると嬉しいです • (php なんだからもっとゆるふわでいー じゃんという気もする) • EnumTrait の完全版は https://gist.github.com/do-aki/61fe688b512bf9255a67da390d9b2030

×