Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

まずはこちらの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を記述する方法が必要となります。

Ruby
p <<PHP_VERSION
<?php
PHP_VERSION
;print "\033[1F\033[1M";

まず、rubyとしてこのコードを解釈すると、ヒアドキュメントにて<?phpという文字列を標準出力に書きだした後、「一行前に戻り、行全体を削除する」という内容のansicodeをprintメソッドに渡しています。

PHP
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";

良い。


  1. ない 

supermomonga
ヾ(  l   _   l  〃)ノ゙ドン☆
https://darui.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした