ジェネレーターを返す一連のクラス (php 5.5) を中心に小さなプロジェクトを作成することに着手しました。
この小さなプロジェクトの主な動機は、TDD の旅を拡張し、ジェネレーターをいじり、後で使用するために packagist に投げることができるパッケージを用意することでした。
「プロジェクト」全体の現状はGithubで確認できます
すべてのテストは緑色で、メソッドは私が望むことを行います。重複が多いので、リファクタリングしたいと思います。
/**
* Returns a Generator with a even range.
*
* getEven(10); // 10,12,14,16,18,20,22 ...
* getEven(null, 10); // 10,8,6,4,2,0,-2,-4 ...
* getEven(10, null, 2); // 10,6,2, -2 ...
* getEven(10,20); // 10,12,14,16,18,20
* getEven(20,10); // 20,18,16,14,12,10
* getEven(10,20,2); // 10,14,18
*
* @param int|null $start
* @param int|null $end
* @param int $step
* @throws InvalidArgumentException|LogicException
* @return Generator
*/
public function getEven( $start = null, $end = null, $step = 1 )
{
// Throws LogicException
$this->throwExceptionIfAllNulls( [$start, $end] );
$this->throwExceptionIfInvalidStep($step);
// Throws InvalidArgumentException
$this->throwExceptionIfNotNullOrInt( [$start, $end] );
// infinite increase range
if(is_int($start) && is_null($end))
{
// throw LogicException
$this->throwExceptionIfOdd($start);
$Generator = function() use ($start, $step)
{
for($i = $start; true; $i += $step * 2)
{
yield $i;
}
};
}
// infinite decrease range
elseif(is_int($end) && is_null($start))
{
// throws LogicException
$this->throwExceptionIfUneven($end);
$Generator = function() use ($end, $step)
{
for($i = $end; true; $i -= $step * 2)
{
yield $i;
}
};
}
// predetermined range
else
{
// throws LogicException
$this->throwExceptionIfUneven($start);
$this->throwExceptionIfUneven($end);
// decrease
if($start >= $end)
{
$Generator = function() use ($start, $end, $step)
{
for($i = $start; $i >= $end; $i -= $step * 2)
{
yield $i;
}
};
}
// increase
else
{
$Generator = function() use ($start, $end, $step)
{
for($i = $start; $i <= $end; $i += $step * 2)
{
yield $i;
}
};
}
}
return $Generator();
}
このクラスには getOdd という名前のメソッドもあります (そして、そうです ;) )
主な重複はクロージャー$Generator = function() ...
であり、違いは主+ - * /
に for ループ内の and 引数などの演算子です。これは、クラスの残りの部分でも主に同じです。
PHP で動的比較演算子を読んだところ、次のようなネイティブ メソッドは存在しないという結論に達しました。compare(...)
比較のためにプライベート/保護されたメソッドを作成する必要があります。もしそうなら、私はこれのために新しいクラス/関数を作るべきですか? 私はそれが現在のクラスに属しているとは思わない。
これを適切な方法で乾燥させる方法がわかりません。
ところで。getEven を知っていますが、getRange With step 関数を取得したときの getOdd はちょっとばかげていますが、それはより一般的なリファクタリング/パターンの質問です。
@github を更新 して getEven と getOdd を削除しました...