Рефакторинг для удаления запаха кода статических методов

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

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.

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
4
0
1 839
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

<?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";

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

Еще раз спасибо, Билл. Я знаю, что вы упомянули позднее статическое связывание в предыдущем ответе, но только когда я начал рефакторинг кода, я понял, каковы последствия этого ограничения. Однако, глядя на ваше первое решение, оно кажется довольно интуитивным.

Noah Goodrich 25.12.2008 02:19

И хотя наследование между статическими свойствами и методами было бы наиболее элегантным решением, по крайней мере, теперь методы get и getCollection в каждом классе ограничены одной строкой кода, а не большим количеством дублированного кода.

Noah Goodrich 25.12.2008 02:23

Другие вопросы по теме