Getter e Setter?


203

Non sono uno sviluppatore di PHP, quindi mi chiedo se in PHP sia più popolare usare getter / setter espliciti, in puro stile OOP, con campi privati ​​(come mi piace):

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;
    }
}

o solo campi pubblici:

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

Grazie


7
Dopo aver provato un po 'di codice dalle risposte, ho usato il codice che stai usando nella domanda. Che tristezza :-(
sumid

9
PHPstorm ... genera> getter e setter. == vittoria
DevDonkey

@DevDonkey Non è affatto una vittoria. Per conservare i dati strutturati, utilizzare invece le matrici. @: Mark Questo non è ciò che gli oggetti sono o sono per. Getter e setter sono cattivi: yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Kubo2

Risposte:


222

Puoi usare metodi magici php __get e __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;
  }
}
?>

15
Penso che tu intenda __gete __set. Ci sono due trattini bassi, non uno. Ecco il link diretto alla parte destra della pagina: php.net/manual/en/… (+1 per una risposta corretta)
Computerish

28
Qual è il vantaggio rispetto alle publicproprietà, se non ci sono convalide / servizi igienico-sanitari?
KingCrunch

7
@KingCrunch, questo è solo un esempio. Un esempio molto fittizio per una risorsa potente.
Davis Peixoto,

10
Questo non è davvero setter e getter. In genere ho bisogno di una diversa implementazione di getter per ogni proprietà!
somma

79
Per favore, non farlo: con i metodi magici perderai quasi tutte le funzionalità legate alla qualità, in molti IDE (anche vim): completamento automatico, eredità esplicita di PHP, interpretazione rapida di PHP e utile generazione e output di PHPDoc. cf. stackoverflow.com/a/6184893/490589
Ronan

113

Perché usare getter e setter?

  1. Scalabilità : è più semplice fare il refactor di un getter che cercare tutte le assegnazioni var in un codice di progetto.
  2. Debug : è possibile inserire punti di interruzione nei setter e nei getter.
  3. Cleaner : le funzioni Magic non sono una buona soluzione per scrivere meno, il tuo IDE non suggerirà il codice. Utilizzare meglio i modelli per getter a scrittura rapida.

assegnazione diretta e getter / setter


7
Se usi @property, il tuo IDE suggerirà il codice (testato con PhpStorm 7)
Alex2php

41

Google ha già pubblicato una guida sull'ottimizzazione di PHP e la conclusione è stata:

Nessun getter e setter Ottimizzazione di PHP

E no, non devi usare metodi magici . Per PHP, il metodo magico è malvagio. Perché?

  1. Sono difficili da eseguire il debug.
  2. C'è un impatto negativo sulle prestazioni.
  3. Richiedono la scrittura di più codice.

PHP non è Java, C ++ o C #. PHP è diverso e gioca con ruoli diversi.


10
Tendo ad essere d'accordo con quell'idea; che $dog->name = 'fido'è meglio di $dog->setName('fido'). Quando effettivamente muto una proprietà (es: $dog->increaseAge(1)posso costruire il metodo che fa la necessaria convalida e muta quella proprietà. Ma non tutte le azioni richiedono davvero una mutazione in questo senso.
Charlie Schliesser,

11
L'articolo non dice " no ", dice "setter e getter ingenui".
Brett Santore,


13
Si può presumere che un articolo scritto da Google che abbia il titolo "Suggerimenti sulle prestazioni di PHP" NON intende suggerire un buon stile di codifica, ma un'esecuzione rapida del codice. Il capitolo relativo ai setter e ai getter è etichettato "Evita di scrivere setter e getter ingenui", e l'esempio di codice è esattamente questo: ingenuo. Imposta e ottiene solo una variabile senza alcuna convalida. Questo tipo di setter / getter è inutile. Effettuare la convalida all'interno di un setter (utilizzare semplicemente un suggerimento di tipo per l'argomento del metodo) renderà utili setter / getter perché ora il tuo codice CONOSCE ciò di cui tratta.
Sven,

3
è come dire che lo stile in linea è migliore. ovviamente le prestazioni sono migliori, ma è un codice migliore? Non sapevo che gli ingegneri di Google usassero php
Claudiu Creanga,

13

L'incapsulamento è importante in qualsiasi linguaggio OO, la popolarità non ha nulla a che fare con esso. Nei linguaggi tipizzati dinamicamente, come PHP, è particolarmente utile perché ci sono pochi modi per garantire che una proprietà sia di un tipo specifico senza usare setter.

