んだ日記

ndaDayoの技術日記です

PHPで『Java言語で学ぶリファクタリング入門』を書いてみる(1) シンボリック定数によるマジックナンバーの置き換え

今回は、こちらの『Java言語で学ぶリファクタリング入門』をPHPで書いていきます。

Java言語で学ぶリファクタリング入門

Java言語で学ぶリファクタリング入門

第一回は

『シンボリック定数によるマジックナンバーの置き換え』

です。

マジックナンバーを書いてはいけない理由

マジックナンバーとは?

プログラム中に直接埋め込まれた数値。 

例)

if(input.length() < 100){
  ..
}

書いた人にしかわからない、書いた人も忘れてしまう謎数字。

それがマジックナンバー

マジックナンバーを書いてはいけない理由

①意味がわかりにくい

その数字が何を意味しているのかわからないので解読に手間がかかる。。

②修正しにくい

たとえば、100文字が200文字になったら....

if(input.length() < 100){
  ..
}

100は、他にも使われているかもしれないから一発置換できない。。

リファクタリング

サンプルは、コマンドを与えてRobotを動かすというプログラム

・コマンドが0なら、歩く
・コマンドが1なら、止まる
・コマンドが2なら、ジャンプ

コマンドがマジックナンバーで書かれているコードがこちら。

<?php

namespace App;

class Robot
{
    /** @var string */
    public $name;

    /**
     * Robot constructor.
     *
     * @param $name
     */
    public function __construct(String $name)
    {
        $this->name = $name;
    }

    /**
     *
     * @return string
     * @param $command
     */
    public function order(int $command)
    {
        if ($command === 0) {
            return $this->name . 'が歩く' . "\n";
        } elseif ($command === 1) {
            return $this->name . 'は止まる' . "\n";
        } elseif ($command === 2 {
            return $this->name . 'がジャンプする' . "\n";
        } else {
            return $command . 'のコマンドはないですよ' . "\n";
        }
    }
}

使ってみる

<?php
// index.php

use App\Robot;

$robot = new Robot('パンティーロボ');

echo $robot->order(0); // 歩く
echo $robot->order(1); // 止まる
echo $robot->order(2); // ジャンプ


// 実行結果
パンティーロボが歩く
パンティーロボは止まる
パンティーロボがジャンプする

$robot->order(0);

は意味がわからないので、コメントで説明しています。

リファクタリング

シンボリック定数によるマジックナンバーの置き換え

<?php

namespace App;

class Robot
{
    const COMMAND_WALK = 0;
    const COMMAND_STOP = 1;
    const COMMAND_JUMP = 2;

 ~省略~
    /**
     *
     * @return string
     * @param $command
     */
    public function order(int $command)
    {
        if ($command === Robot::COMMAND_WALK) {
            return $this->name . 'が歩く' . "\n";
        } elseif ($command === Robot::COMMAND_STOP) {
            return $this->name . 'は止まる' . "\n";
        } elseif ($command === Robot::COMMAND_JUMP) {
            return $this->name . 'がジャンプする' . "\n";
        } else {
            return $command . 'のコマンドはないですよ' . "\n";
        }
    }
}
<?php
use App\Robot;

$robot = new Robot('パンティーロボ');

echo $robot->order(Robot::COMMAND_WALK);
echo $robot->order(Robot::COMMAND_STOP);
echo $robot->order(Robot::COMMAND_JUMP);

テスト

テストも書いてみました。

<?php

namespace Tests;

use App\Robot;
use PHPUnit_Framework_TestCase;

class RobotTest extends PHPUnit_Framework_TestCase
{
    const Exception = 3;
    /**
     * @var Robot
     */
    protected $robot;

    protected function setUp()
    {
        $this->robot = new Robot("テストロボット");
    }

    /**
     * @test
     *
     */
    public function testOrder()
    {
        $expected_walk = 'テストロボットが歩く' . "\n";
        $expected_stop = 'テストロボットは止まる'. "\n";
        $expected_jump = 'テストロボットがジャンプする'. "\n";
        $expected_exception = RobotTest::Exception . 'のコマンドはないですよ' . "\n";

        $this->assertEquals($expected_walk, $this->robot->order(Robot::COMMAND_WALK));
        $this->assertEquals($expected_stop, $this->robot->order(Robot::COMMAND_STOP));
        $this->assertEquals($expected_jump, $this->robot->order(Robot::COMMAND_JUMP));

        $this->assertEquals($expected_exception, $this->robot->order(RobotTest::Exception));
    }
}
vendor/bin/phpunit tests/
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 448 ms, Memory: 4.00MB

OK (1 test, 4 assertions)

以上。