1. Qiita
  2. 投稿
  3. Ruby

PHPerがRubyを勉強するのに役に立つTips

  • 12
    いいね
  • 6
    コメント

RubyAdventCalendar2016 12/15の記事です。

最初に

PHPを今まで長い間書いてきて、そろそろRubyを勉強しようと思っている人向けです。
PHPではこうだけどRubyの場合はこう。という流れで基本的には進めていきます。
私自身も勉強を始めてまだ日が浅いので、ツッコミあったらどんどんください。

本記事はRubyを網羅する事を目的にはしていません。

versionについて

実行しているバージョンは以下の通りです。

☁  ~  php -v
PHP 7.1.0 (cli) (built: Dec 14 2016 00:12:28) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies
☁  ~  ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
☁  ~

IDEについて

IDEよりエディタ派だ!男は黙ってVim!という方は読み飛ばしてください。

お勧めIDE
Rubymine

PHPの場合はPhpStormが有名ですが、Rubyの場合はRubyMineを強くお勧めします。
※私はPhpStormを愛しています。

PhpStormと同じJetBrains製なので、もしPhpStormを普段よく使っているなら学習コストほぼ0でRubyMineも利用できます。
シンタックスもサジェストしてくれたり、コード補完もすごく優秀なのでRubyの学習効率もかなり上がります。
ただし、一点注意があります。PhpStormでは、基本全ての変数や関数が補完できます(PHPDocちゃんと書いていれば)。これがPhpStormが手放せない理由の一つです。これはPHPが静的解析に向いているからです。Rubyの場合は、動的な関数の定義が可能なのでそこまで解析する事は難しいと想像します。なのでRubyの場合は補完できないケースがままあります。例えばgemでとってきたライブラリの一部など。それでも私はRubyMineを推します。ちなみにRailsの場合はバンドルされている超優秀なプラグインがあるので、めちゃくちゃ快適です。
30日無料トライアル可能なのでまずはRubyMineを触ってみてください。きっと虜になるはずです。

RubyMineの魅力を存分に語ってくれている記事を貼っておきます。
メインの開発ツールをVimからRubyMineに変更した理由

nullについて

PHPではnullですが、Rubyではnilです。

Rubyは全てがオブジェクト

Rubyは全てがオブジェクトです。ここがPHPと大きく違うところですね。
全てがオブジェクトだからこそエレガントに書くことが出来ます。

文字列もオブジェクトです。

string.rb
p 'abc'.length
# 結果
3

そう、nilもね。

nil.rb
p nil.nil?
# 結果
true

関数について

method.php
<?php

function calc($a, $b)
{
    echo $a + $b . PHP_EOL;
}

calc(1, 2);
# 結果
3
method.rb
# 関数の定義
def calc(a, b)
  p a+b
end

calc(1, 2)
# 関数呼び出し時の括弧は省略可能
calc 1, 2

# 結果
3
3

返り値

return.php
<?php

function calc($a, $b)
{
    return $a + $b;
}

$total = calc(1, 2);
echo $total . PHP_EOL;
# 結果
3
return.rb
def calc(a, b)
  return a+b
end

total = calc(1,2)
p total
# 結果
3

returnを省略できる。

return.rb
def calc(a, b)
  a+b #最後の行の結果が返る
end

total = calc(1, 2)
p total
# 結果
3

classについて

基本

class_basic.rb
class Hoge
  # メンバ関数の定義
  def fuga
    p 'this is fuga!'
  end
end

## 継承
class HogeHoge < Hoge

end

a = Hoge.new
a.fuga

b = HogeHoge.new
b.fuga
# 結果
"this is fuga!"
"this is fuga!"

初期化

init.php
<?php

class Hoge
{
    function __construct()
    {
        echo 'initial var' . PHP_EOL;
    }
}

$a = new Hoge;

# 結果
'init var'
init.rb
class Hoge
  def initialize
    p 'initial var'
  end
end

a = Hoge.new

# 結果
"initial var"

クラスメソッド

static.php
<?php

class Hoge{
    static function fuga(){
        echo 'this is static function!'.PHP_EOL;
    }
}

Hoge::fuga();

# 結果
'this is static function!'
class_method.rb
class Hoge

  def self.fuga
    p 'this is static method!'
  end
end

Hoge::fuga
# 結果
"this is static method!"

メソッドのアクセス権設定

PHPの場合は各メソッド毎にアクセス修飾子にてアクセス権を設定します。

access.php
<?php

class Hoge
{
    public function publicFunc()
    {
        echo 'this is public method!' . PHP_EOL;
    }

    private function privateFunc()
    {
        echo 'this is private method!' . PHP_EOL;
    }
}

$a = new Hoge();
$a->publicFunc();
$a->privateFunc();

# 結果
this is public method!

Fatal error: Call to private method hoge::privateFunc() from context '' in ...

Rubyの場合はまとめて指定します。これに関してはエレガントなのかわかりません。。

access.rb
class Hoge

  public #publicの場合は省略可能

  def public_func1
    p 'this is public method1'
  end

  def public_func2
    p 'this is public method2'
  end

  private

  def private_func1
    p 'this is private method1'
  end

  def private_func2
    p 'this is private method2'
  end