In PHP, questo funziona:

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

In Java, non:

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

L'uso dei metodi magici ( __gete __set) funziona anche, ma solo quando si accede a una proprietà che ha una visibilità inferiore rispetto all'ambito corrente è possibile accedere. Può facilmente darti mal di testa quando si tenta di eseguire il debug, se non viene utilizzato correttamente.


7
Getter e setter non portano incapsulamento. Gli oggetti incapsulamento == fanno qualcosa con i propri dati invece di fornirli all'esterno. Getter e setter non sono uno strumento per imporre il tipo in linguaggi tipicamente dinamici come PHP.
smentek,

14
@smentek: Stai chiaramente perdendo almeno la metà di ciò che l'incapsulamento è davvero.
netcoder

2
Come aggiornamento a questo per chiunque cerchi, PHP 7.4 verrà fornito con supporto proprietà tipizzato. Quindi potresti dichiarare $barcome intnel primo esempio: wiki.php.net/rfc/typed_properties_v2
Kevin

7

Se si preferisce utilizzare la funzione __call, è possibile utilizzare questo metodo. Funziona con

  • OTTIENI => $this->property()
  • SET => $this->property($value)
  • OTTIENI => $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;
    }
}

2
@ krzysztof-przygoda: questo "metodo magico" ha sempre un prezzo. Devono usare la ricorsione property_exists(get_class($this), $name)e la ricorsione è lenta. Esiste un modo y per mitigarlo con la memorizzazione nella cache, ma sarà comunque più lento della creazione manuale di getter e setter. L'ho scritto solo in alternativa. In realtà non consiglio di usare "Metodi magici". Il tempo extra per la creazione di getter e setter è generalmente insignificante.
J-Rou,

7

Oltre alle già ottime e rispettate risposte qui, vorrei estendere il fatto che PHP non ha setter / getter.

PHP non ha sintassi getter e setter . Forniscemetodisubclassati o magici per consentire l'aggancio e l'override del processo di ricerca delle proprietà, come sottolineato da Dave .

Magic ci consente a programmatori pigri di fare di più con meno codice in un momento in cui siamo attivamente impegnati in un progetto e lo conosciamo intimamente, ma di solito a spese della leggibilità.

Prestazioni Ogni funzione non necessaria, che risulta dalla forzatura di un'architettura di codice simile a getter / setter in PHP, coinvolge il proprio stack frame di memoria al momento dell'invocazione e sta sprecando cicli della CPU.

Leggibilità: la base di codice incorre in righe di codice gonfie, il che influisce sulla navigazione del codice poiché più LOC significa più scorrimento.

Preferenza: Personalmente, come mia regola empirica, prendo il fallimento dell'analisi del codice statico come un segno per evitare di percorrere la strada magica fintanto che in quel momento mi sfuggono evidenti benefici a lungo termine.

fallacies:

Un argomento comune è la leggibilità. Ad esempio, $someobject->widthè più facile da leggere di $someobject->width(). Tuttavia a differenza di un pianeta circumferenceo width, che si può presumere che sia static, un'istanza di un oggetto come $someobject, che richiede una funzione di larghezza, probabilmente prende una misura della larghezza di istanza dell'oggetto.
Pertanto la leggibilità aumenta principalmente a causa di assertivi schemi di denominazione e non nascondendo la funzione che genera un determinato valore di proprietà.

__get / __set utilizza:

  • pre-validazione e pre-sanificazione dei valori di proprietà

  • stringhe ad es

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

    In questo caso generatelatexaderirebbe a uno schema di denominazione di nome_azione + nome_ metodo

  • casi speciali, ovvi

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

Nota: PHP ha scelto di non implementare la sintassi getter / setter. Non sto affermando che i getter / setter sono generalmente cattivi.


6
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

Pronto!


Troppa caldaia. Immagina che questa roba sia in ogni classe. Evita l'IMO
DarkNeuron il

PHP non supporta getter e setter per gli stessi motivi menzionati. Qualsiasi implementazione di questo tipo influisce notevolmente sulle prestazioni dello script lato server.
Joas,

Penso che questo vada contro le proprietà "private". Li incapsuli, ma permetti anche di accedere direttamente.
Koray Küpe,

@ KorayKüpe solo se il getter è definito. Uso molto questo incapsulamento (con molti miglioramenti) e funziona perfettamente. Puoi anche estendere la classe e usarla facilmente in tutto il codice.
Joas

5

