什么时候应该使用stdClass,什么时候应该在php oo代码中使用数组?


68

在工作中进行大量重构的中间,我希望引入stdClass *****作为从函数返回数据的一种方式,并且我试图找到非主观论据来支持我的决定。

在任何情况下,何时最好使用一种而不是另一种?

使用stdClass而不是数组有什么好处?


有人会说,函数必须尽可能少且特定,才能返回一个值。我决定使用stdClass是暂时的,因为从长远来看,我希望为每个进程找到正确的Value Objects。


请参阅:stackoverflow.com/questions/2056931/… 它没有回答我的问题。他说,“真正的”课堂是最好的方法,(我认为)我们都同意。我仍然想知道“何时”使用stdClass返回值比使用数组更好。
JonG

您可能需要澄清“价值对象”的概念。在DDD中,值对象是不可变的,其目的与Java中的VO
Gordon

@Gordon我的意思是,函数的“类似于VO”的返回准则。将VO作为(最好是)小物体,其中只有他的属性很重要,而不是他的身份。关于您的链接,您是否要找出对我来说(我的问题)有关“ VO应该是不可变的,而VO应该是可变的”的讨论很重要?顺便说一句,如今,VO是太阳的TO(传输对象)。java.sun.com/blueprints/corej2eepatterns/Patterns/...
JONG

我不确定的是您是否只是想解决PHP不支持多个返回值或其他问题的问题。是的,可变性重要吗?也许您正在寻找元组(例如Python)?
戈登

@戈登谢谢您的关注。如您刚才所说,我想我的问题主要集中在寻找一种“好的”方式(在OOP中)以将多个值作为函数调用的返回值传递。您认为我应该编辑我的问题,否则此评论会起作用吗?
JonG 2010年

Answers:


62

通常的方法是

  • 返回带有固定分支的已定义数据结构时,请使用对象:

     $person
       -> name = "John"
       -> surname = "Miller"
       -> address = "123 Fake St"
    
  • 返回列表时使用数组:

      "John Miller"
      "Peter Miller"
      "Josh Swanson"
      "Harry Miller"
    
  • 返回结构化信息列表时,使用对象数组:

      $person[0]
        -> name = "John"
        -> surname = "Miller"
        -> address = "123 Fake St"
    
      $person[1]
        -> name = "Peter"
        -> surname = "Miller"
        -> address = "345 High St"
    

对象不适合保存数据列表,因为您始终需要一个密钥来寻址它们。数组可以同时实现两个功能-容纳任意列表和数据结构。

因此,如果需要,您可以在第一个和第三个示例中对对象使用关联数组。我会说,这实际上只是样式和偏好的问题。

@Deceze在何时使用对象方面有很多好处(验证,类型检查和将来的方法)。


我真的很喜欢/同意参数1和
2。– JonG

1
我要求“非主观”论点。可悲的是,没有给出任何消息。我坚持您的回答(跟随他人的投票),因为它显示了从现在开始我将继续遵循的内容:数组用于列表;数组用于列表;列表用于列表。stdClass用于“多值” /属性。
JonG 2010年

12
我对此表示强烈反对。如果您只有数据,甚至是结构化数据,那么您应该使用数组。对象是数据和相关行为的打包。使用stdClass作为数组只是滥用stdClass。
GordonM 2012年

4
同意GordonM,通过使用stdClass错觉适当的对象会带来更多的伤害,然后再造成伤害。在我看到stdClass使用的几乎所有情况下,它总是在滥用动态属性-这使类具有什么样的结构非常混乱,并且即使尊重该结构,因为几乎每次使用它都涉及“动态”填充属性。如果您可能会错过属性或不愿意创建一个实际的类,那么不妨使用数组。
srcspider 2013年

不是客观的答案。
William Entriken 2014年

42

使用stdClass实现相同功能的阵列是不是很有用恕我直言,它只是增加了一个对象的开销,没有任何实际的好处。您还会错过许多有用的数组函数(例如array_intersect)。您至少应该创建自己的类以启用类型检查,或至少向对象添加方法以使其值得使用对象。


1
我特别喜欢/同意您所说的“向对象添加方法以使其值得使用”的说法。
JonG

18

我不认为使用stdClass而不是数组有任何合理的优势,只要您的唯一意图是从函数调用中返回多个任意数据类型

由于从技术上讲不能从本地返回多个值,因此必须使用可以容纳PHP中所有其他数据类型的容器。那将是一个对象或一个数组。

function fn1() { return array(1,2); }
function fn2() { return array('one' => 1, 'two' => 2); }
function fn3() { return (object) array(1,2); }
function fn4() { return (object) array('one' => 1, 'two' => 2); }

