PHP:什么时候使用数组,什么时候将对象用于大多数数据存储的代码构造?


37

PHP是一种混合范式语言,允许使用和返回非对象数据类型,例如数组。我提出一个问题,试图在确定在特定情况下使用哪种编程构造时,阐明一些选择数组还是对象的准则。

这实际上是一个有关使用PHP语言构造对数据进行编码的方法以及何时更可能为了数据传递目的而选择另一种方法(即面向服务的体系结构或Web服务)的问题。

假设您的商品类型由{cost,name,part_number,item_count}组成。您的程序要求显示几种此类项目,并决定使用数组作为外部容器来保存每种项目类型。[您也可以使用PHP的ArrayObjectOO范例,但是我的问题不是关于那个(外部)数组的]。我的问题是关于如何对项目类型数据进行编码,以及使用哪种范式。PHP允许您使用PHP Native ArraysPHP Objects

我可以通过两种方式对此类数据进行编码,如下所示:

//PHP's associative arrays:
$ret = array(
    0 => array(
        'cost' => 10.00, 
        'name' => 'item1',
        'part_number' => 'zyz-100', 
        'item_count' => 15
        ),
    1 => array(
        'cost' => 34.00, 
        'name' => 'item2', 
        'part_number' => 'abc-230', 
        'item_count' => 42
        ),
  );

//here ItemType is encapsulated into an object
$ret = array(
  0 => new ItemType(10.00, 'item1', 'zyz-100', 15),
  1 => new ItemType(34.00, 'item2', 'abc-230', 42),
);

class ItemType
{
    private $price;
    private $name;
    private $partNumber;
    private $itemCount;

    function __construct($price, $name, $partNumber, $itemCount) {..}
}

我在想什么

数组编码是轻量级的,并且更支持JSON,但更容易弄乱。拼写错误的关联数组键之一,您可能会遇到更难以捕获的错误。但是,随心所欲地更改也更容易。说我不想再存储item_count了,我可以使用任何文本处理软件轻松删除item_count阵列中的所有实例,然后相应地更新使用它的其他功能。这可能是一个比较乏味的过程,但是很简单。

面向对象的编码要求使用IDE和PHP语言工具,从而可以更轻松地预先捕获任何错误,但首先很难进行编程和编码。我更难地说,因为您必须仔细考虑对象,提前思考,并且OO编码比键入数组结构要花更多的认知负担。就是说,一旦编码完成,从某种意义上说,某些更改可能更容易实现,item_count例如,删除只需更改较少的代码行。但是,与数组方法相比,更改本身可能仍需要更高的认知负担,因为涉及到更高级别的OO工具。

在某些情况下很明显,例如需要对数据进行操作的情况。但是在某些情况下,当我只需要存储几行“项目类型”数据时,在尝试决定是否使用数组还是构造对象时,我没有明确的指导方针或考虑因素。看来我只能抛硬币然后选一个。是这样吗?


2
请注意,您可以通过将数组转换为对象来获得轻量级对象:(object)['foo'=>'bar']。结果值具有class StdClass,将全部通过JSON编码,json_encode()并且属性可以像数组索引一样容易地重命名(当通过变量间接访问时,这并不总是那么容易)。但是,对这些值有不同的操作。例如,您没有对象联合,就没有数组联合,也不能直接使用这些array_*()函数。
outis 2015年

3
你有3种选择:1: array2: User-defined Class3: stdClass。在速度方面的性能与array和时User-defined class(例如您的ItemType)相比几乎相同,但已定义的classes使用的内存往往比使用arrays 少。stdClass另一方面,这是三个选项中最慢的一个,它也使用最多的内存。
安迪

Answers:


33