Beh, PHP ha metodi magici __get, __set, __issete __unset, che è sempre un inizio. Purtroppo le proprietà OO corrette (capito?) È più che metodi magici. Il problema principale con l'implementazione di PHP è che vengono chiamati metodi magici per tutte le proprietà inaccessibili. Ciò significa che devi ripetere te stesso (ad es. Chiamando property_exists ()) nei metodi magici per determinare se il nome è effettivamente una proprietà del tuo oggetto. E non puoi davvero risolvere questo problema generale con una classe base a meno che tutte le tue classi ereditino da ie. ClassWithProperties, poiché a PHP manca l'ereditarietà multipla.

Al contrario, ti offre nuove classi di stile Pythonproperty() , che ti consentono di definire esplicitamente tutte le tue proprietà. C # ha una sintassi speciale.

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


1
La chiamata di property_exists, class_vars o array_key_exists (vale a dire, verifica se la proprietà esiste davvero) è solo un passo per evitare un errore fatale di runtime. Non sono sicuro che non essere displicenti equivale a essere ripetitivi nella codifica.
Davis Peixoto,

1
Giusto. Ma in Python e C # questa ripetizione non è necessaria. Penso che sia un punto di forza.
Emanuel Landeholm,

4

Ho fatto un esperimento usando il metodo magico __call. Non sono sicuro se dovrei pubblicarlo (a causa di tutti gli avvisi "NON UTILIZZARE METODI MAGICI" nelle altre risposte e commenti), ma lo lascerò qui ... nel caso qualcuno lo trovasse 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];
    }
}

Aggiungi quel metodo sopra nella tua classe, ora puoi digitare:

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


In questo modo puoi ottenere / impostare tutto nella tua classe se esiste, quindi se ne hai bisogno solo per alcuni elementi specifici, puoi utilizzare una "lista bianca" come filtro.

Esempio:

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];
    }
}

Ora puoi solo ottenere / impostare "foo" e "fee".
Puoi anche utilizzare quella "lista bianca" per assegnare nomi personalizzati per accedere ai tuoi var.
Per esempio,

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

Con quell'elenco ora puoi digitare:

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

.
.
.
È tutto.


Doc: __call () viene attivato quando si invocano metodi inaccessibili in un contesto di oggetto.


Il problema con tutte queste soluzioni "magiche" è che usano semplicemente questi metodi magici perché sono lì e sono utili perché il problema richiesto è semplice e generico. Una volta lasciato questo livello di problema generico, incontrerai requisiti specifici che non possono essere risolti con un semplice metodo magico, ma richiederebbero un metodo magico molto complesso - o setter e getter codificati individuali.
Sven,

2

Dopo aver letto gli altri consigli, sono propenso a dire che:

Come regola GENERICA , non definirai sempre setter per TUTTE le proprietà, specialmente quelle "interne" (semafori, flag interni ...). Le proprietà di sola lettura non avranno setter, ovviamente, quindi alcune proprietà avranno solo getter; ecco dove __get () viene a ridurre il codice:

  • definire un __get () (getter globali magici) per tutte quelle proprietà simili,
  • raggruppali in array in modo che:
    • condivideranno caratteristiche comuni: i valori monetari verranno / potrebbero venire formattati correttamente, le date in un layout specifico (ISO, USA, Intl.), ecc.
    • il codice stesso può verificare che solo le proprietà esistenti e consentite vengano lette utilizzando questo metodo magico.
    • ogni volta che è necessario creare una nuova proprietà simile, dichiararla e aggiungerne il nome alla matrice corretta ed è fatta. È molto più VELOCE che definire un nuovo getter, forse con alcune righe di codice RIPETUTE più volte nel codice di classe.

Sì! potremmo anche scrivere un metodo privato per farlo, ma anche in questo caso avremo MOLTI metodi dichiarati (memoria ++) che finiranno per chiamare un altro metodo, sempre lo stesso. Perché semplicemente non scrivere un metodo SINGOLO per domarli tutti ...? [Sì! gioco di parole assolutamente inteso! :)]

I setter magici possono anche rispondere SOLO a proprietà specifiche, quindi tutte le proprietà del tipo di data possono essere schermate rispetto a valori non validi in un solo metodo. Se le proprietà del tipo di data fossero elencate in un array, i loro setter possono essere definiti facilmente. Solo un esempio, ovviamente. ci sono troppe situazioni.

