4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPで学ぶオブジェクト指向再入門

Posted at

概要

最近オブジェクト指向でコードを書く機会が増えてきたので、改めて復習がてら書いてみます。
以前も似たような記事を投稿しましたが、また理解が変わったので。

参考書籍: 「効率的なwebアプリケーションの作り方」小川雄大

前提知識 - MVCとは

そもそもなぜwebアプリケーションにはMVCという考え方があるのか?
すっごい雑にwebアプリケーションを説明すれば、「サーバで何らかの処理をして、HTMLを吐き出すもの」である。

ゆえに、最終的なアウトプットがHTMLなので、如何せんロジックの処理と、HTMLで表示したい部分がごっちゃになりがちである。

特にPHPで言えば、コードの中にHTMLを書く事も出来るので余計に混同しやすい。
(私が最初の頃に書いてたコードもそんな感じでした)

コードが混同すると何が困るのか

ぶっちゃけ、個人的に書いてる分には良いと思いますが、チームで開発し始めるとカオスの始まりです。

  • どこを修正すれば良いのか分からない
  • 修正したら他の所に影響出た
  • ちょっと変えようと思っただけなのに、修正範囲が多すぎて辛い
  • テスト書きづらく、安全性に欠ける

などなど。

じゃあどうやって解決するのか

そこで出てきたのがMVCという考え方で、

Controller: リクエストの処理
Model: ドメインレベルのデータを扱う
View: コントローラから指示された内容の表示(別にViewがModelを参照してもOK)

と、それぞれに役割を与えてやれば、どこに何を書けば良いのかが明確になり、責任の分担が可能になります。
そして、コードが混同しないので、上記のような問題が起きにくくなります。
(MVCで書いてても、コードが混同する可能性はあるし、テストが書きづらい場合は起きます。なので 起きにくく という表現を使ってます)

オブジェクト指向の基本的な考え方

オブジェクト指向には、いくつか、基本的な考え方があります。
設計原則と呼ばれるものですが、あくまでも「原則」なので、必ず守れ!って訳ではなくて、
守ってると良い的なものです。

幾つか上げておきます。

  • SRP - Single Responsibility Principle
    • 単一責任の法則
  • OCP - the Open-Closed Principle
    • 開放 - 閉鎖原則
  • LSP - the Liskov Substitution Principle
    • リスコフの置換原則
  • DIP - the Dependency Inversion Principle
    • 依存関係逆転の原則
  • ISP - the Interface Segregation Principle
    • インターフェイス分離の原則

詳しくはぐぐって欲しいんですが、OCPだけ説明しておきます。
これが自分の中では一番基本的な考え方かなと感じていて、
この考え方を意識するようになってから、割りと良いコードが書ける様になってきたように思います。

OCP - Open-Closed Principleとは

これは、拡張に対しては開いていて、修正に対しては閉じていなさい。という意味で、
モジュールの振る舞いを拡張することが出来て、モジュールの振る舞いを変更してもコードは影響を受けないという事です。

よくわからないかと思いますので、例を。

例えば、ログを吐くという振る舞いをもつクラスを考えて見ます。

class Logger
{
    public function perform()
    {
        $this->log('Peform');
    }

    /**
     * 標準出力にメッセージ表示
     */
    private function log($message)
    {
        echo $message;
    }
}

簡単ですね。

じゃあ、ここで、振る舞いを拡張してみましょう。
例えば、このログを標準出力ではなくて、ファイルに吐き出したい。となった場合、どうなるでしょうか。
このLoggerを修正する必要があります。

class Logger
{
    // $outputTypeによって、ログを吐く場所を変える
    public function perform($outputType)
    {
        if ($outputType === 'file') {
            $this->logForFile('Peform');
        } else {
            $this->log('Peform');
        }
    }

    /**
     * ファイルにログを吐く
     */
    private function logForFile($message)
    {
        // ファイルにログを吐く
    }

    /**
     * 標準出力にログを吐く
     */
    private function log($message)
    {
        echo $message;
    }
}

雑ですが、こんな感じ。
これが、DBにログを残す、メールにログを(ryとか増えていくと、どんどんLoggerを修正しないといけないですよね。
これは「振る舞いを変えた時に、既存のコードを書き換えている」状態なので、OCP違反という事になります。
まぁ、こんな感じで処理変えていくと辛いですよね。

そこで、出てくるのがOCPの考え方で一般的にはポリモーフィズムとか言われてます。
先ほどのコードを、次のように振る舞いを委譲してみます。

class Logger
{
    public function perform($logger)
    {
        $logger->log('Peform');
    }
}

class EchoLogger
{
    public function log($message)
    {
        echo $message;
    }
}

$logger = new Logger();

$echoLogger = new EchoLogger();

// 標準出力にログ吐く
$logger->perform($echoLogger);

perfomeは、$loggerというインスタンスを受け取って、その$loggerのlogメソッドを呼び出すようにしてます。
こうすることで、ファイルやDB・メールにログを残したくなった場合、既存コードのLggerを修正することなく、FileLogger DBLogger MailLogger クラスを拡張するだけで、振る舞いを追加することが出来ます。

このように、既存のコードを修正することなく、モジュールの振る舞いを拡張出来るようにすることがオブジェクト指向の大原則であり、大きなメリットでもあります。
この原則をOCPと呼ぶのです。

これがわかるとオブジェクト指向の有り難みがわかってきます。
では、続きはまた次回。

4
7
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
4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?