У меня есть текущая базовая структура для каждого объекта домена, который мне нужно создать:
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
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";
Вы можете переименовать базовый класс и его имена функций, если хотите пойти по этому пути. Но дело в том, что вы должны назвать дочерний класс в одном или другом месте: либо создайте шаблонную функцию в дочернем классе, как в моем первом примере, либо назовите класс в строке, как во втором примере.
И хотя наследование между статическими свойствами и методами было бы наиболее элегантным решением, по крайней мере, теперь методы get и getCollection в каждом классе ограничены одной строкой кода, а не большим количеством дублированного кода.
Еще раз спасибо, Билл. Я знаю, что вы упомянули позднее статическое связывание в предыдущем ответе, но только когда я начал рефакторинг кода, я понял, каковы последствия этого ограничения. Однако, глядя на ваше первое решение, оно кажется довольно интуитивным.