2

私はこれについてたくさんの質問があることを知っています.私はかなりの量の読書をしました. 私のプロジェクトの文脈でこれを尋ねて、あなたが持っているかもしれない提案を確認したいと思います.

私は、ユーザー記事(メインクラスと見なす)などの多くのクラスと、画像コメントなどの小さなクラスを持つ非常に大きなWebアプリケーションを持っています。ページ上で、たとえばarticleとしましょう。画像コメントの多くのインスタンスが含まれている可能性があります。理にかなっていますよね?たとえば、記事ページで、記事オブジェクトの配列を返す静的メソッドを呼び出します。

それが背景なので、ここで質問です。

大量のアプリを構築して以来、設定と共有機能を含むコア システム クラスが非常に役立つことに気付きました。そこで、すべてのクラスを新しいコア クラスで拡張しました。実装は比較的単純で迅速に行えるように思われました。CodeIgniter が同様のことを行うことは知っています。私のアプリは少し乱雑になっていますが、今は感じています。

質問これは良い考えですか? コアのインスタンスを作成することは、記事のインスタンスを呼び出すときにまさに必要ですが、静的メソッドを使用して複数のインスタンスを作成したり、ページ上の複数の画像やコメントを呼び出したりする場合はどうでしょう。コアクラスを不必要に呼んでいますか?実際には、ページごとに 1 回だけ呼び出す必要があります (たとえば、コンストラクターはデータベースからさまざまな設定を定義します。これは毎回したくありません。明らかにページごとに 1 回だけです) が、すべてのクラスのすべてのインスタンスがそれにアクセスできる必要があります。コアクラス。シングルトン アプローチが必要なように聞こえますが、PHP では時間の無駄であることはわかっています。

この時点で私のコードがどのように見えるかを以下に示します。できるだけシンプルにしようとしました。

class core {

    public function __construct(){
        ...define some settings which are retrieve from the database
    }

    public function usefulFunction(){
    }
}


class user extends core {

    public function __construct(){
        parent::__construct();
    }

    public function getUser($user_id){
        $db = new database();
        $user = /* Get user in assoc array from db */

        $this->__setAll($user);
    }

    public static function getUsers(){
        $db = new database();
        $users = /* Get users from database in assoc array from db */

        foreach($users as $user) {
             $arrUsers[] = new self();
             $arrUsers[]->__setAll($user);
        }

        return $arrUsers;
    }

    private function __setAll($attributes) {
        foreach($attributes as $key => $value)
        {
            $this->__set($key, $value);
        }   
    }

    public function __set($key, $value) {
         $this->$key = $value;
    }

}

私が抱えているもう1つの問題は、データベース接続を効率的に使用/共有することです。現在、データベース接続を必要とするクラスの各メソッドは、データベースの新しいインスタンスを作成するため、1 つのページでこれを 5 回または 10 回行う可能性があります。依存性注入の原則のようなものは、はるかに優れています。

質問DB のインスタンスを新しいユーザー クラスに渡す場合、次のようなものが必要であることがわかります...

class user{
    protected $db;

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

    ... etc
}

$db = new database();
$user = new user($db);

...しかし、静的関数 users::getUsers() を実行したい場合、データベースインスタンスにアクセスする最良の方法は何ですか? 各静的メソッドで変数として渡す必要がありますか? (多くのクラスには多くの静的メソッドがあります)。最善の方法とは思えませんが、別の方法はないかもしれません。

質問パート 1 で提案されているように、すべてのクラスをコア クラスから拡張する場合、そこで DB のインスタンスを作成し、何らかの方法でそれにアクセスできますか?

質問ヘルパー ファイルのような関数 (oop ではない) を含むさまざまなファイルもあります。これらがデータベースにアクセスするための最良の方法は何ですか? 繰り返しますが、各関数で新しいインスタンスを作成しています。私は本当にデータベースをパラメーターとしてそれぞれに渡したくありません。グローバルを使用し、これらのヘルパー ファイルをクラスに変換し、依存性注入または別のものを一緒に使用する必要がありますか?

そこにはたくさんのアドバイスがあることは知っていますが、PHPに関するほとんどの情報とチュートリアルは古く、これほど複雑なことをカバーしていないようです...複雑と呼ぶことができますか?

クラス構造を最適にレイアウトする方法に関する提案。これは大変なことのように思えますが、ほとんどの開発者が毎日直面していることです。さらに情報が必要な場合は、私に知らせてください。読んでくれてありがとう!

4

4 に答える 4

1

すべての回答を要約します。

  1. コアに単一の「神」クラスを使用しないでください。
  2. 仕事をするクラスのリストを使用することをお勧めします。必要な数のクラスを作成します。各クラスは単一の仕事を担当する必要があります。
  3. シングルトーンは使用しないでください。これは古い手法であり、柔軟性がありません。代わりに依存性注入コンテナー (DIC)を使用してください。
于 2012-07-29T12:12:13.303 に答える
1

あなたはコメントで、それが悪い考えである理由を詳しく説明する必要があると尋ねました. それに答えるために、次の点を強調したいと思います。

本当に必要かどうか自問してください。

できるという理由だけでなく、必要に応じて設計上の決定を行います。あなたの場合、コアクラスが必要かどうかを自問してください。すでにコメントでこれを尋ねられているので、あなたは実際にはそれを必要としないと書いたので、答えは明らかです: それは必要ではなく、何かを必要としないために多くの副作用をもたらすため、そうするのは悪いことです.

これらの副作用のため、あなたはそれをしたくありません。ゼロからヒーローまで、次の進化を行いましょう。

コード/機能の 2 つの部分があります。変更される 1 つの部分と、変更されない基本的な機能 (フレームワーク、ライブラリ) である他の部分。両方を一緒にする必要があります。これを単純化して、フレームを 1 つの関数に減らしましょう。

