【问题标题】:Database results as objects or arrays?数据库结果是对象还是数组?
【发布时间】:2012-12-17 08:18:44
【问题描述】:

这个问题类似于Mysql results in PHP - arrays or objects? 但是,我的问题扩展了那里讨论的内容。

我正在尝试确定哪种格式更适合处理数据库结果:对象或数组。我不关心性能(据我所知,这没什么区别)。我的重点还在于显示结果,而不是创建、更新或删除结果。

迄今为止,我一直通过 mysqli_fetch_object 或 PDO 的 fetchObject 等函数使用对象。这通常工作得很好,直到我开始做连接。连接会导致奇怪的对象,这些对象是来自两个或多个表的字段的混合。我的代码很快开始变得混乱。

我应该注意,我正在分配特定的类名,而不是坚持使用默认的 stdClass。我这样做是为了可以访问我在类中创建的任何辅助方法。例如:

foreach ($members as $member)
{
    echo $member->full_name();
    echo $member->age();
}

为了清楚起见,我正在考虑将所有数据库结果转移到数组中。从我读到的其他人也这样做。但是,这让我无法轻松访问我的辅助方法。

使用上面的例子,我想我可以只输出名字和姓氏,而不是使用full_name() 方法,没什么大不了的。至于age() 方法,我想我可以创建一个通用的实用程序类并将其放入其中。

我的问题:

  1. 如果使用(模型)对象,如何处理连接?
  2. 如果使用数组,如何处理辅助方法?

【问题讨论】:

  • 这是个人喜好问题,但我更喜欢在处理来自数据库的数据时处理数组,然后在需要时使用该数据创建对象。我宁愿使用我定义的方法创建对象,也不愿使用 DB 扩展附带的方法。
  • 为什么不两者兼而有之? $sth->fetch(PDO::FETCH_LAZY); 然后是最适合您正在编写的代码的访问器。
  • @DudeSolutions 这种方法很有意义。那么,你是说如果你想访问你的帮助方法之一,你会在那个时候创建​​实际的对象吗?看起来像是额外的工作,但我可以看到在数据库结果和真实对象之间创建了一个很好的区别。
  • @Jonathan 如果您需要将数据作为对象才能访问您的辅助方法,那么可以。实际上,这基本上是框架试图解决的众多问题之一的核心——我应该何时何地访问 X 辅助方法。没有正确的答案,只要它有效且可维护。
  • @Sammitch 不错的主意!

标签: php mysql


【解决方案1】:

我一直使用对象 - 但我不会直接从查询中放入数据。使用“设置”函数我创建了布局,因此避免了连接和命名冲突的问题。在您的“full_name”示例中,我可能会使用“as”来获取名称部分,在对象中设置每个部分并提供“get_full_name”作为成员 fn。

如果您有雄心壮志,您可以在“get_age”中添加各种内容。设置一次出生日期,然后从那里开始。

编辑: 有几种方法可以从数据中创建对象。您可以预定义类并创建对象,也可以“即时”创建它们。

--> 一些简化的例子——如果这还不够,我可以添加更多。

即时:

$conn = DBConnection::_getSubjectsDB();  
$query = "select * from studies where Status = 1";  
$st = $conn->prepare( $query );  

$st->execute();  
$rows = $st->fetchAll();  
foreach ( $rows as $row )  
{  
    $study = (object)array();  
    $study->StudyId = $row[ 'StudyId' ];  
    $study->Name = $row[ 'StudyName' ];  
    $study->Investigator = $row[ 'Investigator' ];  
    $study->StartDate = $row[ 'StartDate' ];  
    $study->EndDate = $row[ 'EndDate' ];  
    $study->IRB = $row[ 'IRB' ];  

    array_push( $ret, $study );  
} 

预定义:

/** Single location info
*/
class Location  
{  
    /** Name  
    * @var string  
    */  
    public $Name;  

    /** Address  
    * @var string  
    */  
    public $Address;  

    /** City  
    * @var string  
    */  
    public $City;

    /** State
    * @var string
    */
    public $State;

    /** Zip
    * @var string
    */
    public $Zip;

    /** getMailing
    * Get a 'mailing label' style output
    */
    function getMailing()
    {  
         return $Name . "\n" . $Address . "\n" . $City . "," . $State . "  " . $Zip;
    }
}

用法:

$conn = DBConnection::_getLocationsDB();  
$query = "select * from Locations where Status = 1";  
$st = $conn->prepare( $query );  

