LoginSignup
1
3

More than 5 years have passed since last update.

PHPカンファレンス2017@東京_メモ②型を意識したPHPアプリケーション開発

Posted at

PHPの型システム

 変数自体には型は無い
 値の方に型を持つ 
  gettype()で型を調べられる
 動的型付け言語
 暗黙的型変換
  10 + “5” = 15
   stringをintに自動で変換されている
  10 + “5e” = 15
   数値じゃない値が出てきたところで切って自動的にintに変換
  10 + “5e2” = 510
   5e2:指数表記になっている
 型宣言
  function double(int $i) : int {}
  引数や戻り値に型を指定出来る
   関数に入った瞬間はint型を保証
   戻り値もint型を保証
   double(“5e”) // TypeError
   型宣言使うならstrictモードをオンにする
    declare(strict_types = 1)
    
 まとめ
  値が型を持つ
  暗黙的型変換で柔軟に開発
  型宣言で厳密に開発
   ユーザーが選択(使い分け)出来る

型宣言を利用したコード実装

 Demo
  型宣言なし
  スカラー型で型宣言
  ユーザー定義型で型宣言

ユーザー定義型の例

<?php
//strictモードオン
declare(strict_types=1);

//税込価格計算クラス
final class priceWithTaxRateCalculate{
    public static function calculate(Price $price, TaxRate $taxRate): PriceWithTax //戻り値は税込価格型にする
    {
        return new PriceWithTax(intval($price->asInt() * (1 + $taxRate->asFloat())));
    }
}

//プライス型
final class price
{

    private $value;

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

    public function asInt():int
    {
        return $this->value;
    }
}

//税率型
final class taxRate
{

    private $value;

    public function __construct(float $value)
    {
        //消費税が1以下で無い場合は例外
        if(!($value < 1)){
            throw new InvariantException('Invalid taxRate is given');
        }
        $this->value = $value;
    }

    public function asFloat():float
    {
        return $this->value;
    }
}

//税込価格型
final class priceWithTaxRate
{

    private $value;

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

    public function asInt():int
    {
        return $this->value;
    }
}


?>

ドメイン特化型の実装Tips

 アプリケーションドメインを表現
 ドメインルールを検証
 型宣言による表現と強制
  インスタンスの生成 = ルールを満たしていることを保証
 PHPdockは実行時は役に立たない
 型宣言で表現できる範囲は限定される
  両方を組み合わせて使う

安易に継承を使わない

 継承元クラス型への適合を防ぐ
  継承元のクラスをそのまま受け継いでしまう
  PriceWithTaxがPriceを継承していた場合
   税込価格を商品価格として渡してしまう場合チェックが効かない
 継承元メソッドが含まれてしまう
  必要の無いメソッドが大量に含まれるクラスが出来てしまう
   出来るだけドメインに特化したメソッドのみにする
 実装を共有したい場合
  委譲やトレイトで共有

イミュータブルにすると安全

 完全コンストラクタ
 不変条件の検証が一度で済む
  コンストラクタで値をセットしても、setValue()みたいなメソッドがあると値がいつでも変えられてしまう
 ミュータブルな場合は都度検証

ファクトリメソッド

 newの乱立を防ぐ
 コンストラクタをprivateに
 

最後に

 型宣言で型を強制
 ドメインを型で表現
 型で気持ちいい開発を!

質疑(一部)

 Q;ドメイン特化型を導入した場合どのくらいパフォーマンスに影響があるか
 A:ケースバイケース、確かにスカラー型の方がメモリは食わないが優先度による
 Q:型を使った実装を少しずつ導入する場合どこから始めればいいか、単体テストもやって無い状況
 A:数値で仕様が決まっている部分、日付など。小さなクラスを作ってそれの単体テストを書くところから
 Q:PHP7.1でnullableが入ったが、エラーの場合例外で返すか、nullで返すか
 A:基本的にはnullで返すのはあまりよろしく無い。例外で返した方がわかりやすいのではないか。nullが返ってきた場合、使う側も扱いづらい。nullオブジェクトを定義する等。
 Q:ドメイン型からデータベースの型への変更をどうするか
 A:Repository層で処理。DBから取得した値を特化型に変換して返す等。
 Q:ソースの別プロジェクトへの流用がやりにくいのでは無いか
 A:流用すると、使わないメソッド等が入ったクラスが出てきてしまうため、ドメイン特化型の方がいい。ただ全てを特化型にすると時間がかかるので、ケースバイケースで対応。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3