1

PHPとOOPは初めてなので、我慢してください...私は、生涯にわたってくだらないM $ VBAのゴミを書いた後、最初のPHPとOOPのWebサイトを設計および作成する楽観的な初期段階にあります。

関連するデータベース呼び出しなどを含むsaveメソッドを持つクラス「User」があります(実際には、接続とCRUDを処理するDBクラスとDBUtilsクラスがあります-私のビジネスクラスは、DB Utilsのselect、update、deleteメソッドを呼び出すだけですデータの連想配列を渡します)

Anywho...私の"User"クラスは、 "User" yadayada...に加えていくつかの追加プロパティを持つ"Admin"クラスによって拡張されています。

「管理者」のsaveメソッドを処理するための最良の方法は何ですか?Adminクラスにsaveメソッドを追加すると、Userのメソッドよりも優先されることを理解していますが、そうしたくありません。Adminでsaveメソッドを記述して、Adminオブジェクトに固有のプロパティなどのみを処理し、「User」から継承されたプロパティをUsersaveメソッドで処理するようにします。

それは理にかなっていますか?それは私が探している特定のOOPパターンですか?このコードをどのように設計および構造化するかについてのヘルプまたはガイダンスをいただければ幸いです。

編集:おっ!以下のすべての回答に感謝します。どちらが私の好みかはまだわかりません。私はいくつか遊んでいなければならないでしょう...

4

5 に答える 5

5

あなたの主な問題は、OOPのコアアイデアの1つである単一責任の原則を無視しているという事実から生じています。繰り返しになりますが、「回答」を提供したすべての人がSRPが何であるかを知らないようです。

「ビジネスロジック」と呼ぶものは、ストレージ関連の操作とは別にしておく必要があります。Usernoのインスタンスも、Adminビジネスロジックではないため、ストレージがどのように実行されるかを認識してはなりません。

$entity = new Admin;
$mapper = new AdminMapper( $db );

$entity->setName('Wintermute');
$mapper->fetch( $entity ); 
//retrieve data for admin with that name

$entity->setName('Neuromancer');
$mapper->store( $entity );
// rename and save

上に表示されているのは、データマッパーパターンの非常に単純化されたアプリケーションです。このパターンの目標は、ビジネスロジックとストレージロジックを分離することです。

マッパーを直接インスタンス化する代わりに、注入されたファクトリ$mapper = new AdminMapper( $db )によって提供される場合(適切なコードベースにあるはずなので)、ストレージメディアについての表示はありません。データは、SQL DBまたはファイル、あるいはリモートRESTAPIのいずれかに保存できます。マッパーのインターフェースが同じであれば、必要なときにいつでも交換できます。$mapper = $this->mapperFactory->build('Admin')

ファクトリを使用すると、特定のクラス名との緊密な結合を回避でき、SQLデータベースのマッパーの場合は、すべてのインスタンスに同じDB接続を挿入できます。

それについてもう少し学ぶために、あなたはこれこれこれを読むことができます。

しかし、OOPの勉強を真剣に考えているのであれば、この本を読むことは必須です。

于 2012-09-24T21:46:35.200 に答える
3

ActiveRecordパターンを実装しようとしています。

オブジェクトの永続性におけるアプローチは、すべてのサブクラスが拡張する共通の祖先クラスを提供することBasicEntityです。これにより、特定のデータスキーマに基づいてクエリが構築されます。

class BasicEntity
{

    protected $tablename;

    protected $schema;

    public function update()
    {

        $fields = "";
        $placeholders = "";

        foreach($this -> schema as $field => $type)
        {

            // you join the fields here to get something like ('username', 'email', 'enabled', 'createdAt', 'password')
            // then you write your PDO statement providing placeholders like (:?, :?, :?, :?, :?)
            // you'll have to bind parameters based on their $type [int, string, date]

        }

        $query = sprintf(
            "UPDATE %s SET VALUES(%s) = %s",
            $this -> tablename,
            $fields,
            $placeholders
        );

        // execute statement here, handle exceptions, and so...

    }

}

