Getter et Setter?

Je ne suis pas un développeur PHP, donc je me demande si en PHP est plus populaire pour utiliser des getter/setters explicites, dans un pur style OOP, avec des champs privés (comme j'aime):

class MyClass {
    private $firstField;
    private $secondField;

    public function getFirstField() {
        return $this->firstField;
    }
    public function setFirstField($x) {
        $this->firstField = $x;
    }
    public function getSecondField() {
        return $this->secondField;
    }
    public function setSecondField($x) {
        $this->secondField = $x;
    }
}

ou tout simplement des champs publics:

class MyClass {
    public $firstField;
    public $secondField;
}

Merci

180
demandé sur David 2010-12-18 18:29:32

15 réponses

Vous pouvez utiliser php méthodes magiques __get et __set .

<?php
class MyClass {
  private $firstField;
  private $secondField;

  public function __get($property) {
    if (property_exists($this, $property)) {
      return $this->$property;
    }
  }

  public function __set($property, $value) {
    if (property_exists($this, $property)) {
      $this->$property = $value;
    }

    return $this;
  }
}
?>
192
répondu Dave 2011-05-19 01:06:30

Pourquoi utiliser getters et setters?

  1. Scalability : il est plus facile de refactor un getter que de rechercher toutes les assignations var dans un code de projet.
  2. débogage : vous pouvez mettre des points d'arrêt aux setters et getters.
  3. Cleaner : les fonctions magiques ne sont pas une bonne solution pour écrire moins, votre IDE ne suggérera pas le code. Meilleure utilisation des modèles rapide d'écrire des getters.

direct assignment and getters/setters

106
répondu Wiliam 2012-01-21 18:25:09

Google déjà publié un guide sur l'optimisation de PHP et la conclusion était:

Pas de getter et setter Optimisation PHP

Et non, vous devez ne pas utiliser les méthodes magiques . Pour PHP, la méthode magique est diabolique. Pourquoi?

  1. Ils sont difficiles à déboguer.
  2. il y a un impact négatif sur le rendement.
  3. ils ont besoin d'écrire plus de code.

PHP n'est pas Java, C++ ou C#. PHP est différent et joue des rôles différents.

30
répondu magallanes 2018-08-27 20:37:37

L'Encapsulation est importante dans n'importe quelle langue OO, la popularité n'a rien à voir avec elle. Dans les langages dynamiquement typés, comme PHP, il est particulièrement utile car il y a peu de façons de s'assurer qu'une propriété est d'un type spécifique sans utiliser de setters.

en PHP, cela fonctionne:

class Foo {
   public $bar; // should be an integer
}
$foo = new Foo;
$foo->bar = "string";

En Java, il n'est pas:

class Foo {
   public int bar;
}
Foo myFoo = new Foo();
myFoo.bar = "string"; // error

utilisant des méthodes magiques ( __get et __set ) fonctionne également, mais seulement lorsque accéder à une propriété dont la visibilité est inférieure à celle à laquelle le champ d'application actuel peut accéder. Il peut facilement vous donner des maux de tête en essayant de déboguer, si elle n'est pas utilisée correctement.

12
répondu netcoder 2010-12-18 15:44:24
class MyClass {
    private $firstField;
    private $secondField;
    private $thirdField;

    public function __get( $name ) {
        if( method_exists( $this , $method = ( 'get' . ucfirst( $name  ) ) ) )
            return $this->$method();
        else
            throw new Exception( 'Can\'t get property ' . $name );
    }

    public function __set( $name , $value ) {
        if( method_exists( $this , $method = ( 'set' . ucfirst( $name  ) ) ) )
            return $this->$method( $value );
        else
            throw new Exception( 'Can\'t set property ' . $name );
    }

    public function __isset( $name )
    {
        return method_exists( $this , 'get' . ucfirst( $name  ) ) 
            || method_exists( $this , 'set' . ucfirst( $name  ) );
    }

    public function getFirstField() {
        return $this->firstField;
    }

    protected function setFirstField($x) {
        $this->firstField = $x;
    }

    private function getSecondField() {
        return $this->secondField;
    }
}

$obj = new MyClass();

echo $obj->firstField; // works
$obj->firstField = 'value'; // works

echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected

echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private

$obj->secondField = 'value'; // not works, setter not exists

echo $obj->thirdField; // not works, property not exists

isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false

prêt!

6
répondu joas 2012-11-06 14:23:36

si vous prévoyez d'utiliser la fonction __call, vous pouvez utiliser cette méthode. Il fonctionne avec

  • GET = > $this->property()
  • SET = > $this->property($value)
  • GET = > $this->getProperty()
  • SET = > $this->setProperty($value)

kalsdas

public function __call($name, $arguments) {

    //Getting and setting with $this->property($optional);

    if (property_exists(get_class($this), $name)) {


        //Always set the value if a parameter is passed
        if (count($arguments) == 1) {
            /* set */
            $this->$name = $arguments[0];
        } else if (count($arguments) > 1) {
            throw new \Exception("Setter for $name only accepts one parameter.");
        }

        //Always return the value (Even on the set)
        return $this->$name;
    }

    //If it doesn't chech if its a normal old type setter ot getter
    //Getting and setting with $this->getProperty($optional);
    //Getting and setting with $this->setProperty($optional);
    $prefix = substr($name, 0, 3);
    $property = strtolower($name[3]) . substr($name, 4);
    switch ($prefix) {
        case 'get':
            return $this->$property;
            break;
        case 'set':
            //Always set the value if a parameter is passed
            if (count($arguments) != 1) {
                throw new \Exception("Setter for $name requires exactly one parameter.");
            }
            $this->$property = $arguments[0];
            //Always return the value (Even on the set)
            return $this->$name;
        default:
            throw new \Exception("Property $name doesn't exist.");
            break;
    }
}
6
répondu J-Rou 2013-08-20 20:05:43

en plus des réponses déjà grandes et respectées ici, je voudrais développer sur PHP n'ayant pas de setters/getters.

PHP ne dispose pas de getter et le setter de la syntaxe . Il fournit sous-classe ou magic méthodes pour permettre "accrochage" et la suppression du processus de recherche de propriété, comme souligné par Dave .

la Magie permet nous programmeurs paresseux "1519250920 de" faire plus avec moins de code à un moment où nous sommes activement engagés dans un projet et de le connaître intimement, mais généralement au détriment de la lisibilité.

Performance chaque fonction inutile, qui résulte de l'imposition d'une architecture de code de type getter/setter en PHP, implique sa propre pile de mémoire à l'invocation et gaspille les cycles CPU.

lisibilité: le codebase comporte des lignes de code gonflées, qui affectent la navigation de code car plus de LOC signifie plus de défilement,.

préférence: personnellement, en règle générale, je considère l'échec de l'analyse statique de code comme un signe pour éviter de descendre la route magique aussi longtemps que des avantages évidents à long terme m'échappent à ce moment-là.

Sophismes:

A l'argument courant est la lisibilité. Par exemple, $someobject->width est plus facile à lire que $someobject->width() . Cependant, contrairement à circumference ou width d'une planète , qui peut être supposé être static , l'instance d'un objet tel que $someobject , qui nécessite une fonction de largeur, prend probablement une mesure de la largeur de l'instance de l'objet.

Par conséquent, la lisibilité augmente principalement en raison de schémas de nommage assertifs et non en masquant la fonction qui produit un de valeur de propriété.

__get et __set utilise:

  • pré-validation et pré-assainissement de la valeur des biens

  • cordes p.ex.

    "
    some {mathsobj1->generatelatex} multi
    line text {mathsobj1->latexoutput}
    with lots of variables for {mathsobj1->generatelatex}
     some reason
    "
    

    dans ce cas generatelatex adhérerait à un schéma de nommage de actionname + methodname

  • cas spéciaux, évidents

    $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
    $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()
    

Note: PHP a choisi de ne pas implémenter la syntaxe getter/setter. Je ne prétends pas que les getters/setter sont généralement mauvais.

6
répondu Lorenz Lo Sauer 2017-03-20 10:29:34

eh Bien, PHP n'ont méthodes magiques __get , __set , __isset & __unset , ce qui est toujours un début. Hélas appropriée (l'obtenir?) OO propriétés est plus que de la magie méthodes. Le principal problème avec L'implémentation de PHP est que les méthodes magiques sont appelées pour toutes propriétés inaccessibles. Ce qui signifie que vous devez vous répéter (par ex. en appelant property_exists ()) dans les méthodes magiques pour déterminer si nom est en fait une propriété de l'objet. Et vous ne pouvez pas vraiment résoudre ce problème général avec une classe de base à moins que toutes vos classes héritent d'ie. ClassWithProperties, puisque PHP n'a pas d'héritage multiple.

