はじめに
まずはこちらのFizzBuzzをご覧ください。
p <<PHP_VERSION
<?php
PHP_VERSION
;print "\033[1F\033[1M";
//.tap{ define_method :range, -> s,e { s.upto e } }
//.tap{ define_method :array_map, -> f,seq { seq.map{ |x| f.(x) } } }
//.tap{ define_method :function, -> x,&b { -> x { $x=x;b.call } } }
array_map(function($x){
print $x % 15 == 0 ? 'FizzBuzz' : ($x % 3 == 0 ? 'Fizz' : ($x % 5 == 0 ? 'Buzz' : $x));
print "\n";
}, range(1,100));
ruby php.rb
もしくはphp php.rb
で動作します。
「PHPとしてもRubyとしても実行できるアプリケーションを作ってください!」という案件が入ってくることはよくあります1ので、この様にPHPとしてもvalidなRubyの書き方を身につける事でそういった案件にも対応していけるようになりましょう。
<?php
をどうするか
phpでは、コードを書く前にまず<?php
という何かを書かなくてはいけません。ですがrubyにおいて<?php
という記述はシンタックスエラーになります。
そこで、まずはrubyとしてvalidな形式で<?php
を記述する方法が必要となります。
p <<PHP_VERSION
<?php
PHP_VERSION
;print "\033[1F\033[1M";
まず、rubyとしてこのコードを解釈すると、ヒアドキュメントにて<?php
という文字列を標準出力に書きだした後、「一行前に戻り、行全体を削除する」という内容のansicodeをprintメソッドに渡しています。
p <<PHP_VERSION
<?php
PHP_VERSION
;print "\033[1F\033[1M";
次にphpとしてこのコードを解釈してみます。まず1行目については通常のテキストとして標準出力に書きだされます。2行目はそのまま、<?php
なのでphpの処理開始を意味します。3行目はPHP_VERSION
という定数を評価する(単に評価して捨てるだけ)処理、4行目はrubyの時と同じく「一行前に戻り、行全体を削除する」という内容のansicodeをprintメソッドに渡し、1行目で出力された「p <<PHP_VERSION」という文字列を削除しています。
ポイントは、4行目最初の;
です。PHPでは文と文の間に;
を書く必要がありますが、必ずしも行末に書く必要はありません。そして、rubyのヒアドキュメントは、識別子の後に;
を書くとシンタックスエラーになってしまいます。この2言語間の差異を吸収するために、;
を4行目の最初に置いています。
標準出力の方法
print "\033[1F\033[1M";
print
を使いましょう。
コメントアウトの利用
//.tap{ define_method :range, -> s,e { s.upto e } }
//.tap{ define_method :array_map, -> f,seq { seq.map{ |x| f.(x) } } }
//.tap{ define_method :function, -> x,&b { -> x { $x=x;b.call } } }
phpにおいて、行内の//
以降はコメントとして解釈されます。一方rubyでは//
は単に正規表現リテラルです。これを利用することでrubyでのみ実行される処理を記述することができます。
上記コードは
//.tap{ ... }
でなく
//; ...
と書くこともできます。
変数の利用
array_map(function($x){
print $x % 15 == 0 ? 'FizzBuzz' : ($x % 3 == 0 ? 'Fizz' : ($x % 5 == 0 ? 'Buzz' : $x));
print "\n";
}, range(1,100));
phpにおいて変数名には$
プレフィクスが必要です。rubyにおいて$
プレフィクス付きの変数はグローバル変数として扱われます。つまり、基本的にphpとしても実行可能なrubyのコードを書く際、変数は全てグローバル変数を使用します。グローバル変数の名前領域がガンガン汚染されていきますので本当に最高ですね。破綻しないように気合いでなんとかしてください。
まとめ
PHPもRubyもだいすき!
2015/1/29追記
コメントを頂きました。
p <<'PHP_VERSION;'
なるほど、この様にすることで;
を含めて識別子として認識させることができますね。
p <<'PHP_VERSION;'
<?php
PHP_VERSION;
print "\033[1F\033[1M";
良い。
-
ない ↩