A proposito di leggibilità ... Beh ... Questo è un altro dibattito: non mi piace essere legato agli usi di un IDE (in effetti, non li uso, tendono a dirmi (e costringermi ) come scrivi ... e mi piacciono i codici di "bellezza"). Tendo ad essere coerente sulla denominazione, quindi usare ctag e un paio di altri aiuti è sufficiente per me ... Comunque: una volta che tutti questi setter e getter magici sono fatti, scrivo gli altri setter che sono troppo specifici o "speciali" per essere generalizzato in un metodo __set (). E questo copre tutto ciò di cui ho bisogno per ottenere e impostare le proprietà. Certo: non c'è sempre un terreno comune, o ci sono così poche proprietà che non vale la pena di codificare un metodo magico, e poi c'è ancora la vecchia buona coppia setter / getter tradizionale.

I linguaggi di programmazione sono proprio questo: linguaggi artificiali umani. Quindi, ognuno di essi ha la sua intonazione o accento, sintassi e sapore, quindi non pretendo di scrivere un codice Ruby o Python usando lo stesso "accento" di Java o C #, né scriverei JavaScript o PHP per assomigliare Perl o SQL ... Usali nel modo in cui sono destinati a essere utilizzati.


1

In generale, il primo modo è più popolare in generale perché quelli con precedenti conoscenze di programmazione possono facilmente passare a PHP e svolgere il lavoro in modo orientato agli oggetti. Il primo modo è più universale. Il mio consiglio sarebbe di attenersi a ciò che è provato e vero in molte lingue. Quindi, quando e se usi un'altra lingua, sarai pronto per ottenere qualcosa ( invece di passare il tempo a reinventare la ruota ).


0

Esistono molti modi per creare il codice sorgente in una convenzione netbeans. Questo è carino. Rende così più facile === FALSO. Usa il tradizionale, specialmente se non sei sicuro di quale delle proprietà debba essere incapsulata e quale no. Lo so, è un codice boi .... pla ..., ma per i lavori di debug e molti altri pensano che sia il modo migliore e chiaro. Non passare troppo tempo con migliaia di arti a creare semplici getter e setter. Non puoi implementare anche alcuni schemi di progettazione come la regola demeter e così via, se usi magie. In situazioni specifiche puoi usare magic_calls o per soluzioni piccole, veloci e chiare. Sicuramente potresti creare soluzioni per gli schemi del design in questo modo, ma perché renderti più difficile vivere.


0

Convalida + formattazione / derivazione dei valori

I setter ti consentono di convalidare i dati e i getter ti consentono di formattare o derivare i dati. Gli oggetti ti consentono di incapsulare i dati e il loro codice di convalida e formattazione in un pacchetto accurato che incoraggia la DRY.

Ad esempio, considera la seguente semplice classe che contiene una data di nascita.

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;
    }
}

Ti consigliamo di confermare che il valore impostato è

  • Una data valida
  • Non in futuro

E non vuoi fare questa validazione su tutta la tua applicazione (o su più applicazioni per quella materia). Invece, è più facile rendere protetta o privata la variabile membro (al fine di rendere il setter l'unico punto di accesso) e convalidare nel setter perché in questo modo saprai che l'oggetto contiene una data di nascita valida, indipendentemente da quale parte del applicazione da cui proviene l'oggetto e se si desidera aggiungere altra convalida, è possibile aggiungerlo in un unico posto.

Si potrebbe desiderare di aggiungere più formattatori che operano sullo stesso cioè variabile membro getAge()e getDaysUntilBirthday()e si potrebbe desiderare di far rispettare un formato configurabile in getBirthDate()base al paese. Perciò io preferisco sempre l'accesso ai valori tramite getter al contrario di miscelazione $date->getAge()con $date->birth_date.

getter e setter sono utili anche quando si estendono oggetti. Ad esempio, supponiamo che l'applicazione sia necessaria per consentire date di nascita di oltre 150 anni in alcuni luoghi ma non in altri. Un modo per risolvere il problema senza ripetere alcun codice sarebbe quello di estendere l' BirthDateoggetto e inserire la convalida aggiuntiva nel 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);
    }
}

Tuttavia, molte volte è necessario convalidare le proprietà insieme (e non solo individualmente). Penso che consentire "setter" significhi che anche tu non stai catturando il contesto. La convalida dovrebbe essere effettuata su base contestuale. Inoltre, sarai costretto a controllare alcuni flag "isValid" su ogni metodo che hai (ed eseguire la convalida se è falso). Detto questo, i setter forniscono un modo utile per suggerire il tipo, ad esempio quando si possiede una proprietà che si desidera essere un oggetto valore (es. Denaro).
prograhammer,

