2

我有一个数据库结构,其中包含一个 Person 表,其中包含名称、电子邮件、company_id、personType 等字段。因为不是所有的人都必须是系统用户的,所以我有一个单独的表用户,它为系统中的用户定义用户名和密码。

我有以下代码来定义人员表的表数据网关:

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”类(它为除一个以外的所有其他类型的用户提供基本类型)以使用映射到一个表的“Model_Person”类函数,同时还将实际的“Model_User”函​​数映射到使用第二张桌子?

4

1 回答 1

1

这是 PHP(5.3.0 之前的版本)的一个巨大弱点——它缺乏对后期静态绑定的支持。

也就是说,当一个静态方法如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 目前仍处于 alpha 版本。


有几种可能的解决方法:

  • 不要子类Person化为User,而是将登录名和密码属性添加到Person类中。如果这些属性是 NULL,那么它是一个非用户的人,并且函数login()应该setPassword()注意这一点并抛出异常或返回 false 或其他东西。

  • 对每个子类型使用不同的get()方法: getUser()getPerson()等。这些方法中的每一个都将初始化其各自的 Table 对象。

于 2008-12-17T19:29:14.117 回答