【问题标题】:When should I use stdClass and when should I use an array in php oo code?什么时候应该使用 stdClass,什么时候应该在 php oo 代码中使用数组?
【发布时间】:2011-03-12 17:56:49
【问题描述】:

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

在什么情况下最好使用一种代替另一种??

使用 stdClass 代替数组有什么好处??


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

【问题讨论】:

  • 见:stackoverflow.com/questions/2056931/… 它没有回答我的问题。他说“真正的”课程将是最好的方法,(我认为)我们都同意。我仍然想知道“何时”使用 stdClass 返回值比使用数组更好。
  • 你可能想澄清你的值对象的概念。 In DDD a Value Object is immutableVOs in Java. 的目的完全不同
  • @Gordon 我的意思是,一个“类似VO”的函数返回指南。将 VO 作为(最好)小对象,其中只有他的属性很重要,而不是他的身份。关于您的链接,您是否试图找出对我(我的问题)关于“VO 应该是不可变的 Vs VO 可以是可变的”的讨论是否重要?顺便说一句,现在 VO 是太阳的 TO(传输对象)。 java.sun.com/blueprints/corej2eepatterns/Patterns/…
  • 我还不确定你是否只是想解决 PHP 不支持多个返回值的问题或其他问题。是的,可变性重要吗?也许您正在寻找元组(例如在 Python 中)?
  • @Gordon 感谢您的关注。正如你刚才所说,我想我的问题主要集中在寻找一种“好”的方式(在 OOP 中)来传递多个值作为函数调用的返回。你认为我应该编辑我的问题还是这个 cmets 可以完成这项工作?

标签: php oop stdclass


【解决方案1】:

在数组与标准类的测试中,php 处理动态属性的方式比关联数组慢。我这样说并不是为了争论微优化,而是如果你要这样做,最好定义一个没有方法的数据类并设置公共属性。特别是如果您使用的是 php 5.4+。在引擎盖下定义的属性直接映射到没有哈希表的 c 数组,而动态属性需要使用哈希表。

这有一个额外的好处,那就是以后成为一个完整的类,而无需任何主要的界面改造。

【讨论】:

  • PHP的性能特点随着每个版本的变化而变化。
【解决方案2】:

我能找到的唯一客观的信任票是:

json_decode默认使用stdClass,所以我们凡人在userland应该使用stdClass来处理类似的情况。

【讨论】:

  • 如果你想获取数组而不是对象,你可以使用json_decode($json, true);
  • 我们在用户空间中的凡人不会“只是”覆盖默认参数值。
【解决方案3】:

当我需要保持我的代码干净并且有点类似句子的可读性时,我发现数组上的 stdClass 对象很有用。以函数getProperties() 为例,它返回一组属性,比如关于一个人的数据(姓名、年龄、性别)。如果getProperties() 会返回一个关联数组,那么当您想使用其中一个返回的属性时,您将编写两条指令:

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

另一方面,如果getProperties() 返回一个stdClass,那么你可以只在一条指令中编写它:

echo getProperties()->name;

【讨论】:

  • 请注意,如果您使用的是 PHP 5.4 或更高版本,这将不再适用,因为这只是 PHP 解析器的一个缺点。你现在可以写echo getProperties()['name'];3v4l.org/t6i0r
  • @IMSoP,你可以,除了很多系统仍然使用 PHP 5.3,它会抛出一个错误,这会让一些开发人员感到困惑:)。
  • @laketuna 是的,因此我的评论中出现了“如果” :) 另请注意,现在正式不支持 5.3,因此人们应该纠缠他们的主机/管理员升级:php.net/eol.php
【解决方案4】:

只要您的唯一目的是从函数调用中返回多个任意数据类型,我认为使用 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 类可能会很快变得乏味。就个人而言,我发现这在最初的目的上被过度设计了。

无论如何,希望这有意义。

【讨论】:

  • 对您的“ReturnValues”提案感兴趣。
  • @JonG 谢谢。我想我的两个要点是:使返回的对象在语义上更清晰,并使其接口明确。如果这些都不重要,那么走这条路真的没用。
  • 我喜欢这个类的想法,它是通用的,但在特定领域/用途中是通用的。它具有实际增加功能的潜力,而stdClass 只不过是关联数组的一种替代表示。
  • 我认为更易读的语法是大多数开发人员的主要好处。然而,使用$options = ['a'=>'str', 'b'=>'str']; 几乎同样优雅,并允许为数组构建许多本机/强大的函数。所以我坚持使用数组,除非我需要匹配 JSON 结构。
【解决方案5】:

嗯,有3个不同:

  • 他们有一个身份。这就是为什么传递数组参数的默认值是按值调用,而对象按共享调用
  • 存在语义差异。如果你使用一个对象,任何读过代码的人都会明白,这个值代表了某种实体的模型,而数组应该充当集合或映射
  • 最后但同样重要的是,重构变得非常容易。如果你想使用一个具体的类而不是 stdClass,你所要做的就是实例化另一个类。它还允许您添加方法。

问候
back2dos

【讨论】:

    【解决方案6】:

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

    【讨论】:

    • 我特别喜欢/同意你所说的“向对象添加方法以使其值得使用”。
    【解决方案7】:

    通常的做法是

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

       $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 个论点。
    • 我要求提供“非主观”论据。可悲的是,没有给出。我坚持你的回答(根据其他人的投票),因为它显示了我从现在开始将继续遵循的内容:数组用于列表; “多值”/属性的 stdClass。
    • 我强烈反对这一点。如果您只有数据,甚至是结构化数据,那么您应该使用数组。对象是数据和相关行为的包。使用 stdClass 作为数组简直就是滥用 stdClass。
    • 同意 GordonM,使用 stdClass 产生正确对象的错觉弊大于利。几乎我看到 stdClass 使用它的所有情况都在滥用动态属性——它非常混淆类的结构,即使该结构受到尊重,因为几乎每次使用它都涉及“动态”填充属性。如果您可能会错过属性或懒得创建一个实际的类,不妨使用数组。
    • 不是一个客观的答案。
    猜你喜欢
    • 2023-04-02
    • 2011-04-15
    • 2017-04-10
    • 2012-03-19
    • 2018-05-12
    • 2018-12-11
    • 1970-01-01
    • 2022-09-28
    • 2021-09-07
    相关资源
    最近更新 更多