PHP: จะใช้อาร์เรย์เมื่อใดและเมื่อใดที่จะใช้วัตถุสำหรับการสร้างรหัสเก็บข้อมูลส่วนใหญ่


37

PHP เป็นภาษากระบวนทัศน์ผสมอนุญาตให้ใช้และส่งคืนชนิดข้อมูลที่ไม่ใช่วัตถุเช่นอาร์เรย์ ฉันถามคำถามเพื่อพยายามอธิบายแนวทางบางอย่างสำหรับการเลือกอาร์เรย์กับวัตถุเมื่อตัดสินใจเลือกสิ่งที่โปรแกรมสร้างขึ้นเพื่อใช้ในสถานการณ์เฉพาะ

นี่เป็นคำถามเกี่ยวกับวิธีการเข้ารหัสข้อมูลโดยใช้การสร้างภาษา PHP และเมื่อมีวิธีหนึ่งที่น่าจะเลือกมากกว่าเพื่อการส่งผ่านข้อมูล (เช่น Service-Oriented Architecture หรือบริการบนเว็บ)

ตัวอย่าง

สมมติว่าคุณมีประเภทรายการประกอบด้วย {cost, name, part_number, item_count} โปรแกรมของคุณเรียกร้องให้แสดงประเภทรายการดังกล่าวหลายประเภทซึ่งคุณต้องการใช้อาร์เรย์เป็นที่เก็บด้านนอกเพื่อเก็บรายการแต่ละประเภทไว้ [คุณยังสามารถใช้ PHP เป็นArrayObjectสำหรับกระบวนทัศน์ OO แต่คำถามของฉันไม่เกี่ยวกับการที่ (นอก) อาร์เรย์] คำถามของฉันเกี่ยวกับวิธีเข้ารหัสข้อมูลประเภทรายการและเกี่ยวกับกระบวนทัศน์ที่จะใช้ 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
        ),
  );

VS

//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 มากขึ้น แต่สามารถทำให้ยุ่งได้ง่ายขึ้น Misspell หนึ่งในคีย์อาเรย์เชื่อมโยงและคุณอาจมีข้อผิดพลาดที่จับยากกว่า แต่มันก็ง่ายกว่าที่จะเปลี่ยนใจ ว่าฉันไม่ต้องการเก็บitem_countอีกต่อไปฉันสามารถใช้ซอฟต์แวร์ประมวลผลข้อความใด ๆ เพื่อลบitem_countอินสแตนซ์ทั้งหมดในอาเรย์แล้วอัปเดตฟังก์ชั่นอื่น ๆ ที่ใช้งานได้ตามนั้น อาจเป็นกระบวนการที่น่าเบื่อกว่า แต่ก็ง่าย

การเข้ารหัสเชิงวัตถุจะเรียกร้องสิ่งอำนวยความสะดวกด้านภาษาของ IDE และ PHP และทำให้ง่ายต่อการตรวจจับข้อผิดพลาดใด ๆ ก่อนหน้า แต่เป็นการยากที่จะเขียนโปรแกรมและเขียนโค้ดในตอนแรก ฉันพูดได้ยากขึ้นเพราะคุณต้องคิดเกี่ยวกับวัตถุของคุณคิดล่วงหน้าและการเข้ารหัส OO ต้องใช้ภาระการรับรู้สูงกว่าการพิมพ์โครงสร้างของอาร์เรย์ ที่กล่าวว่าเมื่อมีการเขียนโค้ดการเปลี่ยนแปลงบางอย่างอาจนำไปใช้ได้ง่ายขึ้นในแง่หนึ่งเช่นการลบออกitem_countจะต้องเปลี่ยนรหัสบรรทัดน้อยลง แต่การเปลี่ยนแปลงตัวเองอาจยังต้องใช้ภาระการรับรู้สูงกว่าเมื่อเปรียบเทียบกับวิธีการเรียงลำดับเนื่องจากสิ่งอำนวยความสะดวก OO ระดับสูงมีส่วนเกี่ยวข้อง

คำถาม