en contraste, Python les nouvelles classes de style vous donnent property() , ce qui vous permet de définir explicitement toutes vos propriétés. c# a une syntaxe spéciale.

http://en.wikipedia.org/wiki/Property_ (programmation)

5
répondu Emanuel Landeholm 2018-08-14 13:32:13

après avoir lu les autres conseils, je suis enclin à dire que:

en tant que règle Générique , vous ne définirez pas toujours les setters pour toutes propriétés, spécialement" internes " (sémaphores, drapeaux internes...). Lecture seule propriétés n'aura pas de poseurs, de toute évidence, de sorte que certaines propriétés ne ont getters; c'est de là __get() vient de réduire le code:

  • définissez un _ _ get () (magical global getters) pour toutes les propriétés qui sont semblables,
  • groupez-les dans les tableaux ainsi:
    • ils partageront des caractéristiques communes: les valeurs monétaires seront/peuvent apparaître correctement formatées, les dates dans une présentation spécifique (ISO, US, Intl.), etc.
    • le code lui-même peut vérifier que seules les propriétés existantes et autorisées sont lues en utilisant cette méthode magique.
    • chaque fois que vous avez besoin de créez une nouvelle propriété similaire, déclarez-la et ajoutez son nom au tableau approprié et c'est fait. C'est la façon plus rapide que de définir un nouveau getter, peut-être avec quelques lignes de code répétées encore et encore partout dans le code de classe.

