2020-12-02: PHP8でFizzBuzzを書いた
初版公開日: 2020年12月2日
FizzBuzzはいろいろ書いてきた
まず、;を含まないFizzBuzz自体は全然難しくない
code:php
<?=implode("\n",array_map(fn($n)=>$n,'Buzz'],['Fizz','FizzBuzz'!($n%3)!($n%5),range(1,100)))?> とかね。
code:php
これはずるい
まあそれはそれとして、例の記事のように?>を書けば邪道ではあるもののクラスの構文を活用できるのも事実
メソッドなどの実装はだいたい式を要求するからな
そんなわけで開き直って書いた
code:php
<?php
final class Handler{
function __construct(private $n, private $s, private $succ){}
function isMatched(int $n):bool{return$n%$this->n===0?><?php }
function __invoke(int $n){return $this->isMatched($n) ? $this : ($this->succ)($n)?><?php }
function __toString(){ return $this->s?><?php }}
foreach(new class(
new Handler(15, \FizzBuzz::class,
new Handler(3, \Fizz::class,
new Handler(5, \Buzz::class,
fn($n) => (string)$n,
))), range(1, 100)) implements IteratorAggregate{
function __construct(private $handler, private $input){}
function getIterator(): Generator {
return (function() {
foreach($this->input as $n)
yield ($this->handler)($n) ?><?php })()?><?php
}
} as $fizzbuzz) echo $fizzbuzz,PHP_EOL?>
Handlerクラスをベースにするところは元記事の受け売り
ところで最初のバージョンはこんな感じだった
code:php
<?php foreach(new class(
new Handler(15, \FizzBuzz::class,
new Handler(3, \Fizz::class,
new Handler(5, \Buzz::class,
fn($n) => (string)$n,
))), range(1, 100)) implements IteratorAggregate{
function __construct(private $handler, private $input){}
function getIterator(): Generator {
return (function() {
foreach($this->input as $n)
yield ($this->handler)($n) ?><?php })()?><?php
}
} as $fizzbuzz) echo $fizzbuzz,PHP_EOL?><?php final class Handler{
function __construct(private $n, private $s, private $succ){}
function isMatched(int $n):bool{return$n%$this->n===0?><?php}
function __invoke(int $n){return $this->isMatched($n) ? $this : ($this->succ)($n)?><?php }
function __toString(){ return $this->s?><?php }}
https://gyazo.com/b3d7762227287e0996b069335048f80a
えっ、Handlerクラスが未定義…?
その次に直したバージョン
code:php
<?php
final class Handler{
function __construct(private $n, private $s, private $succ){}
function isMatched(int $n):bool{return$n%$this->n===0?><?php}
function __invoke(int $n){return $this->isMatched($n) ? $this : ($this->succ)($n)?><?php }
function __toString(){ return $this->s?><?php }}
foreach(new class(
new Handler(15, \FizzBuzz::class,
new Handler(3, \Fizz::class,
new Handler(5, \Buzz::class,
fn($n) => (string)$n,
))), range(1, 100)) implements IteratorAggregate{
function __construct(private $handler, private $input){}
function getIterator(): Generator {
return (function() {
foreach($this->input as $n)
yield ($this->handler)($n) ?><?php })()?><?php
}
} as $fizzbuzz) echo $fizzbuzz,PHP_EOL?>
https://gyazo.com/6e8e01600a6453bd7d89a5c80784d58a
えっ、Handlerがcallableじゃない? __invoke()マジックメソッドあるのに?
僕にはPHP8の処理系の気持ちがわからなくなってしまった…
冬休みの宿題に処理系を読み解いてこの不可解な挙動の原因を探ってみるのもいいかもしれませんね
最近あまり寝れてないので、悪い夢を見たと思って僕は寝ます。