2

name、email、company_id、personType などのフィールドを含む Person テーブルを持つデータベース構造があります。すべての Person が必ずしもシステム ユーザーのものであるとは限らないため、システム内の User である Person の userName と password を定義する別のテーブル User があります。

Person テーブルのテーブル データ ゲートウェイを定義する次のコードがあります。

class Model_Table_Person extends Zend_Db_Table_Abstract
{
    protected $_name = 'person';
    protected $_primary = 'person_id';

    protected $_referenceMap = array(
        'Company' =>    array(
            'columns' => 'company_id',
            'refTableClass' => 'Company',
            'refColumns' => 'id'
        ),
        'Store' =>  array(
            'columns' => 'store_id',
            'refTableClass' => 'Store',
            'refColumns' => 'id'
        )
    );

    public function findByPersonType(string $personType)
    {
        $where = $this->getAdapter()->quoteInto('personType = ?', $personType);
        return $this->fetchAll($where);
    }
}

そして、このコードは Person のドメイン オブジェクトを定義します。

class Model_Person
{
    protected static $_gateway;

    protected $_person;

    public static function init()
    {
        if(self::$_gateway == null)
        {
            self::$_gateway = new Model_Table_Person();
        }
    }

    public static function get(string $searchString, string $searchType = 'id') 
    {
        self::init();

        switch($searchString)
        {
            case 'id':
                $row = self::$_gateway->find($id)->current();
                break;
        }

        return self::factory($row);
    }

    public static function getCollection(string $searchString, string $searchType = null)
    {
        self::init();

        switch($searchType)
        {
            case 'userType':
                $row = self::$_gateway->findByPersonType($searchString);
                break;
            default:
                $personRowset = self::$_gateway->fetchAll();
                break;
        }

        $personArray = array ();

        foreach ($personRowset as $person)
        {
            $personArray[] = self::factory($person);
        }

        return $personArray;
    }

    public function getCompany()
    {
        return $this->_person->findParentRow('Company');
    }

    public function getStore()
    {
        return $this->_person->findParentRow('Store');
    }

    protected static function factory(Zend_Db_Table_Row $row) 
    {
        $class = 'Model_Person_' . ucfirst($row->personType);
        return new $class($row);
    }

    // protected constructor can only be called from this class, e.g. factory()
    protected function __construct(Zend_Db_Table_Row $personRow)
    {
        $this->_person = $personRow;
    }
}

最後に、ユーザー用の別のテーブル データ ゲートウェイがあります。

class Model_Table_User extends Zend_Db_Table_Abstract
{
    protected $_name = 'user';
    protected $_primary = 'person_id';

    public function findByUserName()
    {

    }
}

そして、Model_Person テーブルを次のように拡張する基本クラス:

class Model_User extends Model_Person
{       
    public function login()
    {

    }

    public function setPassword()
    {

    }   
}

「Model_User」クラス (1 つを除く他のすべてのタイプのユーザーの基本タイプを提供する) を適切に拡張して、1 つのテーブルにマップする「Model_Person」クラス関数を使用すると同時に、実際の「Model_User」関数をマップして使用するにはどうすればよいですか?セカンドテーブル?

4

1 に答える 1

1

これは、PHP (バージョン 5.3.0 より前) の大きな弱点であり、最新の静的バインディングがサポートされていません。

つまり、 などの 1 つの静的メソッドが などget()の別の静的メソッドを呼び出すinit()場合、そのクラスで定義されたメソッドが常に使用されます。init()サブクラスが代替メソッドinit()を定義get()して を呼び出し、オーバーライドされたバージョンの を呼び出すことを期待している場合init()、これは発生しません。

class A
{
  static $var = null;
  static function init() { self::$var = 1234; }
  static function get() { self::init(); }
}

class B extends A
{
  static function init() { self::$var = 5678; }
}

B::get();
print B::$var . "\n"; 

これは「1234」と表示されますが、「5678」と表示されると思われるかもしれません。それA::get()がクラスの一部であることを知らないかのようBです。get()回避策として、スーパークラスと何も変わらない場合でも、メソッド の実装をサブクラスにコピーする必要があります。これは非常に不満です。

PHP 5.3.0 ではこれを修正しようとしていますが、次のように少し異なる方法でコーディングする必要がありますget()

function get() {
  static::init();
}

PHP 5.3.0 は現在まだアルファ版です。


考えられる回避策がいくつかあります。

  • Personas としてサブクラス化しないでください。User代わりに、 login および password 属性をPersonクラスに追加してください。これらの属性が NULL の場合、それは非ユーザーであり、関数はこれlogin()setPassword()注意して、例外をスローするか、false または何かを返す必要があります。

  • サブタイプごとに異なるget()メソッドを使用します: getUser()getPerson()など。これらはそれぞれ、独自のそれぞれの Table オブジェクトを初期化します。

于 2008-12-17T19:29:14.117 に答える