meilleure pratique pour initialiser les membres de la classe en php

10

J'ai beaucoup de code comme celui-ci dans mes constructeurs: -

function __construct($params) {

    $this->property = isset($params['property']) ? $params['property'] : default_val;

}

Est-il préférable de le faire plutôt que de spécifier la valeur par défaut dans la définition de propriété? c'est à dire public $property = default_val? Parfois, il existe une logique pour la valeur par défaut, et certaines valeurs par défaut sont extraites d'autres propriétés, c'est pourquoi je faisais cela dans le constructeur.

Dois-je utiliser des setters pour que toute la logique des valeurs par défaut soit séparée?

rgvcorley
la source

Réponses:

8

J'ai déjà eu ce genre de débat philosophique avec moi-même. Voici où j'en suis la plupart du temps, bien que je réalise que c'est une réponse basée sur l'opinion:

Une chose que je vois qui pourrait aider à répondre à la question est le passage de $ params qui peut ou non avoir des attributs / membres de tableau qui sont définis.

Au fil des ans, je suis arrivé à cette conclusion:

Évitez le passage de tableaux.

Pourquoi? Eh bien, il n'y a aucun moyen de définir ou de définir des valeurs sentinelles pour les arguments passés facultatifs.

En d'autres termes, avec le code que vous avez spécifié, vous ne pouvez pas faire quelque chose comme ceci:

function __construct($arg1 = NULL, $arg2 = DEFAULT_VAL) {

    $this->arg1 = $arg1;

    $this->arg2 = $arg2;

}

$ arg1 et $ arg2 sont des arguments facultatifs - s'ils ne sont pas transmis, ils ont respectivement NULL et DEFAULT_VAL - pas besoin de vérifier explicitement.

Peut-être que cela semble un peu arbitraire.

Je pense que j'obtiens ce que vous essayez d'accomplir - le passage d'une seule référence par opposition à des tonnes d'arguments. Cela m'amène à ma prochaine conclusion:

Si vous ne passez pas de variables "atomiques" (chaînes, entiers, littéraux), passez des objets.

Il y a des avantages de performances ici car le passage d'objets se fait par référence (bien que les tableaux soient à peu près les mêmes à l'intérieur de PHP).

Vous pourriez donc faire quelque chose comme:

function __construct(MyAwesomeObject $oArg) {

        $this->oArg = $oArg;

    }

L'argument d'objet passé serait alors garanti d'avoir "property1", "property2" bien qu'avec éventuellement des valeurs par défaut elles-mêmes.

De plus, ici, vous pouvez taper hint et un bon IDE suggérera correctement l'achèvement du code.

Mais nous réalisons rapidement que nous avons un poulet et un œuf en cours: vous construisez un objet avec des arguments d'objet passés qui eux-mêmes doivent être construits à un moment donné.

Alors, où cela nous mène-t-il? Eh bien, je suis arrivé à la conclusion que toutes les classes finissent par se résumer à, faute d'un meilleur terme, des variables "atomiques" (chaînes, flottants, doubles, entiers, ressources que vous comprenez), et que j'ai tendance à essayer pour construire toutes les classes avec ces types ou objets variables - mais pas les tableaux.

Alors ai-je répondu à votre question? probablement pas exactement. Mais j'espère avoir illustré quelque chose d'utile, quoique quelque peu stylistique. Je pense que le code est un peu plus propre, plus lisible et moins coûteux.

Maintenant, cela ne veut pas dire que vous ne devriez pas nettoyer votre entrée. C'est une autre discussion entièrement.

J'espère que cela t'aides.

ekeyser
la source
1
C'est un bon point, et très pratique pour les invites IDE mais il y a beaucoup trop de propriétés d'objet pour les passer toutes en paramètres. Si vous avez 7 arguments, dont 5 sont facultatifs, vous vous retrouvez avec des choses comme new object($param1,-some default value so I can specify the next parameter-, $param3);et vous avez donc vos valeurs par défaut codées en dur à plusieurs endroits différents
rgvcorley
3

Bien que j'ai tendance à éviter de transmettre des tableaux à un constructeur, je trouve parfois nécessaire de traiter une valeur de tableau entrante (comme pour une classe qui lit les valeurs d'un fichier de configuration).

Dans un cas comme celui-ci, je profiterai des fonctions de tableau de PHP pour m'assurer que je travaille exactement avec ce avec quoi je pense travailler:

public function import( array $incoming )
{
  $defaults = array(
      'foo' => DEFAULT_FOO
    , 'bar' => DEFAULT_BAR
    ...
  );

  $values = array_merge($defaults, array_intersect_key($incoming, $defaults));

  ...
}

Cette dernière ligne utilise array_merge()pour écraser toutes les valeurs $defaultsavec leurs valeurs correspondantes de $incoming. J'utilise également array_intersect_key()pour m'assurer que le tableau résultant ne contient aucune clé supplémentaire que la classe / méthode ne saurait pas traiter.


la source
Bonjour, quel est le comportement si $ defaults contient un tableau au lieu de simples variables?
Pol Dellaiera
@PolDellaiera Regardez array_merge_recursive.