Oui! nous pourrions écrire une méthode privée pour le faire, aussi, mais encore une fois, nous aurons beaucoup de méthodes déclarées (mémoire++) qui finissent par appeler une autre méthode, toujours la même. Pourquoi il suffit de ne pas écrire un simple méthode à règle Tous les ...? [yep! jeu de mots absolument voulu! :)]

Magic setters peut également répondre uniquement à des propriétés spécifiques, de sorte que toutes les propriétés de type date peuvent être criblées contre des valeurs invalides dans une seule méthode. Si les propriétés de type date ont été listées dans un tableau, leurs setters peuvent être définis facilement. Juste un exemple, bien sûr. il y a bien trop de situations.

à Propos de lisibilité ... Bien... C'est un autre débat: je n'aime pas être lié aux utilisations d'un IDE (en fait, je ne les utilise pas, ils ont tendance à me dire (et force moi) comment écrire... et j'ai mes goûts en codage "beauté"). J'ai tendance à être cohérent en ce qui concerne le nom, donc utiliser des ctags et quelques autres aides est suffisant pour moi... Quoi qu'il en soit: une fois que tous ces setters magiques et getters sont finis, j'écris les autres setters qui sont trop spécifiques ou" spéciaux " pour être généralisé dans une méthode _ _ set (). Et ça couvre tout ce dont j'ai besoin pour obtenir et configurer des propriétés. Bien sûr: il n'y a pas toujours un terrain d'entente, ou il y a tellement de propriétés qui ne valent pas la peine de coder une méthode magique, et puis il y a toujours la bonne vieille paire de setter/getter traditionnel.

les langages de programmation sont exactement cela: les langages artificiels humains. Donc, chacun d'eux a sa propre intonation ou accent, syntaxe et saveur, donc je ne vais pas prétendre écrire un Code Ruby ou Python utilisant le même "accent" que Java ou C#, Je n'écrirais pas non plus un JavaScript ou PHP ressemblant à Perl ou SQL... Utilisez-les comme elles sont censées être utilisées.

2
répondu Manuel 2015-01-27 16:20:08

j'ai fait une expérience en utilisant la méthode magique __call. Pas sûr si je devrais le poster (en raison de tous les Avertissements "N'utilisez pas de méthodes magiques" dans les autres réponses et commentaires) mais je vais le laisser ici.. juste au cas où quelqu'un la trouver utile.


