【PHP入門】RubyエンジニアがPHPを勉強し始めるときに見る記事

# この記事 is 何

RubyエンジニアがPHPを勉強し始めるときに見る、PHPの入門記事です。

## 動機
今までRubyをやってきていて、PHPを使うことになったというケースは少なくないと思っています。
特に実務未経験の方々では、このケースが多いのではないでしょうか？
というのは、実務未経験が学習している言語は、Rubyがファーストチョイスである一方で、PHPを使う企業は少なくないためです。
ちなみに、僕もそのケースでした。
そういう方々が過度に不安を持ったりせず、スムーズに転向できるようにしたいと思い、この記事を書きました。

## この記事の主なターゲット

- 今までRubyを勉強してたが、PHPを使うことになった人
- というか半年前の自分

### この記事で書くつもりのないこと

- 技術選定時・初学者が学ぶ言語としてRuby or PHPはどっちが良いのかということ
- 網羅的・辞書的にRubyとPHPを比較した結果
- RubyとPHPの文法の正確な対応関係

# 学習のし始め

## RubyからPHPへの転向コスト

Rubyをちゃんと習得できた方であれば、転向・学習コストにおいて問題はほぼ起きないと思います。
文法を調べながらとりあえず書き始められる、というレベルに達するには半日〜3日程度の勉強で済むと思います。

## 文法を調べるときに何を使うか