Non capisco cosa intendi per essere stato costretto a controllare un flag "isValid"? Se l'unico modo per impostare valori è tramite setter che eseguono la validazione, allora sai che i dati sono validi dal fatto che sono stati impostati con successo. Se è necessario convalidare le proprietà insieme, è possibile scrivere un metodo di convalida comune chiamato dai setter di tali proprietà.
FuzzyTree,

Supponi di avere una classe di dipendenti con setHirede setHireDate. Non è valido per consentire a qualcuno di impostare una data di assunzione senza impostare anche il dipendente come assunto. Ma non è possibile imporlo. Se lo imponi in uno di questi setter, allora stai forzando l'ordine di "impostazione", e questo richiede una maggiore lettura del codice da uno sviluppatore per saperlo. Quindi quando vai a fare un metodo come quello $employee->promote($newPosition);devi controllare un flag per vedere se la validazione è stata fatta o supporre che non sia stata fatta e farlo di nuovo (ridondante).
prograhammer,

Invece, cattura le interazioni. Forse $employee->updateWorkStatus($hired, $hireDate);o se più avanzato $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. Ora puoi convalidare nel contesto di cui hai bisogno e decidere se è necessaria alcuna ulteriore convalida.
prograhammer

updateWorkStatus è essenzialmente una funzione setter che imposta 2 invece di 1 valore ma il concetto è lo stesso. Questo è un modo per farlo, ma puoi anche inserire la convalida contestuale in un metodo comune che viene eseguito solo quando tutte le proprietà che devono essere convalidate insieme sono impostate, ovvero la parte contestuale della convalida viene chiamata sia da setHiredDate che da setHired ma verrebbe eseguita se sia isset assunto che isset assuntiDate fossero vere.
FuzzyTree,

0

Questo post non riguarda in particolare __gete, __setma piuttosto, __callche è la stessa idea tranne che per la chiamata del metodo. Di norma, sto alla larga da qualsiasi tipo di metodo magico che consenta il sovraccarico per le ragioni descritte nei commenti e nei messaggi TUTTAVIA , di recente mi sono imbattuto in un'API di terze parti che utilizzo che utilizza un SERVIZIO e un SUB-SERVIZIO, ad esempio :

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

La parte importante di questo è che questa API ha tutto lo stesso tranne l'azione secondaria, in questo caso doActionOne. L'idea è che lo sviluppatore (io e altri che utilizziamo questa classe) potrebbe chiamare il sottoservizio per nome invece di qualcosa come:

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

Potrei invece fare:

 $myClass->doActionOne($args);

Per hardcode questo sarebbe solo un sacco di duplicazione (questo esempio ricorda molto vagamente il codice):

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();
    }

Ma con il metodo magico di __call()sono in grado di accedere a tutti i servizi con metodi dinamici:

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

Il vantaggio di questa chiamata dinamica per la restituzione dei dati è che se il fornitore aggiunge un altro servizio secondario, non devo aggiungere un altro metodo nella classe o creare una classe estesa, ecc. Non sono sicuro che sia utile per nessuno, ma ho pensato che vorrei mostrare un esempio in cui __set, __get, __call, ecc può essere un'opzione per l'esame in quanto la funzione primaria è il ritorno di dati.


MODIFICARE:

Per coincidenza, l'ho visto pochi giorni dopo la pubblicazione che delinea esattamente il mio scenario. Non è l'API a cui mi riferivo, ma l'applicazione dei metodi è identica:

Sto usando API correttamente?


-2

Aggiornamento: non usare questa risposta poiché questo è un codice molto stupido che ho trovato mentre imparo. Usa semplicemente getter e setter, è molto meglio.


Di solito uso quel nome di variabile come nome della funzione e aggiungo un parametro opzionale a quella funzione, quindi quando quel parametro facoltativo viene riempito dal chiamante, quindi impostarlo sulla proprietà e restituire $ questo oggetto (concatenamento) e quindi quando quel parametro facoltativo non specificato da chiamante, ho appena restituito la proprietà al chiamante.

Il mio esempio:

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;
          }
     }
}

Ora la domanda rimane: come si imposta una proprietà sulla stringa vuota? E come si rileva che l'impostazione di una proprietà sulla stringa vuota non è riuscita e ha funzionato come getter? Basti pensare ai moduli HTML che inviano campi vuoti come stringhe ... E no: l'utilizzo di un valore diverso come NULL come valore predefinito non risolve il problema.
Sven,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.