PHPとしても実行できるRubyの書きかた

  • 233
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

まずはこちらのFizzBuzzをご覧ください。

php.rb
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メソッドに渡しています。

次に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";

良い。


  1. ない