[php.net](https://www.php.net/)
PHPは公式ドキュメントが神なので、基本的にこのサイトを見ればPHPの文法的な解決してくれるはずです。

![Screen Shot 2020-11-15 at 18.55.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496036/79178cc9-21d1-2a86-6775-42790aa477ba.png)

ググラビリティも良好で、「array_merge php」などと検索すれば公式ドキュメントが先頭に出てくれます。

# 本題

```bash:動作確認バージョン
$ php -v
PHP 7.3.11 ...

$ ruby -v
ruby 2.6.3p62 ...
```

## 基本的なオブジェクトの概念

### 出力

|| Ruby | PHP |
| ---- | ---- | ---- |
|改行なし出力| print | echo |
|型情報付き出力| p | var_dump() |
|配列に対し改行付き出力| puts | echo, PHP_EOL |

Rubyの`print`は、PHPでいうと`echo`に近いです。
Rubyの`p`は、PHPでいうと`var_dump`に近いです。

Rubyの`puts`は？と言われると、対応したものはありません。
`echo`と`PHP_EOL`を組み合わせる必要があります。

```Ruby:objects/print.rb
print 'sample!'
# sample!

sample_array = [1, 'sample']
print sample_array
# [1, "sample"]

p sample_array
# [1, "sample"]

puts sample_array
# 1
# sample
```

```PHP:objects/class.php
<?php
echo 'sample!';
// sample!

$sample_array = [1, 'sample'];
echo $sample_array;
// Array

var_dump($sample_array);
// array(2) {
//   [0]=>
//   int(1)
//   [1]=>
//   string(6) "sample"
// }

foreach ($sample_array as $value) {
    echo $value . PHP_EOL;
}
// 1
// sample
```

### プリミティブ型のクラス

|| Ruby | PHP |
| ---- | ---- | ---- |
| プリミティブ型は | クラス | ただの型 |
| 文字列への変換 | to_s | "{$変数}" |
| 数値への変換| to_i | intval() |

Rubyでは`String`, `Integer`, `Array`といったプリミティブ型も全てがオブジェクトです。
一方、PHPにはプリミティブ型においてはクラスの概念はありません。

PHPでは`string`への変換は、ダブルクウォートで囲った上で変数展開することによって実現します。
また、`int`に変換するには`intval()`を使います。

```ruby:objects/class.rb
int3 = 3

string3 = int3.to_s
p string3
# "3"

p string3.class
# String

re_int3 = string3.to_i
p re_int3
# 3

p re_int3.class
# Integer
```

```PHP:objects/method.php
<?php
$int3 = 3;

$string3 = "{$int3}";
var_dump($string3);
// string(1) "3"

get_class($string3);
// Warning: get_class() expects parameter 1 to be object, string given in ...

$re_int3 = intval($string3);
var_dump($re_int3);
// int(3)

get_class($re_int3);
// Warning: get_class() expects parameter 1 to be object, int given in ...
```

### 値・オブジェクトに対する基本的な操作・変換

|| Ruby | PHP |
| ---- | ---- | ---- |
| 基本的な操作・変換は | オブジェクトメソッド | 標準関数の引数に渡す |
| 文字数を調べる | length / size | mb_strlen() |
| 配列を合計する | sum | array_sum() |

Rubyでは値・オブジェクトに対する基本的な操作・変換はオブジェクトメソッドで実現します。
参考: [class Object(Ruby 2.7.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Object.html)

一方、PHPは標準関数が充実しており、その標準関数の引数として対象を渡すのが一般的です。

```ruby:objects/method.rb
address = '千代田区千代田1-1'
puts address.length
# 10

fibonacci_numbers = [1, 1, 2, 3, 5, 8, 13]
puts fibonacci_numbers.sum
# 33
```

```php:objects/method.php
<?php
$address = '千代田区千代田1-1';
echo mb_strlen($address);
// 10

$fibonacci_numbers = [1, 1, 2, 3, 5, 8, 13];
echo array_sum($fibonacci_numbers);
// 33
```

### 配列・ハッシュと、連想配列

|| Ruby | PHP |
| ---- | ---- | ---- |
| 配列の概念 | 配列 | 連想配列 |
| 連想配列の概念 | ハッシュ | 連想配列 |
| 配列の要素の取得 | 配列[インデックス] | 連想配列[インデックス] |
| 連想配列の要素の取得 | 配列[シンボル] | 連想配列[キー] |

Rubyでは配列と連想配列（ハッシュ）を使い分けます。
一方で、PHPはちょっと特殊で、連想配列しかありません。PHPにおける（連想配列でない）配列は、キーが数値である連想配列です。
また、Rubyでは連想配列のキーにはシンボルを使うことが多いと思いますが、PHPでは文字列をキーとすることが多いです。

```Ruby:objects/array.rb
days_of_week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
p days_of_week
# ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

puts days_of_week[0]
# Monday

fruits = {red: 'apple', purple: 'grape', yellow: 'lemon'}
p fruits
# {:red=>"apple", :purple=>"grape", :yellow=>"lemon"}

puts fruits[:red]
# apple
```

```php:objects/array.php
<?php
$days_of_week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
var_dump($days_of_week);
// array(7) {
//   [0]=>
//   string(6) "Monday"
//   [1]=>
//   string(7) "Tuesday"
//   [2]=>
//   string(9) "Wednesday"
//   [3]=>
//   string(8) "Thursday"
//   [4]=>
//   string(6) "Friday"
//   [5]=>
//   string(8) "Saturday"
//   [6]=>
//   string(6) "Sunday"
// }

echo $days_of_week[0];
// Monday

$fruits = ['red' => 'apple', 'purple' => 'grape', 'yellow' => 'lemon'];
var_dump($fruits);
// array(3) {
//   ["red"]=>
//   string(5) "apple"
//   ["purple"]=>
//   string(5) "grape"
//   ["yellow"]=>
//   string(5) "lemon"
//}

echo $fruits['red'];
// apple
```

### 配列への操作

|| Ruby | PHP |
| ---- | ---- | ---- |
| 配列への追加 | 配列 << 新要素 | 配列[] = 新要素 |
| 連想配列への追加 | 配列[シンボル] = 新要素 | 配列[キー] = 新要素 |
| 繰り返し処理 | each | foreach |
| 繰り返し処理(返り値使用) | map | array_map() |
| 繰り返し処理内での行いたい処理 | ブロック | コールバック関数 |

配列への追加は、Rubyは`<<`によってできる一方、PHPでは`配列[] = 新要素`という書き方を使います。
連想配列への追加は、書き方的にほぼ違いは無いかと思います。

手続き的な繰り返し処理は、Rubyなら`each`, PHPなら`foreach`です。
返り値を使用したいときはRubyなら`map`, PHPなら`array_map()`を使います。

繰り返し処理中に行いたい処理を表現するのは、Rubyならブロック、PHPならコールバック関数を使います。
`array_map()`はよく使う割にはちょっと複雑な見た目をしていますね。

```Ruby:objects/array_function.rb
sequence_numbers = [1, 2, 3, 4, 5]
sequence_numbers << 6
p sequence_numbers
# [1, 2, 3, 4, 5, 6]

fruits = {red: 'apple', purple: 'grape', yellow: 'lemon'}
fruits[:orange] = 'pumpkin'
p fruits
# {:red=>"apple", :purple=>"grape", :yellow=>"lemon", :orange=>"pumpkin"}

sequence_numbers.each do |number|
  multiple_of_3 = number * 3
  puts multiple_of_3
end
# 3
# 6
# 9
# 12
# 15
# 18

multiples = sequence_numbers.map do |number|
  number * 3
end
p multiples
# [3, 6, 9, 12, 15, 18]
```

```PHP:objects/array_function.php
<?php
$sequence_numbers = [1, 2, 3, 4, 5];
$sequence_numbers[] = 6;
var_dump($sequence_numbers);
// array(6) {
//   [0]=>
//   int(1)
//   [1]=>
//   int(2)
//   [2]=>
//   int(3)
//   [3]=>
//   int(4)
//   [4]=>
//   int(5)
//   [5]=>
//   int(6)
// }

$fruits = ['red' => 'apple', 'purple' => 'grape', 'yellow' => 'lemon'];
$fruits['orange'] = 'pumpkin';
var_dump($fruits);
// array(4) {
//   ["red"]=>
//   string(5) "apple"
//   ["purple"]=>
//   string(5) "grape"
//   ["yellow"]=>
//   string(5) "lemon"
//   ["orange"]=>
//   string(7) "pumpkin"
// }

foreach ($sequence_numbers as $number) {
    $multiple_of_3 = $number * 3;
    echo $multiple_of_3 . PHP_EOL;
}
// 3
// 6
// 9
// 12
// 15
// 18

$multiples = array_map(
    function ($number) {
        return $number * 3;
    },
    $sequence_numbers
);
var_dump($multiples);
// array(6) {
//   [0]=>
//   int(3)
//   [1]=>
//   int(6)
//   [2]=>
//   int(9)
//   [3]=>
//   int(12)
//   [4]=>
//   int(15)
//   [5]=>
//   int(18)
// }
```

## クラス関連

クラスは重要なので、重点的に解説します。

### インスタンス変数=プロパティ

|| Ruby | PHP |
| ---- | ---- | ---- |
| メンバ変数 | インスタンス変数 | プロパティ |
| privateなメンバ変数の定義 | 不要 | private $変数; |
| publicなメンバ変数の定義 | @変数に代入し、attr_accessor | public $変数; |
| コンストラクタ | def initialize | function __construct() |
| メンバ変数への代入 | @変数に代入 | `$this->変数`に代入 |
| メンバ変数の呼び出し | . | -> |

Rubyのインスタンス変数は、PHPのプロパティに該当します。
Rubyはインスタンス変数の宣言は特に必要なく、コンストラクタで`@変数`に代入してしまえば完了です。
一方、PHPだと宣言が必要で、`private $変数;`のように定義します。

また、メンバ変数を公開可能にしたいのであれば、Rubyでは`attr_accessor`を使う一方、PHPでは`public $変数`によって定義します。

```ruby:classes/Person.rb
class Person
  attr_accessor :name

  def initialize name, age
    @name = name
    @age = age
  end
end

person = Person.new '一郎', 10
p person
# #<Person:0x00007ff39f158750 @name="一郎", @age=10>

puts person.name
# 一郎

puts person.age
# Traceback (most recent call last):
# classes/Person.rb:16:in `<main>': undefined method `age' for #<Person:0x00007ff39f158750 @name="一郎", @age=10> (NoMethodError)
```

```php:classes/Person.php
<?PHP

class Person
{
    public $name;
    private $age;

    public function __construct($name, $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

$person = new Person('一郎', 10);
var_dump($person);
// object(Person)#1 (2) {
//   ["name"]=>
//   string(6) "一郎"
//   ["age":"Person":private]=>
//   int(10)
// }

echo $person->name;
// 一郎

echo $person->age;
// Fatal error: Uncaught Error: Cannot access private property Person::$age in ...
```

### クラスの定数

|| Ruby | PHP |
| ---- | ---- | ---- |
| 定数の定義 | 大文字 | const 大文字 |
| クラス外からの定数の呼び出し |  クラス::定数 | クラス::定数 |
| クラス内からの定数の呼び出し |  定数 | self::定数 |

PHPだと定数は`const`を付けて宣言します。
クラス外からの呼び出しは、RubyでもPHPでも同じ書き方です。
PHPだとクラス内からの呼び出しでは`self::`をつけます。

```ruby:classes/Sample.rb
class Sample
  TEST_CODE = 'test_code'

  def print_code
    puts "コードは#{TEST_CODE}です。";
  end
end

puts Sample::TEST_CODE
# test_code

sample = Sample.new
sample.print_code
# コードはtest_codeです。
```

```php:classes/Sample.php
<?PHP

class Sample
{
    const TEST_CODE = 'test_code';

    public function printCode()
    {
        $code = self::TEST_CODE;
        echo "コードは「{$code}」です。";
    }
}

echo Sample::TEST_CODE;
// test_code

$sample = new Sample();
$sample->printCode();
// コードは「test_code」です。
```

### インスタンスメソッド

|| Ruby | PHP |
| ---- | ---- | ---- |
| publicメソッドの定義方法 | ただのdef | public function() |
| privateメソッドの定義方法 |  privateの下でdef | private function() |

Rubyではクラス内で何も行わずに`def`をするとpublicメソッドとなり、`private`の下で定義されるとprivateメソッドになります。
一方、PHPではメソッドの定義時に必ず`public`/`private`を定義します。
(本当はもっと色々種類がありますが割愛)

```ruby:classes/Product.rb
class Product
    def initialize price, cost
        @price = price
        @cost = cost
    end

    def print_judgment
        if calc_profit > 0
            puts 'この商品は利益が出ます！どんどん売りましょう！';
        else
            puts 'この商品は利益が出ません...売るべきではないかもしれません...'
        end
    end

    private

    def calc_profit
        @price - @cost
    end
end

product = Product.new 120, 100
product.print_judgment
# この商品は利益が出ます！どんどん売りましょう！

product =  Product.new 90, 100
product.print_judgment
# この商品は利益が出ません...売るべきではないかもしれません...

product.calc_profit
# Traceback (most recent call last):
# classes/Product.rb:30:in `<main>': private method `calc_profit' called for #<Product:0x00007fc9f19dc408 @price=120, @cost=100> (NoMethodError)
```

```php:classes/Product.php
<?php

class Product
{
    private $price;
    private $cost;

    public function __construct($price, $cost)
    {
        $this->price = $price;
        $this->cost = $cost;
    }

    public function printJudgment()
    {
        if ($this->calcProfit() > 0) {
            echo 'この商品は利益が出ます！どんどん売りましょう！';
        } else {
            echo 'この商品は利益が出ません...売るべきではないかもしれません...';
        }
    }

    private function calcProfit()
    {
        return $this->price - $this->cost;
    }
}

$product = new Product(120, 100);

$product->printJudgment();
// この商品は利益が出ます！どんどん売りましょう！

$product = new Product(90, 100);
$product->printJudgment();
// この商品は利益が出ません...売るべきではないかもしれません...

$product->calcProfit();
// Fatal error: Uncaught Error: Call to private method Product::calcProfit() from context '' in ...
```

### クラスメソッドとstaticメソッド

|| Ruby | PHP |
| ---- | ---- | ---- |
| 静的メソッド | クラスメソッド | staticメソッド |
| インスタンスメソッド | インスタンスメソッド | staticでないメソッド |
| 静的メソッドの定義方法 | self | static function() |
| 静的メソッドの呼び出し | クラス::メソッド | クラス::メソッド |

Rubyにおけるクラスメソッドは、PHPではstaticメソッドに該当します。
逆に、インスタンスメソッドはstaicでないメソッドということになります。

Rubyでクラスメソッドを定義するときは、`class << self`の中で定義することが多いと思います。
一方で、PHPではメソッドの定義ごとに`static`を付与することで定義します。

また、`public`/`private`はどんなメソッドでも付けるので、staticメソッドにも`public`/`private`を付けて定義します。
静的メソッドの呼び出しの書き方は、RubyとPHPとでほぼ差は無いかと思います。

```Ruby:classes/VertebrateAnimal.rb
class VertebrateAnimal
  class << self
    def is_vertebrate_animal group
      get_vertebrate_animals.include? group
    end

    private

    def get_vertebrate_animals
      %w[fishes amphibians reptiles birds mammals]
    end
  end
end

is_vertebrate_animal1 = VertebrateAnimal::is_vertebrate_animal 'fishes'
puts is_vertebrate_animal1
# true

is_vertebrate_animal2 = VertebrateAnimal::is_vertebrate_animal 'insects'
puts is_vertebrate_animal2
# false
```

```PHP:classes/VertebrateAnimal.php
<?PHP

class VertebrateAnimal
{
    public static function isVertebrateAnimal($group)
    {
        $vertebrate_animals = self::getVertebrateAnimals();
        return in_array($group, $vertebrate_animals, true);
    }

    private static function getVertebrateAnimals()
    {
        return ['fishes', 'amphibians', 'reptiles', 'birds', 'mammals'];
    }
}

$is_vertebrate_animal1 = VertebrateAnimal::isVertebrateAnimal('fishes');
var_dump($is_vertebrate_animal1);
// bool(true)

$is_vertebrate_animal2 = VertebrateAnimal::isVertebrateAnimal('insects');
var_dump($is_vertebrate_animal2);
// bool(false)
```

### ゲッターとセッター

|| Ruby | PHP |
| ---- | ---- | ---- |
| ゲッター | attr_reader | getXX() |
| セッター | attr_writer | setXX() |

Rubyにおける`attr_reader`および`attr_writer`に該当するような文法は、PHPにはありません。
よって`getXX`, `setXX`という命名で自作することになります。

```ruby:classes/Capsule.rb
class Capsule
  attr_reader :element
  attr_writer :element

  def initialize element
    @element = element
  end
end

capsule = Capsule.new '有効成分'
puts capsule.element
# 有効成分

p capsule
# #<Capsule:0x00007f8d909ac660 @element="有効成分">

capsule.element = '毒'
p capsule
# #<Capsule:0x00007f8d909ac660 @element="毒">
```

```php:classes/Capsule.php
<?PHP

class Capsule
{
    private $element;

    public function __construct($element)
    {
        $this->element = $element;
    }

    public function getElement()
    {
        return $this->element;
    }

    public function setElement($element)
    {
        $this->element = $element;
    }
}

$capsule = new Capsule('有効成分');
echo $capsule->getElement();
// 有効成分

var_dump($capsule);
// object(Capsule)#1 (1) {
//   ["element":"Capsule":private]=>
//   string(12) "有効成分"
// }

$capsule->setElement('毒');
var_dump($capsule);
// object(Capsule)#1 (1) {
//   ["element":"Capsule":private]=>
//   string(3) "毒"
// }
```

## その他ハマりポイント

### ライブラリの対応関係

|| Ruby | PHP |
| ---- | ---- | ---- |
| ライブラリ管理 | Gem | Composer |
| テスト | Rspec | PHPUnit |
| Linter | Rubocop | PHP-CS-Fixerなど |
| コメント | RDoc | PHPDoc |
| フレームワーク | Ruby on Rails | Laravel, CakePHPなど |

有名どころのライブラリなどの対応関係のみを記載しました。
Rubyと言ったらRails、Railsと言ったらRubyという印象ですが、PHPではフレームワークは複数の選択肢があります。
シェアが高いという意味であればLaravelが近く、MVCの思想に忠実という意味ではCakePHPに近いかなという印象を持っています。

### 真偽判定・nil/null判定

|| Ruby | PHP |
| ---- | ---- | ---- |
| == | そこそこ使う | 絶対に使わない |
| Null | nil | null |
| オブジェクトのNull確認 | ! | empty() |

[PHPの==はあまりにもヤバい](https://twitter.com/dyoshimitsu/status/1332508068135923712)ことで有名だと思いますので、比較のときには必ず`===`を使うようにします。
Rubyでの`nil`は、PHPだと`null`に該当します。

Rubyでは全てがオブジェクトであり、真偽値判定・`nil`判定がうまく設計されていて、オブジェクトのみで直感的に真偽値判定・`nil`判定をできることも多いです。
一方、PHPの場合は直感的に真偽値判定・`null`判定を行うのは危険なので、型を意識して判定した方が安全です。
オブジェクトがnullや空かどうかを確認するなら、`empty()`を使うのが有効です。

```Ruby:others/User.rb
class User
  class << self
    def find_by_id id
      # IDが1のときはユーザオブジェクトを返し、それ以外のときはユーザオブジェクトを返さないとします
      if id == 1
        User.new '最初のユーザ'
      else
        nil
      end
    end
  end

  def initialize name
    @name = name
  end
end

def print_user user
  # ユーザオブジェクトが存在するかを確認する
  if !user
    puts 'ユーザはいません'
  else
    p user
  end
end

user2 = User::find_by_id 2
print_user user2
# ユーザはいません

p user2
# nil

user1 = User::find_by_id 1
print_user user1
# #<User:0x00007fe70f173f88 @name="最初のユーザ">
```

```PHP:others/User.php
<?php

class User
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    static function findById($id)
    {
        /** IDが1のときはユーザオブジェクトを返し、それ以外のときはユーザオブジェクトを返さないとします */
        if ($id === 1) {
            return new static('最初のユーザ');
        } else {
            return null;
        }
    }
}

function printUser($user)
{
    // ユーザオブジェクトが存在するかを確認する
    if (empty($user)) {
        echo 'ユーザはいません';
    } else {
        var_dump($user);
    }
}

$user2 = User::findById(2);
printUser($user2);
// ユーザはいません

var_dump($user2);
// NULL

$user1 = User::findById(1);
printUser($user1);
// object(User)#1 (1) {
//   ["name":"User":private]=>
//   string(18) "最初のユーザ"
// }
```

### if文の返り値

|| Ruby | PHP |
| ---- | ---- | ---- |
| if文の返り値 | 最後の値 | なし |
| 分岐によって値を生成する場合 | ifの返り値に入れる | 一度値を初期化し、再代入する |

PHPは`if`文の返り値が返ってきません。
そのため、分岐によって値を生成させるケースでは一度値を初期化するなどしてから再代入する、みたいな方法を取る必要があります。

どうしても再代入がいやだ、イミュータブルにしたい、という場合は三項演算子という方法もあります。
ただし、三項演算子は多くの場合は処理が分かりにくくなるだけなので、非推奨です。

```others/day.rb
def print_ymd is_beginning_of_month
  today = Time.now

  datetime = if is_beginning_of_month
               Time.new today.year, today.month, 1 # is_beginning_of_month = falseでは現在日を返す
             else
               today # 月初を返す
             end

  puts datetime.strftime "%Y年%m月%d日です"
end

print_ymd false
# 2020年12月07日です

print_ymd true
# 2020年12月01日です
```

```PHP:others/day.php
<?php

function printYmd($is_beginning_of_month)
{
    $today = new DateTimeImmutable();

    $datetime = null;
    if ($is_beginning_of_month) {
        // 月初を返す
        $datetime = new DateTimeImmutable($today->format('Y-m-01'));
    } else {
        // $is_beginning_of_month = falseでは現在日を返す
        $datetime = $today;
    }

    echo $datetime->format('Y年m月d日です');
}

printYmd(false);
// 2020年12月07日です

printYmd(true);
// 2020年12月01日です

/**
 * 別の書き方。コード量は少ないが分かりにくい
 */
function printYmd2($is_beginning_of_month)
{
    $today = new DateTimeImmutable();
    $datetime = $is_beginning_of_month ? new DateTimeImmutable($today->format('Y-m-01')) : $today;

    echo $datetime->format('Y年m月d日です');
}
```

### 名前付き引数がない(PHP7以前)

|| Ruby | PHP7以前 | PHP8以後 |
| ---- | ---- | ---- | ---- |
| 名前付き引数 | 引数名: | なし | 引数名: |

PHP7以前では名前付き引数がありません。
よって、オプション引数と言いながらも順番を意識して代入する必要があります(辛い)。
このため、依存性注入が凄まじくやりづらいです。

PHP8には名前付き引数が導入されています。
[【PHP8.0】PHPに名前付き引数が実装される](https://qiita.com/rana_kualu/items/13bc0c30192ee22c1396)

```Ruby:others/argument.rb
def calc_goku_scouter original_power, kaio_ken: 1, is_suppressed: false, is_super_saiyan: false
  power = original_power * kaio_ken

  if power > 5000 && is_suppressed
    power = 5000
  end

  if is_super_saiyan
    power += 100000000
  end

  power
end

puts calc_goku_scouter 85000
# 85000

puts calc_goku_scouter 85000, kaio_ken: 2
# 170000

puts calc_goku_scouter 85000, is_suppressed: true
# 5000

puts calc_goku_scouter 85000, kaio_ken: 20, is_super_saiyan: true
# 101700000
```

```PHP:others/argument.php
<?php

function calcGokuScouter($original_power, $kaio_ken = 1, $is_suppressed = false, $is_super_saiyan = false)
{
    $power = $original_power * $kaio_ken;

    if ($power > 5000 && $is_suppressed) {
        $power = 5000;
    }

    if ($is_super_saiyan) {
        $power += 100000000;
    }

    return $power;
}

echo calcGokuScouter(85000);
// 85000

echo calcGokuScouter(85000, 2);
// 170000

echo calcGokuScouter(85000, 1, true);
// 5000

echo calcGokuScouter(85000, 20, false, true);
// 101700000
```

### interfaceとabstract

|| Ruby | PHP |
| ---- | ---- | ---- |
| インターフェース | なし | interface |
| 抽象クラス | なし | abstract |

Rubyには無い概念として、PHPには`interface`, `abstract`というものがあります。

特に`interface`は重要なのですが、中々概念の理解が難しいかもしれません。
とても勉強になった記事があるので、貼っておきます。
[脱PHP初心者！インターフェイスを理解しよう](https://qiita.com/KNJ/items/210b0b119d45927eca1e)

`abstract`はGoFのデザインパターンでいうTemplate Methodパターンを実装するのに必要です。
参考になった記事を貼っておきます。
[PHPによるデザインパターン入門 - TemplateMethod〜処理を穴埋めする - Do You PHP はてブロ](http://shimooka.hateblo.jp/entry/20141212/1418363698)

# 結び
いかがでしたか？
もし誤記・間違い・より良い書き方などあれば、ご指摘いただければと思います。
また他にこんなこと困ったよ！みたいなのもあれば、教えて頂けると嬉しいです。

一応GitHubにもコードをまとめておきました。
https://github.com/kumackey/php-ruby

## 他参考になりそうなもの
[PHPer向けのRuby入門](https://qiita.com/yamamoto_hiroya/items/08ee8d7bf5deafeebf75)
この記事の逆パターンです。演習問題が付いてる優しさ。

[PHPerがRubyを勉強するのに役に立つTips](https://qiita.com/bigplants/items/d1d38d934a2e962d5364)
同じくこの記事の逆パターン。

[元PHPエンジニアがPHPとRubyを比較してみた](https://blog.linkbal.co.jp/5156/)
PHPとRubyの文法の違いなど。

[PHPからRubyへ](https://www.ruby-lang.org/ja/documentation/ruby-from-other-languages/to-ruby-from-php/)
Rubyの公式が出している、PHPとの違いというドキュメント