「間違った使い方ができない」ようなコードを書くためにはEnumが有用です。
元ネタ
防御的プログラミング
コードを書く人間であれば誰しも,『良いコードとは何か』という問いに直面した経験があるかと思います。
これを一概に言い切ることは難しいですが,個人的にわかりやすい指標として「間違った使い方をする方が難しい」というのが挙げられると考えています。
コード例
元ネタ:https://twitter.com/yoookd/status/933711986071953409
具体的に、以下のコードを例にします。
<?php
class Something {
public function praise($country)
{
if($status === '1'){
return 'Awesome';
}else if ($status === '2'){
return 'Excellent';
}
}else if ($status === '3'){
return "...actually it's not bad";
}
throw new Exception('not defined country');
}
}
引数にcountry
を受取り,これが1の時はアメリカ人なのでAwesome,これが2の時はオーストラリア人なのでExcellent,これが3の時は英国人なので...actually it's not badと返します。
国籍設定に他意はありません。
この関数の「正しい」使い方を知るためには,関数の処理内容を見て「あ、1か2か3のどれかを渡すんだな」と理解する必要があります。あるいはコメントでそれを説明する方式もあります。いずれにせよ,関数の処理を文書かソースから理解し,関数を呼び出す側で1〜3以外の値が渡されないように工夫する必要があります。
Enumを使ったコード例
引用:https://qiita.com/Hiraku/items/71e385b56dcaa37629fe
<?php
abstract class Enum
{
private $scalar;
public function __construct($value)
{
$ref = new ReflectionObject($this);
$consts = $ref->getConstants();
if (! in_array($value, $consts, true)) {
throw new InvalidArgumentException;
}
$this->scalar = $value;
}
final public static function __callStatic($label, $args)
{
$class = get_called_class();
$const = constant("$class::$label");
return new $class($const);
}
//元の値を取り出すメソッド。
//メソッド名は好みのものに変更どうぞ
final public function valueOf()
{
return $this->scalar;
}
final public function __toString()
{
return (string)$this->scalar;
}
}
final class Country extends Enum
{
const USA = '1';
const AUSTRALIA = '2';
const BRITISH = '3';
}
class Something {
public function praise(Country $country)
{
switch($country->value()){
case Country::USA:
return 'Awesome';
case Country::AUSTRALIA:
return 'Excellent';
case Country::BRITISH:
return "...actually it's not bad";
}
}
}
この書き方だと,例えばpraise
関数に対して4
という値を与えるとInvalidArgumentExceptionが発生します。先のコード例でも4
という値を渡すと正しく動かないという点では共通していますが,InvalidArgumentExceptionというメッセージが出されることで,「あ、値の渡し方が間違えているんだな」と利用者に対して理解してもらうことができます。