end

a=Hoge.new
a.public_func1
a.public_func2
a.private_func1
a.private_func2

# 結果
"this is public method1"
"this is public method2"
access.rb:21:in `<main>': private method `private_func1' called for #<Hoge:0x007fa18b1291f0> (NoMethodError)

setter/getter

setter_getter.php
<?php

class Hoge
{
    private $var;

    function __construct()
    {
        $this->var = 'initial var';
    }

    function setVar($txt)
    {
        $this->var = $txt;
    }

    function getVar()
    {
        return $this->var;
    }
}

$a = new Hoge;
echo $a->getVar().PHP_EOL;
$a->setVar('hogehoge');
echo $a->getVar().PHP_EOL;

# 結果
initial var
hogehoge

rubyの場合はプロパティの宣言が不要です。
initializeで初期化してますが、これも必須ではありません。

setter_getter.rb
class Hoge
  def initialize
    @var ='initial var' #インスタンス変数(省略可能)
  end

  def set_var(txt)
    @var = txt
  end

  def get_var
    @var
  end

end

a = Hoge.new
p a.get_var
a.set_var 'hogehoge'
p a.get_var

# 結果
"initial var"
"hogehoge"

Rubyの場合は別の書き方が出来ます。

accesser.rb
class Hoge
  attr_accessor :var #varのsetter/getterのセット

  def initialize
    @var ='initial var'
  end
end

a = Hoge.new
p a.var
a.var = 'hogehoge'
p a.var
# 結果
"initial var"
"hogehoge"

ただし、これだとPHPのpublicな変数と一緒になってしまうので使いすぎに注意です。
実際には読み取り専用にするシチュエーションが多いと思うので、その場合は以下のようにします。

read_only.rb
class Hoge
  attr_reader :var #varのgetterのみ

  def initialize
    @var ='initial var'
  end
end

a = Hoge.new
p a.var
a.var = 'hogehoge'
p a.var

# 結果
"initial var"
for.rb:11:in `<main>': undefined method `var=' for #<Hoge:0x007f8844805d08 @var="initial var"> (NoMethodError)
Did you mean?  var

あと、替わりにattr_writerを使うと書き込み専用となります。

その他シンタックス

条件分岐

if

if.php
<?php
$a = 'hoge';
if ($a === 'hoge') {
    echo 'true' . PHP_EOL;
} else {
    echo 'false' . PHP_EOL;
}
if.rb
a = 'hoge'
if a == 'hoge'
  p 'true'
else
  p 'false'
end

ほぼ一緒ですね。違うのは、rubyでは===じゃなくて==を使う事。
===もシンタックス的にはokだけど、「特殊な等号演算子」で主にcase文の比較で用いられる。
詳しくは、当記事のコメント参照。

ワンライナーだと、

if.php
<?php
$a = 'hoge';
if ($a === 'hoge') echo 'true' . PHP_EOL;
if.rb
a = 'hoge'
p 'true' if a == 'hoge'

rubyだと後置ifになります。

否定

if.php
<?php
$a = 'hoge';
if ($a !== 'hoge') {
    echo 'true' . PHP_EOL;
} else {
    echo 'false' . PHP_EOL;
}
if.rb
a = 'hoge'
unless a == 'hoge'
  p 'true'
else
  p 'false'
end

rubyでは否定を先に評価する場合は、unlessを使うと表現力が上がります。unlessの場合にelseを使う場合は二重否定になって読みにくいので推奨はされていません。

for

for.php
<?php
for ($num = 0; $num < 10; $num++) {
    echo $num . PHP_EOL;
}

これがrubyだと、

for.rb
for num in 0...10 do
  p num
end

また、次のようにも書けます。

each.rb
(0...10).each do |num|
  p num
end

そして一番直感的なのは、以下の記述でしょう。

times.rb
10.times.each do |num|
  p num
end

foreach

配列

each.php
<?php
$array = ['a','b','c'];
foreach($array as $v){
    echo $v.PHP_EOL;
}
# 結果
"a"
"b"
"c"
each.rb
array = ["a","b","c"]
array.each do |v|
  p v
end
# 結果
"a"
"b"
"c"

ハッシュ

hash.php
<?php
$hash = ['one'=>'a','two'=>'b','three'=>'c'];
foreach($hash as $k=>$v){
    echo "{$k}:{$v}".PHP_EOL;
}
# 結果
"one:a"
"tow:b"
"three:c"
hash.rb
hash = {one:"a",tow:"b",three:"c"}
hash.each do |k,v|
  p "#{k}:#{v}"
end
# 結果
"one:a"
"tow:b"
"three:c"

おわりに

他にもブロック付き引数とか覚える事はいっぱいあるんですが、PHPが書ければとりあえずRubyもすんなり書けるよ!という事で、Ruby参入の障壁はほとんど無い事が理解してもらえたら嬉しいです。
あとは私もですがRailsのコードリーディングをやってみたりして、わからない記述があったら少し深く調べてみたりと、少しづつキャッチアップしていけたらよいかなと思います。