function usefulFunction($with, $four, $useful, $parameters)
{
    ...
}

そして、アプリケーションの 2 番目の部分 (変更する部分) を 1 つのUserクラスに減らしましょう。

class User extends DatabaseObject
{
    ...
}

ここで、小さいながらも重要な変更を 1 つ紹介しました。コードを正しく読めば、データベース テーブル、つまりユーザー テーブルの行を表す機能であるため、Userクラスは拡張されCoreません。DatabaseObject

非常に重要なルールがあるため、この変更を既に行いました。クラスなど、コード内で何かに名前を付けるときはいつでも、話すのに適した名前を使用してください。名前とは、何かに名前を付けることです。その名前Coreは、それが重要、一般的、基本的、または奥深くにあると思うこと、またはそれが溶けた鉄であるとあなたが考える以外には何も言いません. 全く分からない。したがって、デザインのネーミングであっても、適切な名前を選択してください。私は思った、DatabaseObjectそしてそれはあなたのコードさえ知らない非常に迅速な決定だったので、あなたはそのクラスの本当の名前を知っていると確信しており、それに本当の名前を付けるのもあなたの義務です。寛大になってください。

ただし、これは詳細にすぎず、解決したい一般的な問題とはあまり関係がないため、この詳細は脇に置いておきます。悪い名前は症状であり、原因ではないとしましょう。Dr.Houseをプレイして症状をカタログ化しますが、原因を見つけるためだけです.

これまでに見つかった症状:

  • 余計なコード (不要でもクラスを書く)
  • ネーミングが悪い

診断してもいいですか: 見当識障害?:)

したがって、それを回避するには、常に必要なことを行い、コードを記述するためのシンプルなツールを選択してください。たとえば、一般的な機能 (フレームワーク) を提供する最も簡単な方法は、次のincludeコマンドを使用するのと同じくらい簡単です。

 include 'my-framework.php';    
 usefuleFunction('this', 'time', 'really', 'useful');

この非常に単純な 2 行のスクリプトは次のことを示しています。アプリケーションの一部は必要な機能 (ロードとも呼ばれます) を提供し、他の部分はそれらを使用します (これは、初日から知っているプログラム コードにすぎません。右?)。

これは、ユーザーオブジェクトが拡張されている可能性のあるオブジェクト指向の例にどのようにマップ/スケーリングしますか? まったく同じ:

include 'my-framework.php';
$user = $services->store->findUserByID($_GET['id']);

ここでの違いはmy-framework.php、一般的に変更されている部分が変更されていないものを利用できるように、より多くのものがロードされていることだけです。たとえば、 Service Locator (ここでは)を表すグローバル変数を提供し$servicesたり、自動読み込みを提供したりできます。

これをシンプルにすればするほど、進歩が進み、最終的に真の決断を迫られることになります。そして、これらの決定により、何が違いを生むかをより直接的に見ることができます。

「データベースクラス」についてさらに議論/ガイダンスが必要な場合は、本の「エンタープライズアプリケーションアーキテクチャのパターン」でこれらを処理する方法についての非常に良い章を読むことを検討してください。これはやや長いタイトルですが、トピックについて非常によく説明されている章があり、データベースに非常に簡単にアクセスする方法について適切なパターンを選択できます。最初から物事を簡単にしておくと、上達が早くなるだけでなく、後で簡単に変更することもできます。

ただし、基本クラスから拡張した複雑なシステム (一度に複数のことを実行することさえあります) から始めると、最初から物事を簡単に変更できるわけではないため、そのような決定にいつまでも固執することになります。それまで。

于 2012-07-29T11:46:34.510 に答える
1

すべてのデータベース クエリを処理する抽象クラスから始めて、それらをオブジェクトに構築できます。この方法でパラメーター化されたクエリを設定するのは簡単で、データベースとの対話方法を標準化できます。また、新しいオブジェクト モデルの追加も簡単になります。

http://php.net/manual/en/language.oop5.abstract.php

abstract class DB
{
  abstract protected function table();
  abstract protected function fields();
  abstract protected function keys();

  public function find()
  {
    //maybe write yourself a parameterized method that all objects will use...
    global $db; //this would be the database connection that you set up elsewhere.
    //query, and then pack up as an object
  }

  public function save()
  {
  }

  public function destroy()
  {
  }
}

class User extends DB
{
  protected function table()
  {
    //table name
  }  

  protected function fields()
  {
    //table fields here
  }

  protected function keys()
  {
    //table key(s) here
  }

  //reusable pattern for parameterized queries
  public static function get_user( $id )
  {
    $factory = new User;
    $params = array( '=' => array( 'id' => $id ) );
    $query = $factory->find( $params );
    //return the object
  }
}

共通の構成ファイルからデータベース接続を行い、それをこのパターンのグローバル変数としてそのままにしておく必要があります。

明らかに、これは表面をなぞっただけですが、うまくいけば、いくつかのアイデアを得ることができます。

于 2012-07-28T19:33:03.323 に答える
0

まず、シングルトン パターンを使用してデータベース インスタンスを取得することをお勧めします。

class Db{
protected $_db;

private function __construct() {
       $this->_db = new Database();
}

public static function getInstance() {
if (!isset(self::$_db)) {
    self::$_db = new self();
}
return self::$_db;
}
}

db::getInstance();どこでも同じように使えるようになりました。

第二に、あなたは Active Record パターンと呼ばれる自転車を発明しようとしています。__setAll($attributes).

3番目に、コアを拡張するクラスでこれを書いたのはなぜですか?

public function __construct(){
    parent::__construct();
}

最後に、クラス名は大文字にする必要があります。

于 2012-07-28T13:49:48.477 に答える