public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = substr($_name, 4);

    if (isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

il suffit d'ajouter cette méthode ci-dessus dans votre classe, maintenant vous pouvez taper:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_foo(); // return "bar"
$C->get_bom(); // return "bim"

// as setter
$C->set_foo("abc"); // set "abc" as new value of foo
$C->set_bom("zam"); // set "zam" as new value of bom


de Cette façon, vous pouvez obtenir/définir tout dans votre classe si elle existe ainsi, si vous en avez besoin pour seulement quelques éléments spécifiques, vous pouvez utiliser une "liste blanche" comme filtre.

exemple:

private $callWhiteList = array(
    "foo" => "foo",
    "fee" => "fee",
    // ...
);

public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = $this->callWhiteList[substr($_name, 4)];

    if (!is_null($varName) && isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

Maintenant vous pouvez seulement obtenir / mettre "foo"et " fee".

Vous pouvez également utiliser ce "whitelist" pour assigner des noms personnalisés pour accéder à vos vars.

Par exemple,

private $callWhiteList = array(
    "myfoo" => "foo",
    "zim" => "bom",
    // ...
);

Avec cette liste vous pouvez maintenant taper:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // private $callWhiteList = array( ... )
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_myfoo(); // return "bar"
$C->get_zim(); // return "bim"

// as setter
$C->set_myfoo("abc"); // set "abc" as new value of foo
$C->set_zim("zam"); // set "zam" as new value of bom

.

.

.

C'est tout.


Doc: __ _ call () est déclenché lors de l'invocation de méthodes inaccessibles dans un contexte d'objet.

2
répondu Saba 2015-11-24 08:13:16

en général, la première voie est plus populaire dans l'ensemble parce que ceux qui ont une connaissance préalable de la programmation peuvent facilement passer à PHP et obtenir du travail fait d'une manière orientée objet. La première méthode est plus universelle. Mon conseil serait de rester avec ce qui est éprouvé et vrai dans de nombreuses langues. Ensuite, quand et si vous utilisez une autre langue, vous serez prêt à accomplir quelque chose ( au lieu de passer du temps à réinventer la roue ).

1
répondu Anthony Rutledge 2015-04-09 14:14:14

il y a plusieurs façons de créer sourcecode dans une convention netbeans. C'est gentil. Il rend pense plus facile = = = faux. Utilisez simplement le traditionel, spécialement si vous n'êtes pas sûr de l'une des propriétés doit être encapsulé et que l'on a pas. Je sais, c'est un ce.... pla... code, mais pour le débogage-fonctionne et beaucoup d'autres pense que c'est la meilleure, voie claire. Ne passez pas beaucoup de temps avec des milliers d'arts comment faire simples getters et setters. Vous ne pouvez pas mettre en œuvre trop de design modèles comme demeter-règle et ainsi de suite, si vous utilisez la magie. Dans des situations spécifiques, vous pouvez utiliser magic_calls ou pour des solutions petites, rapides et claires. Bien sûr, vous pourriez faire des solutions pour design-patters de cette façon aussi, mais pourquoi vous rendre la vie plus difficile.

0
répondu Dennis Komnenovic 2013-03-10 10:05:56

Validation + Formatage / Valeurs Dérivées

Les Setters

vous permettent de valider des données et les getters vous permettent de formater ou de dériver des données. Les objets vous permettent d'encapsuler des données et son code de validation et de formatage dans un paquet ordonné qui encourage DRY.

par exemple, considérez la classe simple suivante qui contient une date de naissance.

class BirthDate {

    private $birth_date;

    public function getBirthDate($format='Y-m-d') {
        //format $birth_date ...
        //$birth_date = ...
        return $birth_date;
    }

    public function setBirthDate($birth_date) {                   
        //if($birth_date is not valid) throw an exception ...          
        $this->birth_date = $birth_date;
    }

    public function getAge() {
        //calculate age ...
        return $age;
    }

    public function getDaysUntilBirthday() {
        //calculate days until birth days
        return $days;
    }
}

vous voudrez valider que la valeur définie est

  • Une date valide
  • Pas dans l'avenir

et vous ne voulez pas faire cette validation sur toute votre application (ou sur plusieurs applications d'ailleurs). Au lieu de cela, il est plus facile de faire de la variable member protected ou private (afin de faire du setter le seul point d'accès) et de valider dans le setter parce que vous saurez alors que l'objet contient une date de naissance valide quelle que soit la partie de la application provenance de l'objet et si vous voulez ajouter plus de validation puis vous pouvez l'ajouter en un seul endroit.

vous pourriez vouloir ajouter des formatteurs multiples qui fonctionnent sur la même variable membre i.e. getAge() et getDaysUntilBirthday() et vous pourriez vouloir appliquer un format configurable dans getBirthDate() selon locale. Par conséquent, je préfère systématiquement accéder aux valeurs via getters plutôt que de mélanger $date->getAge() avec $date->birth_date .

les accesseurs et mutateurs sont également utiles lorsque vous étendez les objets. Par exemple, supposons que votre demande devait permettre des dates de naissance de plus de 150 ans dans certains endroits, mais pas dans d'autres. Une façon de résoudre le problème sans répéter aucun code serait d'étendre l'objet BirthDate et de mettre la validation supplémentaire dans le setter.

class LivingBirthDate extends BirthDate {

    public function setBirthDate($birth_date) {
        //if $birth_date is greater than 150 years throw an exception
        //else pass to parent's setter
        return parent::setBirthDate($birth_date);
    }
}
0
répondu FuzzyTree 2014-09-25 02:09:46

ce post n'est pas spécifiquement sur __get et __set mais plutôt __call qui est la même idée sauf pour la méthode calling. En règle générale, je reste à l'écart de tout type de méthodes magiques qui permettent de surcharger pour les raisons décrites dans les commentaires et les messages cependant , j'ai récemment rencontré une API tierce partie que j'utilise qui utilise un SERVICE et un sous-SERVICE, exemple:

http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234

l'important est que cette API a tout le même sauf la sous-action, dans ce cas doActionOne . L'idée est que le développeur (moi-même et les autres utilisateurs de cette classe) pourrait appeler le sous-service par son nom par opposition à quelque chose comme:

$myClass->doAction(array('service'=>'doActionOne','args'=>$args));

je pourrais le faire à la place:

 $myClass->doActionOne($args);

Pour coder en dur, ce serait juste un beaucoup de duplication (dans cet exemple, très vaguement semblable au code):

public function doActionOne($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionTwo($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionThree($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

protected function executeCoreCall($service)
    {
        $cURL = new \cURL();
        return $cURL->('http://3rdparty.api.com?service='.$service.'&apikey='.$this->api.'&'.http_build_query($this->args))
                    ->getResponse();
    }

Mais avec la méthode magique de __call() je suis en mesure d'accéder à tous les services avec des méthodes dynamiques:

public function __call($name, $arguments)
    {
        $this->args     =   $arguments;
        $this->response =   $this->executeCoreCall("APIService.{$name}");   
        return $this;
    }

l'avantage de cette demande dynamique de retour de données est que si le vendeur ajoute un autre Sous-service, je n'ai pas à ajouter une autre méthode dans la classe ou créer une classe étendue, etc. Je ne suis pas sûr que cela soit utile à quiconque, mais j'ai pensé que je voudrais montrer un exemple où __set , __get , __call , etc. peut-être une option attention, car la fonction première est le retour des données.


EDIT:

par coïncidence, j'ai vu ceci quelques jours après l'affichage qui décrit exactement mon scénario. Ce N'est pas L'API à laquelle je faisais référence mais l'application des méthodes est identique:

est-ce que j'utilise l'api correctement?

0
répondu Rasclatt 2017-05-23 12:18:01

mise à jour: N'utilisez pas cette réponse car il s'agit d'un code très stupide que j'ai trouvé en apprenant. Utilisez simplement getter et setter, c'est beaucoup mieux.


" j'utilise habituellement ce nom de variable comme nom de fonction, et j'ajoute un paramètre optionnel à cette fonction de sorte que lorsque ce paramètre optionnel est rempli par l'appelant, je le place dans la propriété et je renvoie $this object (chaining) et ensuite lorsque ce paramètre optionnel n'est pas spécifié par l'appelant, je renvoie juste la propriété de l'appelant.

mon exemple:

class Model
{
     private $propOne;
     private $propTwo;

     public function propOne($propVal = '')
     {
          if ($propVal === '') {
              return $this->propOne;
          } else {
              $this->propOne = $propVal;
              return $this;
          }
     }

     public function propTwo($propVal = '')
     {
          if ($propVal === '') {
              return $this->propTwo;
          } else {
              $this->propTwo = $propVal;
              return $this;
          }
     }
}
-2
répondu ajiyakin 2017-12-15 02:23:08