以上所有方法均有效。数组是一个很小的微不足道的部分,速度更快,打字工作更少。与通用stdClass相比,它还有一个明确定义的目的(有点麻烦,不是吗)。两者都只有一个隐式接口,因此您必须查看文档或函数体以了解它们将包含什么。

如果您想不惜任何代价使用对象,则可以使用ArrayObjectSplFixedArray,但是如果您查看它们的API,您会说需要它们的功能来完成返回随机多个值的简单任务吗?我不这么认为。但是请不要误会我的意思:如果要使用stdClass,请使用它。它不会破坏任何东西。但是您也不会获得任何收益。为了至少增加一些好处,您可以为此创建一个单独的名为ReturnValues的类。

可能是简单的标记类

class ReturnValues {}

或更实用的功能

class ReturnValues implements Countable
{
    protected $values;
    public function __construct() { $this->values = func_get_args(); }
    public function __get($key) return $this->values[$key]; }
    public function count() { return count($this->values); }
}

当然,它并没有做很多事情,并且仍然可以通过一个隐式接口来获取其价值,但至少现在该类具有更明确定义的职责。您可以从此类扩展以为特定操作创建ReturnValue对象,并为它们提供一个显式接口:

class FooReturnValues extends ReturnValues
{
    public function getFoo() { return $this->values['foo']; }
    public function getBar() { return $this->values['foo']; }
}

现在,开发人员只需查看API即可知道foo()将返回哪个值。当然,必须为每个可能返回多个值的操作编写具体的ReturnValue类,可能很快就会变得乏味。就个人而言,我发现这是出于最初目的而过度设计的。

无论如何,希望这是有道理的。


1
您的“ ReturnValues”提案有趣。
JonG

@JonG谢谢。我猜想我的两个主要要点是:使返回的对象在语义上更清晰,并使其接口明确。如果这些都不重要,那么走那条路线imo真的没有用。
戈登

我喜欢泛型但在特定领域/用途内具有泛型的类的想法。它有可能真正增加功能,而stdClass仅是关联数组的替代表示。
IMSoP 2014年

我认为稍微可读性强的语法是大多数开发人员的主要好处。但是,使用$options = ['a'=>'str', 'b'=>'str'];几乎一样优雅,并允许为数组构建许多本机/强大的功能。因此,除非需要匹配JSON结构,否则我会坚持使用数组。
贾斯汀

4

好吧,这里有3个区别:

  • 他们有一个身份。这就是为什么传递数组参数的默认按值调用,而对象的默认通过共享调用
  • 在语义上有区别。如果使用对象,则任何读取代码的人都会理解,该值表示模型具有某种实体性,而数组则应充当集合或映射
  • 最后但并非最不重要的一点是,重构变得非常容易。如果要使用具体的类而不是stdClass,则要做的就是实例化另一个类。这也允许您添加方法。

greetz
back2dos


2

我能找到的唯一的目标信任票是:

json_decode 默认情况下使用stdClass,因此在类似情况下,userland中的凡人应该使用stdClass。


4
json_decode($json, true);如果您要获取数组而不是对象,则可以使用
彼得

1
我们在userland中的凡人不会“只是”覆盖默认参数值。
tishma '16

1

当我需要保持代码整洁和有点句子可读性时,我发现数组上的stdClass对象很有用。以getProperties()返回一个属性集的函数为例,例如关于一个人的数据(姓名,年龄,性别)。如果getProperties()要返回一个关联数组,则当您要使用返回的属性之一时,应编写两条指令:

$data = getProperties();
echo $data['name'];

另一方面,如果getProperties()返回stdClass,则可以只用一条指令编写它:

echo getProperties()->name;

4
请注意,如果您使用的是PHP 5.4或更高版本,则不再适用,因为这只是PHP解析器的一个缺点。您现在可以编写echo getProperties()['name']; 3v4l.org/t6i0r
IMSoP,2014年

@IMSoP,可以,除了许多系统仍使用PHP 5.3之外,这将引发错误,使某些开发人员感到困惑:)。
musicliftsme 2014年

2
@laketuna是的,因此在我的评论中是“ if” :)还请注意,现在正式不支持5.3,因此人们应该麻烦
IMSoP 2014年

1

在数组与stdclass的测试中,php处理动态属性的方式要比关联数组慢。我并不是说这是在争论微优化,而是如果您打算这样做,最好定义没有方法的数据类并设置公共属性。Esp,如果您使用的是php 5.4+。在幕后,定义的属性直接映射到没有散列表的ac数组,而动态列表则需要使用散列表。

这样做的好处是,以后无需进行任何主要的界面修改即可成为完整的类。


PHP的性能特征随每个版本而变化。
William Entriken '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.