hero_picture
Cover Image for 分岐処理をオブジェクトで表現してみる

分岐処理をオブジェクトで表現してみる

2014/10/10

みなさんどうも、WEBエンジニアの kinu です。

好奇心で Smalltalk を参考に普段使っている PHP で分岐処理を if 文を使わずにオブジェクト指向で実装してみました。

目標

下にあげたような単純な分岐を処理できるようにする。

[code]

$value = 1;

if ($value == 1) {

echo ‘True’;

} else {

echo ‘False’;

}

[/code]

実装内容

処理の内容はシンプルで Logical にセットした値によって Bool の具象クラスが生成され、それがifTrue と ifFalse に渡されたクロージャを実行するかを決定するようになってます。

以下ソースコードです。

Bool.php

[code]

interface Bool

{

public function ifTrue($closure);

1    public function ifFalse($closure);
2

}

[/code]

True.php

[code]

namespace Bool;

class True

{

public function ifTrue($closure)

{

$closure();

}

1    public function ifFalse($closure){}
2

}

[/code]

False.php

[code]

namespace Bool;

class False

{

public function ifTrue($closure){}

1    public function ifFalse($closure)
2{
3return $closure();
4}
5

}

[/code]

Logical.php

[code]

class Logical

{

private $value;

1    public function __construct($logic)
2{
3$this->value (bool)$logic;
4}
5public static function set($logic)
6{
7return new self($logic);
8}
9public function asBoolean()
10{
11return $this->value ? new \Bool\True : new \Bool\False;
12}
13public function ifTrue($closure)
14{
15$this->asBoolean()->ifTrue($closure);
16return $this;
17}
18public function ifFalse($closure)
19{
20$this->asBoolean()->ifFalse($closure);
21return $this;
22}
23

}

[/code]

使用例

[code]

$value = 1;

Logical::set($value == 1)

  • >ifTrue(function () {

echo ‘True’;

})

  • >ifFalse(function () {

echo ‘False’;

});

[/code]

ちなみに Smalltalk だと

[code]

| aValue |

aValue := 1.

aValue = 1

ifTrue: [Transcript show: ‘True’]

ifFalse: [Transcript show: ‘False’]

[/code]

やっぱり比較するとクロージャfunction ()...のくだりが長い…。

しかも、外のスコープの変数を使おうとすると、

[code]

$value = 1;

Logical::set($value == 1)

  • >ifTrue(function () use ($value) {

echo $value.’ は 1 だよ。’;

})

  • >ifFalse(function () use ($value) {

echo $value.’ は 1 じゃないよ。’;

});

[/code]

さらにネストでもしようものなら、

[code]

$value = 1;

Logical::set(isset($value))

  • >ifTrue(function () use ($value) {

Logical::set($value == 1)

  • >ifTrue(function () use ($value) {

echo $value.’ は 1 だよ。’;

})

  • >ifFalse(function () use ($value) {

echo $value.’ は 1 じゃないよ。’;

});

});

[/code]

…実用的ではないですね。

まとめ

参考に Smalltalk の実装を見ていたときにポリモーフィズムなんかのオブジェクト指向の基礎を学べました。なにより Smalltalk 環境の使い方も少しだけ理解できたのでよかったです。まあ、もともとそのつもりでやってみたというのもありますが。

出来上がったものに関しては… PHP は if文がありますしね…。

でもクロージャの use がいらなくなったりしたら使ってみてもいいかな。あとはPHPで論理値がオブジェクトになっていることによるメリットなんか見つけていきたいです。