web-dev-qa-db-fra.com

PHP: quand utiliser des tableaux et quand utiliser des objets pour des constructions de code stockant principalement des données?

PHP est un langage de paradigme mixte, permettant d'utiliser et de renvoyer des types de données non-objets, tels que des tableaux. Je pose une question pour essayer de clarifier certaines lignes directrices pour la sélection de tableaux par rapport aux objets lors du choix de la construction de programmation à utiliser dans une situation particulière.

C'est vraiment une question sur les façons de coder les données en utilisant PHP constructions de langage et quand une façon doit être plus susceptible d'être choisie sur une autre à des fins de transmission de données (c'est-à-dire une architecture orientée services ou des services Web).

Exemple

Supposons que vous ayez un type d'élément composé de {coût, nom, numéro_partie, nombre_élément}. Votre programme demande l'affichage de plusieurs de ces types d'éléments, à l'endroit où vous décidez d'utiliser un tableau comme conteneur externe pour contenir chacun des types d'éléments. [Vous pouvez également utiliser le ArrayObject de PHP pour OO, mais ma question ne concerne pas que (externe) tableau. Ma question est de savoir comment coder les données de type d'élément et quel paradigme utiliser. PHP vous permet d'utiliser PHP Native Arrays ou PHP Objects.

Je peux encoder de telles données, de deux manières ici, comme ceci:

//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
        ),
  );

contre

//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) {..}
}

Ce que je pense

L'encodage des tableaux est léger et plus compatible avec JSON, mais peut être plus facile à gâcher. Mal orthographier l'une des clés du tableau associatif et vous pouvez avoir une erreur plus difficile à détecter. Mais il est également plus facile de changer sur un coup de tête. Dis que je ne veux pas stocker item_count plus, je peux utiliser n'importe quel logiciel de traitement de texte pour supprimer facilement tous les item_count instances dans le tableau, puis mettez à jour les autres fonctions qui l'utilisent en conséquence. Cela peut être un processus plus fastidieux, mais c'est simple.

Le codage orienté objet fait appel à IDE et PHP facilités de langage et facilite la détection des erreurs au préalable, mais est plus difficile à programmer et à coder en premier lieu) . Je dis plus fort, car il faut penser un peu à ses objets, penser à l’avance et OO le codage prend une charge cognitive un peu plus élevée que de taper des structures de tableaux. Cela dit, une fois codé , certains changements peuvent être plus faciles à mettre en œuvre, dans un sens, que la suppression de item_count, par exemple, nécessitera de changer moins de lignes de code. Mais les changements eux-mêmes peuvent encore nécessiter une charge cognitive plus élevée par rapport à la méthode de tableau, car des installations de niveau supérieur OO sont impliquées.

Question

Dans certains cas, c'est clair, comme dans les cas où je devrai effectuer des manipulations sur les données. Mais dans certains cas, lorsque je dois simplement stocker quelques lignes de données "Type d'élément", je n'ai pas de directives ou de considérations claires sur lesquelles m'appuyer pour décider d'utiliser des tableaux ou de construire des objets. Il semble que je puisse simplement lancer une pièce et en choisir une. est-ce le cas ici?

37
Dennis

À mon avis, cela dépend de ce que vous comptez faire des données par la suite. Sur la base de quelques vérifications simples, vous pouvez déterminer laquelle des deux structures de données vous convient le mieux:

  1. Ces données sont-elles associées à une logique?

    Par exemple, $price Est-il stocké sous la forme d'un nombre entier de cents, donc un produit avec un prix de 9,99 $ aurait price = 999 Et non price = 9.99? (Probablement, oui) Ou partNumber doit-il correspondre à une expression rationnelle spécifique? Ou, devez-vous pouvoir vérifier facilement si le itemCount est disponible dans votre inventaire? Aurez-vous besoin de faire ces fonctions à l'avenir? Si oui, alors votre meilleur pari est de créer une classe maintenant. Cela signifie que vous pouvez définir des contraintes et une logique intégrées dans la structure de données: private $myPrice Est défini sur 999 Mais $item->getPriceString() renvoie $9.99 Et $item->inStock() est disponible pour être appelé dans votre application.

  2. Allez-vous transmettre ces données à plusieurs PHP?

    Si c'est le cas, utilisez une classe. Si vous générez ces données une fois pour y effectuer des transformations, ou simplement pour envoyer des données JSON à une autre application (JavaScript ou autre), un tableau est un choix plus facile. Mais si vous avez plus de deux fonctions PHP qui acceptent ces données comme paramètre, utilisez une classe. Si rien d'autre, cela vous permet de définir someFunction(MyProductClass $product) { et il est très clair ce que vos fonctions attendent en entrée. Lorsque vous augmentez l'échelle de votre code et que vous en avez plus, il sera beaucoup plus facile de savoir quel type de données chaque fonction accepte. Voir someFunction($someArrayData) { n'est pas aussi clair. De plus, cela ne signifie pas appliquer la cohérence des types et signifie que (comme vous l'avez dit) la structure flexible de la matrice peut entraîner des problèmes de développement plus tard

  3. Construisez-vous une bibliothèque ou une base de code partagée?

    Si oui, tilisez une classe! Pensez à un nouveau développeur qui utilise votre bibliothèque, ou à un autre développeur ailleurs dans l'entreprise qui n'a jamais utilisé votre code auparavant. Il leur sera beaucoup plus facile de regarder une définition de classe et de comprendre ce que fait cette classe, ou de voir un certain nombre de fonctions dans votre bibliothèque qui acceptent des objets d'une certaine classe, que d'essayer de deviner quelle structure ils doivent générer dans un nombre de tableaux. En outre, cela touche aux problèmes de cohérence des données avec # 1: si vous développez une bibliothèque ou une base de code partagée, soyez gentil avec vos utilisateurs: donnez-leur des classes qui appliquent la cohérence des données et les empêchent de faire des erreurs avec la conception de vos données .

  4. S'agit-il d'une petite partie d'une application ou simplement d'une transformation de données? N'entrez-vous dans aucun des éléments ci-dessus?

    Une classe peut être trop; utilisez un tableau s'il vous convient et que vous le trouvez plus facile. Comme mentionné ci-dessus, si vous générez simplement des données structurées à envoyer au format JSON ou YAML ou XML ou autre, ne vous embêtez pas avec une classe, sauf si cela est nécessaire. Si vous écrivez un petit module dans une application plus grande et qu'aucun autre module/équipe n'a besoin de s'interfacer avec votre code, peut-être qu'un tableau est suffisant.

En fin de compte, considérez les besoins de mise à l'échelle de votre code et considérez qu'un tableau structuré peut être une solution rapide, mais une classe est une solution beaucoup plus résiliente et évolutive.

Tenez également compte des éléments suivants: si vous avez une classe et que vous souhaitez exporter vers JSON, il n'y a aucune raison pour laquelle vous ne pouvez pas définir une méthode json_data() de votre classe qui renvoie un tableau de données JSON-ifiable dans la classe. C'est ce que j'ai fait dans mes applications PHP où j'avais besoin d'envoyer des données de classe en JSON. Par exemple:

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());
33
Josh

Vous pouvez implémenter la structure json en utilisant l'interface JsonSerializable et utiliser le tableau/classe imbriqué de quelque manière que ce soit. Classe est plus rapide dans les opérations get/set et plus facile à déboguer. Avec Array vous n'avez besoin d'aucune déclaration.

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'
}
*/
2
El'