如何在Zend框架中优化模型?

7
我需要找出在Zend Framework中高效利用模型的最佳实践。
目前,我有一些类扩展了Zend_Db_Table_Abstract,用于处理每个类对应表的查询。
当我需要从一个控制器访问5个这样的表时,我发现自己需要创建5个每个具体的Zend_Db_Table对象的新实例。这非常低效。
我考虑过实现工厂模式来创建新实例(或提供现有静态副本),但不确定这是最好的方法。
确保速度而不消耗过多资源的正确方法是什么?这里应该使用惰性加载吗?
[编辑] 例如,我有一个类用于处理从原始搜索查询获取位置详细信息,并且需要这些对象以便解析查询:
// Initialize database object
$this->dbLocations = new Model_Locations;
$this->dbStates = new Model_States;
$this->dbZipcodes = new Model_Zipcodes;
$this->dbLookup = new Model_Lookup;

在另一个类中,我可能需要再次访问这些模型,因此我重复上述代码。本质上是重新初始化可能是静态/单例的对象。


1
你的问题比较模糊,能否展示一段代码示例,其中实际创建了5个表类的实例,并描述你需要它们做什么。 - markus
我理解你的担忧,但并不完全明白。在面向对象编程中,创建多个类实例,尤其是抽象类实例,是一件很常见的事情。对这个表格模型提出质疑,对我来说有点像质疑整个面向对象编程或继承的概念。 - Adrian World
在基本层面上,这种方法的使用是可以接受的。我有一个自定义的“处理程序”(缺乏更好的词语),它接收一个查询对象,解析其中的属性,并将其传递给一个位置处理程序,该处理程序获取该查询的所有位置数据,然后将其传递给Tide数据处理程序以及天气数据处理程序。在此过程的许多阶段中,我需要访问各种表格,并且经常从各种类中启动这些对象。请参见此处以获取更多信息:http://stackoverflow.com/questions/9116838/data-encapsulation-and-data-flow-in-php - Jeremy Harris
如果你非常担心创建太多的对象,那么你可以自由地使用 $db->query('SELECT * FROM tide'); ,而不是使用 Zend_Db_Table。这样只会留下一个对象。 - Adrian World
2个回答

3

我倾向于像您一样在DbTable上工作。当我需要在单个操作中查询多个表时,我发现在dbTable之上创建另一层模型是有效的。类似于服务或领域层。这样我只需要调用一个模型,但仍然拥有我需要的功能。

这里有一个简单的示例,可能会与5个DbTable类以及几个Row类交互:

<?php

class Application_Model_TrackInfo
{


    protected $_track;
    protected $_bidLocation;
    protected $_weekend;
    protected $_shift;
    protected $_station;

    public function __construct() {
        //assign DbTable models to properties for convience
        $this->_track = new Application_Model_DbTable_Track();

    }

    /**
     *
     * @param type $trackId
     * @return type object
     */
    public function getByTrackId($trackId) {

        $trackData = $this->_track->fetchRow($trackId);
        //getAllInfo() Application_Model_Row_TRack
        $result = $trackData->getAllInfo();
        //returns std object reflecting data from 3 DbTable classes
        return $result;
    }

    /**
     *Get Station from trackid through bidlocationid
     *
     * @param type $trackId
     * @return type object
     */
    public function getStation($trackId){

        $data = $this->_track->fetchRow($trackId);
        //This a Application_Model_Row_Track method
        $result= $data->getStationFromBidLocation();

        return $result;
    }

} 

我希望这能帮助到您。
[编辑] 自从我写下这个答案后,我已经学会了领域模型和数据映射的好处。哇,我的应用程序有了很大的改善。虽然不是万能药,但是确实是一个巨大的进步。
感谢
Alejandro Gervasio在PHPMaster.com上的帮助
Rob Allen在Akrabat.com上的帮助
以及
Pádraic Brady在Surviving The Deepend上的帮助。

他们帮助我理解了这种模式。


每次使用Application_Model_TrackInfo类时,它都会执行我有问题的操作。它创建可能被使用或者不被使用的dbTable对象,然后将其删除,下一次使用时又重新创建。这些dbTable连接应该在工厂模式中生成,还是多个并发实例是可以接受的开销? - Jeremy Harris
@cillosis 听起来你最好考虑缓存策略,这样可以最小化数据库查询。ORM(带有一些数据持久性)解决方案也可能是合适的。 - RockyFord

1

您似乎处于需要具备当前Zend框架所不具备的高效数据管理功能的位置。Zend没有内置用于处理任何类型数据库的引擎,它只有包装类来帮助您编写查询。

您需要的是一个对象关系模型(ORM),这是专业框架必备的。据我了解,ORM本身就是一个框架,它具有模式和强烈定义的“做事”方式,支持延迟加载(最大程度地利用它)并将您的查询优化到最佳状态。当您使用ORM时,甚至不需要编写SQL,而是需要改变对数据存储的解释,需要忘记表格并专注于对象。例如,在Doctrine中,每种类型(表格)由一个类指定,每个记录(行)作为一个类实例,您可以访问不同的方法和属性。它支持事件侦听器和疯狂的级联关系。

不再需要从相关表中提取行以删除记录(它是自动的),也不再需要编写复杂混乱的脚本来确保文件系统同步,您可以随时迁移到几乎任何数据库引擎(mysql、postgresql、simplesql等)等等。

我一直在使用Doctrine 2与Symfony 2框架,我必须说我不会回到Zend。是的,它很复杂和沉重,但确实是最终解决方案。当你需要管理数百个表格,总共有数百万条记录时,你就会看到差异。

所以,最终总结: ORM是你需要的,有许多解决方案,我知道两个真正好的:Doctrine 1或2和Propel。

P.S.:ORM是您系统中独立的部分,因此您不需要真正使用特定的框架,Zend可以配置为与Doctrine完美地配合使用 :)


4
Zend_Db本身就是ORM设计模式的一种实现。你的回答没有解决提问者真正的问题,只是告诉他根据你个人意见更换工具。你的第一段完全错误,这表明你在谈论你实际上并不了解的事情。 - markus
我没有写任何代码,因为目前问题中没有足够的信息可以编写答案。 - markus
它可能会保持这样,至少我的是一个可行的解决方案,即使不完全符合OP的要求。 - Tony Bogdanov
我目前不需要ORM的开销。但是,对于未来在SO上的研究,这个答案和评论可能会提供一些有用的见解。 - Jeremy Harris
@cillosis - 如何创建一个单例的dbTable容器,按需进行懒加载,并返回所需的模型?可以这样写:$this->dbLocations = My_DbContainer::getInstance()->getDbLocations() 然后依次类推。我从来没有这样做过,只是在问一下。 - bububaba
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接