知らないPHP解読の手順

# PHPを読むことを諦める瞬間
昔のPHPのコードはなぜか読みにくい。
Laravelが出る前の「フレームワーク乱立」が原因の1つではあるんですが、

それ以外に、
「これって、このフレームワーク独自の書き方なのか…？」と思ったら、
コーディング規約が（ない・古い・ゆるい）だけだったりします。

### 「僕の知ってるPHPじゃない」が結構ある
Laravel とか Symfony を見た後に、それ以外のフレームワークを見ると
抽象化されてないので、native な PHP という印象を受ける事があります。

知らないPHPフレームワークのコードをいざ読む時、
まず何からやったら良いのか、わからなくないですか？
例えば、こんな感じのPHPが書かれてるとします。
#### 例文
```
$param = [':user_id' => Yii::$app-> users -> user_id];
$query = "SELECT COUNT(*) FROM user_log WHERE mid = :user_id";
$count = Yii::$app->db_component->createCommand($query, $param)->queryScalar() ?: 0;
```

3行くらいならまだ読めるんですが、これが100行続いてると
「もう読めない」となってきます。そういう時の、地道な解決策です。

# (1)とにかくバラしてみる
メソッドチェーンも、コンポーネントを変数に代入しておくと、読んで理解できます。
三項演算子も、わざわざ省略しないで書いてみました。

```php
$userComponent = Yii::$app->users;
$userId = $userComponent->user_id;

$param = [':user_id' => $userId];
$query = "SELECT COUNT(*) FROM user_log WHERE mid = :user_id";
$dbComponent = Yii::$app->db_component;
$command = $dbComponent->createCommand($query, $param);

$count = $command->queryScalar();
$count = ($count !== null && $count !== false) ? $count : 0;
```

# (2)とにかく改行する
配列の代入がわかりますし、SQLもっと長い場合適切に改行することでSQLが読めるようになります。

```php
$userComponent = Yii::$app->users;
$userId = $userComponent->user_id;

$param = [
    ':user_id' => $userId
];

$query = "
    SELECT 
        COUNT(*) 
    FROM 
        user_log 
    WHERE 
        user_id = :user_id
";

$dbComponent = Yii::$app->db_component;

$command = $dbComponent->createCommand($query, $param);

$count = $command->queryScalar();
$count = ($count !== null && $count !== false) ? $count : 0;
```

# (3)とにかく説明を書いてみる
データ型もちゃんと分かるように書いてみる。
```php
/** @var UserComponent $userComponent */
$userComponent = Yii::$app->users;

/** @var int|string|null $userId */
$userId = $userComponent->user_id;

// パラメータを個別に変数へ
$param = [
    ':user_id' => $userId
];

// SQLクエリを作成、確認しやすいようにフォーマット
$query = "
    SELECT 
        COUNT(*) 
    FROM 
        user_log 
    WHERE 
        user_id = :user_id
";

// DBコンポーネントを取得し変数に代入
/** @var DbComponent $dbComponent データベースコンポーネントインスタンス */
$dbComponent = Yii::$app->db_component;

// createCommandメソッドを使ってコマンドを作成
/** @var \yii\db\Command $command SQLコマンドオブジェクト */
$command = $dbComponent->createCommand($query, $param);

// queryScalarメソッドの結果を取得し、nullをチェックして0をデフォルトに設定
/** @var int|string|false|null $count COUNT結果の型 */
$count = $command->queryScalar();
$count = ($count !== null && $count !== false) ? (int)$count : 0;
```

# (4)ORMに変換してみる
ORMに慣れてる人であれば、ORMで書き直したほうがわかりやすい。
どうやらこのフレームワークには、Eloquent的なライブラリがあるらしい。

```php
use app\models\UserLog;

$userComponent = Yii::$app->users;

$userId = $userComponent->user_id;

$count = UserLog::find()
    ->where(['user_id' => $userId])
    ->count();
```

# 見比べてみよう
当初は、「これ `$count` ってことは `int` で返るよな…？」と半信半疑でしたが

```
$count = Yii::$app->db_component->createCommand($query, $param)->queryScalar() ?: 0;
```
説明を付けることで `int` で返っている事が、わかりますし

```php
// queryScalarメソッドの結果を取得し、nullをチェックして0をデフォルトに設定
/** @var int|string|false|null $count COUNT結果の型 */
$count = $command->queryScalar();
$count = ($count !== null && $count !== false) ? (int)$count : 0;
```

（そもそもキャストしなくても)ORMの方が何をやってるのか分かりやすい、気がします。
```PHP
$count = UserLog::find()
    ->where(['user_id' => $userId])
    ->count();
```

# 理解できたら、書き直せる範囲で書き直す
もし書き直して良ければ書き直します。

古い書き方
```php
$param = [':user_id' => Yii::$app-> users -> user_id];
$query = "SELECT COUNT(*) FROM user_log WHERE user_id = :user_id";
$count = Yii::$app->db_component->createCommand($query, $param)->queryScalar() ?: 0;
```
Yii の Active Record
```php
use app\models\UserLog;
$userId = Yii::$app->users->user_id;
$count = UserLog::find()->where(['user_id' => $userId])->count() ?: 0;
```
もしも Laravel の Eloquent に置き換えるとしたらこうなる。
```php
use App\Models\UserLog;
$userId = auth()->user()->id;
$count = UserLog::where('user_id', $userId)->count() ?: 0;
```

# 結論
今更 Laravel に置き換えるのかどうかは別として、昔の古いPHPのコードは読んでみたら
実は、ほとんど今とやってる事は変わってない事がわかります。


「ちゃんとチューニングしてある」っていう見方もあるんですが、
コードを読み解く工夫が必要な時点で、開発体験が悪くなるので、
こまめなアップデート、もしくは大胆なリプレイスが必要と、個人的には考えています。