したがって、Userクラスは次のようになります。

class User extends BasicEntity
{

    protected $id;
    protected $username;
    protected $email;
    protected $password;
    protected $enabled;
    protected $createdAt;

    public function __construct()
    {

        $this -> tablename = '_user';
        $this -> schema = array(
            'id'        => 'int',
            'username'  => 'string',
            'email'     => 'string',
            'password'  => 'string',
            'enabled'   => 'int',
            'createdAt' => 'datetime'
        );

    }

}

そしてあなたのAdminクラス:

class Admin extends User
{

    protected $additionalProperty;

    public function __construct()
    {

        parent::__construct();

        $this -> schema['additionalProperty'] = 'string';

    }

}

を呼び出すupdate()と、クラススキーマに基づいて適切なクエリが作成されます。このアプローチは、次のことに気付くため、複雑度の低いレベルで機能します。

  • [同じテーブル上で]エンティティを拡張する場合は、そのようなクラスフィールドがない行に対しても空のテーブルフィールドを提供する必要があります[この場合additionalProperty]。
  • スキーマが変更された場合(たとえば、変数名を変更した場合)、スキーマをクラスコンストラクターにハードコーディングする必要があり、保守が困難になります。
  • エンティティ間の関係を処理する場合は、多くの個別のクエリを記述してパフォーマンスを低下させない限り、すべてのSELECTステートメントに適切な結合を記述するのは非常に困難です。

最初の問題を解決するには、オブジェクトの構成が必要なので、メインテーブルをあまり大きくしないでください[AdditionalPropertyListたとえば、外部エンティティへの参照を取得するだけです]。

2番目を解決するには、スキーマを外部ファイルに保持するか、インラインアノテーションを使用する必要があります。

3番目を解決するには、独自のORM [ Object Relational Mapping ]を作成するか、既存のORMに切り替える必要があります。

とにかく、学習のメリットから、私は巨人の肩の上に立って、スケーラブルで保守可能なアプリケーションを構築することを計画している場合は、フレームワークを選択します。

于 2012-09-24T12:13:06.537 に答える
3

Adminクラスでsaveメソッドを作成すると、標準の保存のために親オブジェクトに延期した後、追加の作業を実行できます...

class Admin extends User
{
    // Other methods

    public function save()
    {
        parent::save();
        // now save your additional fields wherever they need to go
    }
}

ちなみに、ユーザーや管理者などのドメインを表すためにオブジェクトを使用する場合は問題ありません。たとえば、リポジトリパターンを使用するなどして、他の場所に永続性ロジックを設定することでメリットが得られる場合があります。これにより、オブジェクトが永続メカニズムに関連付けられるのを防ぎます。

于 2012-09-24T11:46:27.923 に答える
2

この問題を解決する方法はたくさんあります。それらの1つは、拡張クラスでオーバーライドして、その拡張クラスからのデータを提供できる保護されたメソッドを持っていることです。

例:

class User
{
  public function Save()
  {
    $savestuff = $this->GetProperties();
    // do save acctions
  }

  protected function GetProperties()
  {
    return 'user prop';
  }
}

class Admin Extends User
{
  protected function GetProperties()
  {
    return  'admin prop';
  }
} 
于 2012-09-24T11:46:47.990 に答える
1

OOは初めてですが、PHPのオブジェクトモデルの主な欠点の1つにぶつかったように聞こえます。あなたがしたいことは、メソッドのオーバーロードによって簡単に達成できます(同じ名前の複数のメソッドを持つことができますが、異なるパラメーターを取り、呼び出される実際のメンバー関数はパラメーターによって異なります)。

この問題を回避するには、クラスのsaveメソッドのパラメーターを確認します。Admin

class Admin
{
    public function save(Model_Abstract $model = null)//type hinting
    {
        if ($model instanceof Model_Admin)
        {
            //do admin insert/update stuff here
            return;
        }
        parent::save($model);//call regular method
    }
}
于 2012-09-24T11:51:28.510 に答える