我所看到的方式,取决于您以后打算如何处理数据。根据一些简单的检查,您可以确定以下两种数据结构中的哪一种更适合您:

  1. 此数据有任何逻辑关联吗?

    例如,$price以美分的整数形式存储,因此价格为9.99美元的产品将具有price = 999而非price = 9.99?(可能是)还是partNumber需要匹配特定的正则表达式?或者,您是否需要能够轻松检查itemCount库存中是否可用?将来是否需要执行这些功能?如果是这样,那么最好的选择就是立即创建一个类。这意味着您可以定义内置在数据结构中的约束和逻辑:private $myPrice设置为,999$item->getPriceString()返回$9.99$item->inStock()可以在应用程序中调用。

  2. 您是否要将这些数据传递给多个PHP函数?

    如果是这样,则使用一个类。如果您一次生成此数据以对其进行一些转换,或者仅作为JSON数据发送到另一个应用程序(JavaScript或其他),则数组是一个更简单的选择。但是,如果您有两个以上的PHP函数接受此数据作为参数,请使用一个类。如果没有别的,那可以让您定义someFunction(MyProductClass $product) {并且很清楚您的函数期望输入什么。当您扩展代码并拥有更多功能时,将更容易知道每个功能接受的数据类型。眼神someFunction($someArrayData) {不那么清晰。此外,这不会强制类型一致性,并且(如您所说)意味着数组的灵活结构可能会在以后导致开发难题

  3. 您是要构建库还是共享代码库?

    如果是这样,请使用课程!想想一些正在使用您的库的新开发人员,或者公司中从未使用过您的代码的其他开发人员。对于他们来说,查看一个类定义并了解该类的作用,或者在您的库中查看接受某个类的对象的许多函数,比尝试猜测它们需要在一个类中生成的结构要容易得多。数组数。此外,这还涉及到#1的数据一致性问题:如果您正在开发库或共享代码库,请对您的用户好:为他们提供可增强数据一致性的类,并防止他们在设计数据时出错。

  4. 这是应用程序的一小部分,还是只是数据的转换?您不符合以上任何条件吗?

    一堂课可能太多了;如果适合,则使用数组,您会发现它更容易。如上所述,如果您只是生成结构化数据以JSON或YAML或XML或其他形式发送,则无需费心使用类,除非有必要。如果您在大型应用程序中编写一个小模块,而无需其他模块/团队与您的代码进行接口,那么数组就足够了。

最终,考虑代码的伸缩需求,并考虑使用结构化数组可能是一个快速解决方案,但是类是更具弹性和可扩展性的解决方案。

另外,请考虑以下因素:如果您有一个类,并且想要输出为JSON,则没有理由不能定义json_data()您的类的方法,该方法返回该类中数据的JSON可数组。这就是我在PHP应用程序中需要将类数据作为JSON发送的操作。举个例子:

class Order {
    private $my_total;
    private $my_lineitems;

    public function getItems() { return $this->my_lineitems; }
    public function addItem(Product $p) { $this->my_lineitems[] = $p; }
    public function getTotal() { return $this->my_total; }

    public function forJSON() {
        $items_json = array();
        foreach($this->my_lineitems as $item) $items_json[] = $item->forJSON();
        return array(
            'total' => $this->getTotal(),
            'items' => $items_json
        );
    }
}

$o = new Order();
// do some stuff with it
$json = json_encode($o->forJSON());

您无需更改的元素my_lineitems,因此无需通过引用获取它们,尤其是因为变量仅持有对象的标识符,而不是对象本身。php.net/manual/en/language.oop5.references.php
Chinoto Vokro

同意 我认为这是一个更大的应用程序的摘要,出于某种原因需要引用,这是什么原因……
Josh

2

您可以使用JsonSerializable接口实现json结构, 并以任何方式使用嵌套的数组/类。 在获取/设置操作中更快,并且更易于调试。使用Array时无需声明。

class Order implements \JsonSerializable{
    private $my_total;
    private $my_lineitems;

    public function getItems() { return $this->my_lineitems; }
    public function addItem(Product $p) { $this->my_lineitems[] = $p; }
    public function getTotal() { return $this->my_total; }

    public function jsonSerialize(){
        return [
            'total'=>$this->my_total,
            'products'=>$this->my_lineitems;
        ];
    }
}

class Product implements \JsonSerializable{
    private $name;
    private $price;

    public function jsonSerialize(){ 
        return [
            'name'=>$this->name, 
            'price'=>$this->price
        ];
    }
}

$order = new Order();
$order->addProduct(new Product('Product1', 15));
$order->addProduct(new Product('Product2', 35));
$order->addProduct(new Product('Product3', 42));
$json = json_encode(['order'=>$order, 'username'=>'Eughen']);
/*
json = {
    order: {
        total: 92, 
        products: [
            {
                name: 'Product1',
                price: 15
            }, 
            {
                name: 'Product2',
                price: 35
            },
            {
                name: 'Product3',
                price: 42
            }
        ]
    }, 
    username: 'Eughen'
}
*/

这个问题与现有的已接受答案相比又增加了什么?
esoterik

@esoterik嵌套。json_encode(['order'=>$o]);在现有的接受答案中为空白:{"order":{}}。当然,您可以使用:$o->forJSON()每次都在每个级别上的每个对象上,但这并不是真正的好设计。因为一直以来,您都需要这样写: $items_json = array(); foreach($this->my_lineitems as $item) $items_json[] = $item->forJSON();
El'18
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.