$st->execute();  
$rows = $st->fetchAll();  
foreach ( $rows as $row )  
{  
    $location = new Location();  
    $location->Name= $row[ 'Name' ];  
    $location->Address = $row[ 'Address ' ];  
    $location->City = $row[ 'City' ];  
    $location->State = $row[ 'State ' ];  
    $location->Zip = $row[ 'Zip ' ];  

    array_push( $ret, $location );  
} 

然后你可以循环 $ret 并输出邮件标签:

foreach( $ret as $location )
{ 
    echo $location->getMailing();
}

【讨论】:

  • 您介意添加一些代码来更好地说明您的方法吗?
  • 感谢您提供代码!那么,如果你做了一个JOIN,你会简单地创建两个对象而不是一个对象吗?
  • 另外,这种方法不会为您带来很多额外的工作吗?您不只是使用数据库类中的数组/对象,而是手动浏览每个结果集。还是只在需要微调时才这样做?
  • 投票赞成:琐碎的 ORM 看起来可以节省时间,但 IME 处理复杂系统是一场噩梦 - 无论是在初始实施和维护中 - 使用工厂可以节省大量的痛苦和时间。跨度>
  • 不错的答案。然而,$study = (object)array(); 是一种相当丑陋的说法 $study = new stdClass();
【解决方案2】:

这是一天结束时的偏好。就个人而言,我更喜欢对象。尽管 CakePHP 使用数组作为结果,使用“对象”名称作为数组键。但是,当您在 CakePHP 中获取相关记录时,事情开始变得有趣。

对于您的问题,您可以简单地在对象中包含对象。例如:

stdClass Object
(
    [id] => 1
    [title] => Article Title
    [published] => 2013-03-04 16:30:00
    [category] => stdClass Object
        (
            [id] => 1
            [name] => Category Name
        )

)

然后您可以在视图中显示相关数据,如下所示:

<?php echo $article->category->name; ?>

或者如果你使用 getter 和 setter:

<?php echo $article->getCategory()->getName(); ?>

没有正确或错误的答案。正如我所说,这完全是个人喜好。

【讨论】:

  • 我喜欢 Martin 的这种方法,但这不可能发生在一个数据库查询中,这对我来说非常重要。连接中的额外字段将添加到父 object,而不是 parameter。我现在正在开展一个更大规模的项目,我真的看到了不必要的额外查询的负面影响。除非我错过了什么?再次感谢。
  • 有可能; CakePHP 设法在一个查询中做到这一点(仅使用数组而不是对象)。您可以将结果分配给填充正确属性和“子”对象的模型。
  • 有趣,他们必须在他们的 ORM 中这样做,类似于 @ethrbunny 的建议。
【解决方案3】:

我认为最好以模型的形式表示您的所有数据及其类型。对于连接对象和单个对象。这样做总是会忽略你的问题。

class Member_Details {
    public $id;    
    public $first_name;
    public $last_name;

    public function FullName() {
         return $this -> first_name." ".$this -> last_name;
    }
}

class Member_Address {
    public $id;
    public $address;
    public $city;
}

class MemberJoins {
     public $objects = array();
}

创建此类类后,您可以通过以下方式配置 JOIN。

$obj_details = new Member_Details();
$obj_address = new Member_Address();
//Add data to the objects and then

//Then create the join object
$obj_address_details = new MemberJoins();
$obj_address_details -> objects = array($obj_details, $obj_address);

它们都有一个共同的属性id,可以从中链接其数据。

【讨论】:

  • Starx:感谢您的回答。但是,当从数据库运行 SELECT 时,这会起作用吗?我想我的问题还不够清楚。我真的很想运行一个查询,它可能包括连接(出于性能原因)。然后,在查询完成后,我不确定使用数据的最佳方式是 - 作为数组还是作为对象。
  • @Jonathan,然后您必须创建组合模型类并按自己的方式工作。
【解决方案4】:

认为您说的是在两个或多个表上使用 SELECT 出现的奇怪对象。

我通过在我的 sql 中使用 AS 给它一个更简单的名称来解决这个问题。

SELECT IFNULL(SUM(table2.big_name),0) AS sumBig

...


$result=$PDO->fetchObject();
$sum=$result->sumBig;

【讨论】:

  • 并非如此。我经常使用AS,但我仍然被一个包含不属于它的参数的对象所困扰。更新:但感谢您的回复。 ;)
猜你喜欢
  • 2013-05-18
  • 1970-01-01
  • 2017-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多