Рефакторинг для удаления статических методов Code Smell - PullRequest
4 голосов
/ 24 декабря 2008

У меня есть текущая базовая структура для каждого объекта домена, который мне нужно создать:

class Model_Company extends LP_Model
{   
    protected static $_gatewayName = 'Model_Table_Company';
    protected static $_gateway;
    protected static $_class;

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

    public static function get() 
    {
        self::init();

        $param = func_get_arg(0);

        if($param instanceof Zend_Db_Table_Row_Abstract)
        {
            $row = $param;
        }
        elseif(is_numeric($param))
        {
            $row = self::$_gateway->find($param)->current();
        }

        return new self::$_class($row);
    }

    public static function getCollection()
    {
        self::init();

        $param = func_get_arg(0);

        if($param instanceof Zend_Db_Table_Rowset_Abstract)
        {
            $rowset = $param;
        }
        elseif(!$param)
        {
            $rowset = self::$_gateway->fetchAll();
        }

        $array = array ();      

        foreach ($rowset as $row)
        {
            $array[] = new self::$_class($row);
        }

        return $array;
    }
}

Первоначально я пытался реорганизовать статические методы в родительский класс LP_Model только для того, чтобы наконец узнать, что означает "позднее статическое связывание" в мире php.

Мне просто интересно, есть ли у кого-нибудь предложения о том, как реорганизовать этот код, чтобы мне не пришлось повторно объявлять те же три функции в каждом объекте домена, который я создаю?

1 Ответ

3 голосов
/ 25 декабря 2008

Как насчет этого:

<?php

abstract class Model_Abstract
{
    protected $_gatewayName = null;
    protected $_gateway = null;

    protected function _init()
    {
        $this->_gateway = new $this->_gatewayName();
    }

    protected function __construct($row = null)
    {
        $this->_init();
        if ($row) {
            $this->_data = $row;
        }
    }

    public static function getAbstract($class, $param)
    {
        $model = new $class();
        if($param instanceof Zend_Db_Table_Row_Abstract)
        {
                $row = $param;
        }
        elseif(is_numeric($param))
        {
                $row = $model->_gateway->find($param)->current();
        }

        return new $class($row);
    }

    public static function getAbstractCollection($class, $param = null)
    {
        $model = new $class();
        if($param instanceof Zend_Db_Table_Rowset_Abstract)
        {
                $rowset = $param;
        }
        elseif($param === null)
        {
                $rowset = $model->_gateway->fetchAll();
        }

        $array = array ();

        foreach ($rowset as $row)
        {
                $array[] = new $class($row);
        }

        return $array;
    }

    abstract public static function get($param);
    abstract public static function getCollection($param = null);
}

class Model_Company extends Model_Abstract
{
    protected $_gatewayName = 'Model_Table_Company';

    public static function get($param) {
        return self::getAbstract(__CLASS__, $param);
    }

    public static function getCollection($param = null) {
        return self::getAbstractCollection(__CLASS__, $param);
    }
}

class Model_Table_Company extends Zend_Db_Table_Abstract
{
    protected $_name = 'company';
}

$model = Model_Company::get(1);
print "Got an object of type ".get_class($model)."\n";

$models = Model_Company::getCollection();
print "Got ".count($models)." objects of type ".get_class($models[0])."\n";

?>

К сожалению, для упрощения вызова функций необходимо дублировать get() и getCollection() в каждом подклассе. Другой вариант - вызвать функцию в родительском классе:

$model = Model_Abstract::getAbstract('Model_Company', 1);
print "Got an object of type ".get_class($model)."\n";

$models = Model_Abstract::getAbstractCollection('Model_Company');
print "Got ".count($models)." objects of type ".get_class($models[0])."\n";

Вы можете переименовать базовый класс и имена его функций, если хотите идти по этому пути. Но дело в том, что вы должны назвать дочерний класс в одном месте или в другом : либо создать шаблонную функцию в дочернем классе, как в моем первом примере, либо назвать класс в строке, как в моем Второй пример.

...