ในบางกรณีมีความชัดเจนเช่นกรณีที่ฉันจะต้องทำการปรับเปลี่ยนข้อมูล แต่ในบางกรณีที่ฉันต้องเก็บข้อมูล "Item Type" สองสามบรรทัดฉันไม่มีแนวทางที่ชัดเจนหรือข้อควรพิจารณาที่จะพึ่งพาเมื่อพยายามตัดสินใจว่าจะใช้อาร์เรย์หรือว่าจะสร้างวัตถุ ดูเหมือนว่าฉันจะโยนเหรียญและเลือกหนึ่งเหรียญ เป็นกรณีนี้หรือไม่


2
หมายเหตุ: (object)['foo'=>'bar']คุณจะได้รับวัตถุที่มีน้ำหนักเบาโดยการหล่ออาร์เรย์วัตถุ: ค่าผลลัพธ์มีคลาสStdClassจะถูกเข้ารหัส JSON อย่างครบถ้วนโดยjson_encode()คุณสมบัติสามารถเปลี่ยนชื่อได้อย่างง่ายดายเหมือนกับดัชนีอาเรย์ (ซึ่งไม่ง่ายเสมอไปเมื่อเข้าถึงโดยอ้อมผ่านตัวแปร) อย่างไรก็ตามมีการดำเนินการที่แตกต่างกันในค่าดังกล่าว ตัวอย่างเช่นคุณไม่มีสหภาพวัตถุในขณะที่คุณมีสหภาพอาร์เรย์และคุณไม่สามารถใช้array_*()ฟังก์ชันได้โดยตรง
outis

3
คุณมี 3 ตัวเลือก: 1: array , 2: User-defined Class , 3: stdClassประสิทธิภาพในแง่ของความเร็วนั้นค่อนข้างเหมือนกันเมื่อเปรียบเทียบarrayและ a User-defined class(เช่นของคุณItemType) แต่classes ที่กำหนดมักใช้หน่วยความจำน้อยกว่าการใช้arrays stdClassในขณะที่ช้าที่สุดในสามตัวเลือกและใช้หน่วยความจำมากที่สุด
Andy

คำตอบ:


33

วิธีที่ฉันเห็นมันขึ้นอยู่กับว่าคุณตั้งใจจะทำอะไรกับข้อมูลในภายหลัง จากการตรวจสอบง่ายๆสองสามครั้งคุณสามารถพิจารณาว่าโครงสร้างข้อมูลใดในสองโครงสร้างที่ดีกว่าสำหรับคุณ:

  1. ข้อมูลนี้มีตรรกะใด ๆ ที่เกี่ยวข้องหรือไม่?

    ตัวอย่างเช่น$priceเก็บไว้เป็นจำนวนเต็มเซ็นต์ดังนั้นสินค้าที่มีราคา $ 9.99 จะมีหรือprice = 999ไม่price = 9.99? (อาจใช่) หรือไม่partNumberต้องจับคู่ regex ที่เฉพาะเจาะจง หรือคุณจำเป็นต้องสามารถตรวจสอบได้อย่างง่ายดายว่า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-ifiable นี่คือสิ่งที่ฉันทำในแอปพลิเคชัน 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

คุณสามารถนำโครงสร้าง json มาใช้โดยใช้ JsonSerializable interface และใช้ array / class ที่ซ้อนกันในทางใดทางหนึ่ง คลาสเร็วกว่าในการดำเนินการรับ / ตั้ง ด้วย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]);ใน existsing {"order":{}}คำตอบที่ได้รับการยอมรับจะว่างเปล่า: แน่นอนว่าคุณสามารถใช้: $o->forJSON()ทุกครั้งที่วัตถุทุกชิ้นในทุก ๆ ระดับ แต่มันก็ไม่ใช่การออกแบบที่ดีจริงๆ เพราะตลอดเวลาที่คุณต้องเขียนบางสิ่งเช่น: $items_json = array(); foreach($this->my_lineitems as $item) $items_json[] = $item->forJSON();
El '
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.