Getter ve Setter?


203

Ben bir PHP geliştiricisi değilim, bu yüzden PHP'de özel alanlarla (sevdiğim şekilde) saf bir OOP tarzında, açık alıcı / ayarlayıcıları kullanmak için daha popüler olup olmadığını merak ediyorum:

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

veya yalnızca genel alanlar:

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

Teşekkürler


7
Cevaplardan bazı kodları denedikten sonra soruda kullandığınız kodu kullandım. Ne kadar üzücü :-(
sumid

9
PHPstorm ... oluşturmak> alıcılar ve ayarlayıcılar. == galibiyet
DevDonkey

@DevDonkey Hiç kazanmadım. Yapısal verileri tutmak için bunun yerine dizileri kullanın. @: Mark Nesnelerin amacı bu değildir veya değildir. Getters
Kubo2

Yanıtlar:


222

Php magic yöntemlerini __get ve kullanabilirsiniz __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
Sanırım demek istiyorsun __getve __set. İki alt çizgi var, bir değil. Sayfanın sağ tarafına doğrudan bağlantı: php.net/manual/tr/… (Doğru yanıt için +1)
Computerish

28
publicDoğrulama / sanitasyon yoksa mülklere karşı ne fayda sağlar ?
KingCrunch

7
@KingCrunch, bu sadece bir örnek. Güçlü bir kaynak için çok çok kukla bir örnek.
Davis Peixoto

10
Bu gerçekten ayarlayıcı ve alıcı değil. Tipik olarak her özelliği farklı alıcı uygulaması gerekir!
sumid

79
Lütfen yapmayın: Sihirli yöntemlerle, birçok IDE'de (hatta vim) neredeyse tüm kalite ile ilgili özellikleri KAYBEDECEKSİNİZ: otomatik tamamlama, açık PHP mirası, hızlı PHP yorumu ve kullanışlı PHPDoc oluşturma ve çıktı. bakınız stackoverflow.com/a/6184893/490589
Ronan

114

Alıcıları ve ayarlayıcıları neden kullanmalıyım?

  1. Ölçeklenebilirlik : Bir alıcıyı bir proje kodundaki tüm ödevleri aramaktan daha kolay yeniden düzenleyen.
  2. Hata ayıklama : Ayarlayıcılara ve alıcılara kesme noktaları koyabilirsiniz.
  3. Daha temiz : Sihirli işlevler daha az yazı yazmak için iyi bir çözüm değildir, IDE'niz kodu önermez. Hızlı yazan alıcılar için daha iyi şablonlar kullanın.

doğrudan atama ve alıcılar / belirleyiciler



42

Google zaten PHP optimizasyonu hakkında bir kılavuz yayınladı ve sonuç şuydu:

Alıcı ve ayarlayıcı yok PHP optimizasyonu

Ve hayır, sihirli yöntemler kullanmamalısınız . PHP için, Magic Method kötüdür. Neden?

  1. Hata ayıklamak zordur.
  2. Performans üzerinde olumsuz bir etkisi vardır.
  3. Daha fazla kod yazmayı gerektirirler.

PHP Java, C ++ veya C # değildir. PHP farklıdır ve farklı rollerle oynar.


10
Bu fikre katılma eğilimindeyim; o $dog->name = 'fido'daha iyidir $dog->setName('fido'). Bir mülkü gerçekten mutasyona uğratırken (örn: $dog->increaseAge(1)gerekli validasyonu yapan ve bu mülkü mutasyona uğratan bir yöntem oluşturabilirim. Ancak tüm eylemler bu anlamda gerçekten mutasyon gerektirmez.
Charlie Schliesser 23:13

11
Makale gelmez "demek değil ," o naif ayarlayıcılar ve alıcılar 'diyor bu.
Brett Santore


13
Google tarafından yazılan ve "PHP performans ipuçları" başlığına sahip bir makalenin iyi kodlama stili değil, hızlı kod yürütme önermek üzere tasarlandığını varsayalım. Setters ve getters ile ilgilenen bölüm "Naif seters ve getters yazmaktan kaçının" olarak etiketlenmiştir ve kod örneği tam olarak şöyledir: Naive. Herhangi bir doğrulama olmadan sadece bir değişken ayarlar ve alır. BU tür ayarlayıcı / alıcı işe yaramaz. Bir ayarlayıcı içinde doğrulama yapmak (yalnızca yöntem bağımsız değişkeni için bir tür ipucu kullanın) ayarlayıcıları / alıcıları kullanışlı hale getirecektir, çünkü şimdi kodunuz ne ile uğraştığını Bilmektedir.
Sven

3
bu satır içi stilin daha iyi olduğunu söylemek gibidir. Tabii ki performans daha iyi, ama daha iyi kod mu? Google mühendislerinin yine de php kullandığını bilmiyordum
Claudiu Creanga

13

Kapsülleme herhangi bir OO dilinde önemlidir, popülerliğin bununla hiçbir ilgisi yoktur. PHP gibi dinamik olarak yazılan dillerde özellikle yararlıdır, çünkü bir özelliğin ayarlayıcıları kullanmadan belirli bir türde olmasını sağlamanın çok az yolu vardır.

PHP'de bu çalışır:

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

Java'da şunları yapmaz:

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

Sihirli yöntemleri ( __getve __set) kullanmak da çalışır, ancak yalnızca geçerli kapsamın erişebileceğinden daha düşük görünürlüğe sahip bir özelliğe erişirken. Düzgün kullanılmazsa, hata ayıklamaya çalışırken kolayca baş ağrısı verebilir.


7
Harfler ve ayarlayıcı kapsülleme getirmez. Encapsulation == nesneleri dışarıda vermek yerine kendi verileriyle bir şeyler yaparlar. Harfler ve ayarlayıcılar, PHP gibi dinamik olarak yazılan dillerde yazı zorlamak için bir araç değildir.
smentek

14
@smentek: Kapsülleme işleminin gerçekte en azından yarısını açıkça kaçırıyorsunuz.
netcoder

2
Bunu arayan herkes için bir güncelleme olarak, PHP 7.4 yazılan özellik desteği ile gelecek. Böylece ilk örnekte $barbir olarak ilan edebilirsiniz int: wiki.php.net/rfc/typed_properties_v2
Kevin

7

__Call işlevini kullanmayı tercih ediyorsanız, bu yöntemi kullanabilirsiniz. İle çalışır

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

2
@ krzysztof-przygoda: Bu "Sihirli Yöntemler" her zaman bir bedeli vardır. Özyineleme kullanmak zorundalar property_exists(get_class($this), $name)ve özyineleme yavaş. Bunu önbellekleme ile hafifletmenin bir yolu var, ancak yine de alıcıları ve ayarlayıcıları elle oluşturmaktan daha yavaş olacak. Bunu sadece alternatif olarak yazdım. Aslında "Sihirli Yöntemler" i kullanmanızı önermiyorum. Alıcıları ve ayarlayıcıları oluşturmak için ek süre genellikle önemsizdir.
J-Rou

7

Burada zaten büyük ve saygın cevaplara ek olarak, ben hiçbir setters / alıcılar PHP genişletmek istiyorum.

PHP'nin alıcı ve ayarlayıcı sözdizimi yoktur . Dave tarafından belirtildiği gibi, özellik arama sürecini "kancalamak" ve geçersiz kılmak içinalt sınıf veya sihirli yöntemler sağlar.

Magic , tembel programcıların , bir projeye aktif olarak dahil olduğumuz ve onu yakından bildiğimiz bir zamanda daha az kodla daha fazlasını yapmamıza izin verir , ancak genellikle okunabilirlik pahasına.

Performans PHP'de alıcı / ayarlayıcı benzeri bir kod mimarisini zorlamaktan kaynaklanan her gereksiz işlev, çağrıldığında kendi bellek yığını çerçevesini içerir ve CPU döngülerini boşa harcar.

Okunabilirlik: Kod tabanı, daha fazla LOC daha fazla kaydırma anlamına geldiği için kod gezintisini etkileyen şişkin kod satırlarına neden olur.

Tercih: Şahsen, temel kuralım olarak, uzun vadeli faydalar o zamanlar elimde olduğu sürece büyülü yolda gitmekten kaçınmak için statik kod analizinin başarısızlığını bir işaret olarak alıyorum.

Yanılgı:

Ortak bir argüman okunabilirliktir. Örneğin $someobject->widthokumak daha kolay $someobject->width(). Bir gezegen Ancak farklı circumferenceya da widthkabul edilebilir olmak staticgibi bir nesnenin, örneğin $someobjectbir genişlik işlevi gerektiren, muhtemelen nesnenin örnek genişliğinin ölçümü yapılır.
Bu nedenle, okunabilirlik, belirli bir özellik değeri veren işlevi gizleyerek değil, temel olarak iddialı adlandırma şemaları nedeniyle artar.

__get / __set kullanır:

  • mülkiyet değerlerinin ön validasyonu ve ön sanitasyonu

  • dizeler ör.

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

    Bu durumda generatelatex, actionname + methodname adlandırma düzenine bağlı kalırsınız

  • özel, belirgin durumlar

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

Not: PHP getter / setter sözdizimini uygulamamayı tercih etti. Getters / setter genellikle kötü olduğunu iddia etmiyorum.


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

Hazır!


Çok fazla kazan plakası. Bu şeylerin her sınıfta olduğunu düşünün. IMO'dan Kaçının
DarkNeuron

PHP, bahsettiğiniz aynı nedenlerle alıcıları ve ayarlayıcıları desteklemez. Bu tür herhangi bir uygulama, sunucu tarafı komut dosyasının performansını ciddi şekilde etkiler.
joas

Bunun 'özel' mülklere aykırı olduğunu düşünüyorum. Bunları kapsüllersiniz, ancak doğrudan erişime de izin verirsiniz.
Koray Küpe

@ KorayKüpe yalnızca alıcı tanımlanmışsa. Bu kapsüllemeyi çok kullanıyorum (birçok iyileştirme ile) ve mükemmel çalışıyor. Ayrıca sınıfı genişletebilir ve tüm kodda kolayca kullanabilirsiniz.
joas

5

Eh, PHP sihirli yöntemler var __get, __set, __issetve __unsether zaman bir başlangıç olan. Ne yazık ki uygun (olsun?) OO özellikleri sihirli yöntemlerden daha fazlasıdır. PHP'nin uygulanmasındaki temel sorun, erişilemeyen tüm özellikler için sihirli yöntemlerin çağrılmasıdır . Bu, adın gerçekten nesnenizin bir özelliği olup olmadığını belirlerken sihirli yöntemlerde Kendinizi Tekrarlamanız (örneğin, property_exists () yöntemini çağırarak) anlamına gelir . Ve tüm sınıflarınız ie miras almadıkça, bu genel problemi bir temel sınıfla gerçekten çözemezsiniz. ClassWithProperties, çünkü PHP birden fazla kalıtımdan yoksundur.

Buna karşılık, Python yeni stil sınıfları size verir property(), bu da tüm özelliklerinizi açıkça tanımlamanızı sağlar. C # özel sözdizimine sahiptir.

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


1
Property_exists, class_vars veya array_key_exists öğelerini çağırmak (örneğin, özelliğin gerçekten var olup olmadığını kontrol etmek) bir çalışma zamanı ölümcül hatasını önlemek için sadece bir adımdır. Uyuşmaz olmanın kodlamada tekrarlayan ile aynı olup olmadığından emin değilim.
Davis Peixoto

1
Yeterince adil. Ancak Python ve C # 'da bu tekrarlamaya gerek yoktur. Bunun bir güç olduğunu düşünüyorum.
Emanuel Landeholm

4

__Call sihirli yöntemini kullanarak bir deneme yaptım. Eğer diğer cevaplar ve yorumlar "tüm" BÜYÜ YÖNTEMLERİ KULLANMAYIN "uyarıları nedeniyle ben sonrası gerekir emin değilim ama ben burada bırakacaktır .. sadece biri yararlı bulursanız.


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

Sadece bu yöntemi sınıfınıza ekleyin, şimdi şunları yazabilirsiniz:

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


Bu şekilde sınıfınızdaki herşeyi varsa alabilir / ayarlayabilirsiniz, böylece yalnızca birkaç belirli öğeye ihtiyacınız varsa, filtre olarak bir "beyaz liste" kullanabilirsiniz.

Misal:

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

Şimdi sadece "foo" ve "ücret" alabilirsiniz / ayarlayabilirsiniz.
Bu "beyaz listeyi", değişkenlerinize erişmek üzere özel adlar atamak için de kullanabilirsiniz.
Örneğin,

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

Bu listeye şimdi şunları yazabilirsiniz:

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

.
.
.
Bu kadar.


Doc: __call () , bir nesne bağlamında erişilemez yöntemler çağrıldığında tetiklenir.


Tüm bu "sihirli" çözümlerin sorunu, sadece bu sihirli yöntemleri kullanmalarıdır çünkü oradalar ve yararlıdırlar çünkü sorulan problem basit, genel bir çözümdür. Bu seviyedeki genel problemden ayrıldıktan sonra, basit bir sihirli yöntemle çözülemeyen, ancak çok karmaşık bir sihirli yöntem veya bireysel, kodlanmış ayarlayıcılar ve alıcılar gerektiren belirli gereksinimlerle karşılaşacaksınız.
Sven

2

Diğer tavsiyeleri okuduktan sonra şunu söylemeye meyilliyim:

Bir itibariyle GENERIC kural, her zaman için ayarlayıcılar tanımlamak olmaz TÜM (... semaforları, iç bayrakları) özelliklerine, özel olarak "iç" olanları. Salt okunur özelliklerin ayarlayıcıları olmayacağı açıktır, bu nedenle bazı özelliklerin yalnızca alıcıları olacaktır; __get () kodu küçültmek için buraya gelir:

  • benzer tüm bu özellikler için bir __get () (büyülü küresel alıcılar) tanımlayın,
  • bunları dizilerde gruplayın:
    • ortak özellikleri paylaşacaklardır: parasal değerler düzgün biçimlendirilmiş / belirli bir düzende (ISO, ABD, Uluslararası) vb.
    • kodun kendisi bu büyülü yöntemi kullanarak sadece mevcut ve izin verilen özelliklerin okunduğunu doğrulayabilir.
    • yeni bir benzer özellik oluşturmanız gerektiğinde, bunu bildirmeniz ve adını doğru diziye eklemeniz yeterlidir. Bu , belki de bazı kod satırları tekrar tekrar sınıf kodu üzerinde REPEATED ile yeni bir alıcı tanımlamaktan daha hızlı .

Evet! Bunu yapmak için özel bir yöntem de yazabiliriz, ancak yine de, her zaman aynı yöntemi çağıran başka bir yöntem (++ bellek) bildirmiş oluruz. Neden hepsini yönetmek için TEK bir yöntem yazmıyorsunuz ? [Evet! pun kesinlikle amaçlanan! :)]

Sihirli ayarlayıcılar SADECE belirli özelliklere de yanıt verebilir, böylece tüm tarih türü özellikleri yalnızca bir yöntemde geçersiz değerlere karşı taranabilir. Tarih türü özellikleri bir dizide listelenmişse, ayarlayıcıları kolayca tanımlanabilir. Tabii ki sadece bir örnek. çok fazla durum var.

Hakkında okunabilirliği ... Eh ... Bu başka bir tartışma var: Ben (aslında bir IDE kullanımlara bağlı kalmayı sevmem, onları kullanmayın, bunlar (ve söyle eğilimindedir zorlamak nasıl beni) yazmak ... ve ben "güzellik" kodlama hakkında benim sevdim var). Adlandırma konusunda tutarlı olma eğilimindeyim, bu yüzden ctags ve birkaç başka yardım kullanmak benim için yeterli ... Her neyse: tüm bu sihirli ayarlayıcılar ve alıcılar yapıldıktan sonra, çok özel veya "özel" olan diğer ayarlayıcıları __set () yöntemiyle genelleştirilmelidir. Bu özellik almak ve özellikleri ayarlamak için ihtiyacım olan her şeyi kapsar. Tabii ki: her zaman ortak bir zemin yoktur veya büyülü bir yöntemi kodlama zahmetine değmeyecek kadar az özellik vardır ve sonra hala eski iyi geleneksel ayarlayıcı / alıcı çifti vardır.

Programlama dilleri sadece: insan yapay dilleri. Yani, her birinin kendi tonlaması veya aksanı, sözdizimi ve lezzeti var, bu yüzden Java veya C # ile aynı "aksanını" kullanarak bir Ruby veya Python kodu yazmak gibi davranmayacağım, ya da benzemek için bir JavaScript veya PHP yazmam Perl veya SQL ... Onları kullanılması gerektiği gibi kullanın.


1

Genel olarak konuşursak, ilk yol genel olarak daha popülerdir, çünkü önceden programlama bilgisine sahip olanlar kolayca PHP'ye geçiş yapabilir ve nesneye yönelik bir şekilde iş yapabilirler. İlk yol daha evrensel. Benim tavsiyem birçok dilde denenmiş ve doğru olana sadık kalmak olacaktır. Daha sonra, başka bir dil ne zaman ve kullanırsanız, bir şeyleri başarmaya hazır olacaksınız ( tekerleği yeniden keşfetmek için zaman harcamak yerine ).


0

Bir netbeans sözleşmesinde kaynak kodu oluşturmanın birçok yolu vardır. Bu güzel. Düşünceleri bu kadar kolaylaştırır === YANLIŞ. Sadece gelenekleri kullanın, özellikle hangi özelliklerden hangisinin kapsülleneceğinden ve hangisinin kapsüllenmediğinden emin değilseniz. Biliyorum, bu bir boi .... pla ... kodu, ama hata ayıklama işleri ve diğer birçok şey için daha iyi, net bir yol olduğunu düşünüyor. Sanatın basit alıcıları ve ayarlayıcıları yapmak için çok fazla zaman harcamayın. Eğer sihir kullanırsanız, demeter kuralı gibi bazı tasarım desenlerini çok fazla uygulayamazsınız. Belirli durumlarda magic_calls veya küçük, hızlı ve net çözümler için kullanabilirsiniz. Elbette tasarım desenleri için de bu şekilde çözümler üretebilirsiniz, ancak neden sizi daha zor yaşamanız gerekir.


0

Değerleri Doğrulama + Biçimlendirme / Türetme

Ayarlayıcılar verileri doğrulamanıza ve alıcılar verileri biçimlendirmenize veya türetmenize olanak tanır. Nesneler, verileri ve doğrulama ve biçimlendirme kodunu DRY'yi teşvik eden düzgün bir pakete kapsüllemenizi sağlar.

Örneğin, doğum tarihi içeren aşağıdaki basit sınıfı düşünün.

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

Ayarlanan değerin geçerli olduğunu doğrulamak isteyeceksiniz

  • Geçerli bir tarih
  • Gelecekte değil

Ve bu doğrulamayı uygulamanızın her yerinde (veya bu konu için birden fazla uygulamada) yapmak istemezsiniz. Bunun yerine, üye değişkenini korumalı veya özel yapmak (ayarlayıcıyı tek erişim noktası yapmak için) ve ayarlayıcıda doğrulamak daha kolaydır, çünkü o zaman nesnenin, uygulama nesneden geldi ve daha fazla doğrulama eklemek istiyorsanız, o zaman tek bir yerde ekleyebilirsiniz.

Aynı üye değişken üzerinde çalışan birden çok biçimlendirici eklemek isteyebilirsiniz, ör. getAge() ve getDaysUntilBirthday()ve içinde yapılandırılabilir bir biçim zorlamak isteyebilirsiniz getBirthDate()yerel ayara bağlı. Karıştırma aksine nedenle ben sürekli alıcılar üzerinden değerleri erişen tercih $date->getAge()ile $date->birth_date.

alıcılar ve ayarlayıcılar nesneleri genişlettiğinizde de yararlıdır. Örneğin, uygulamanızın bazı yerlerde 150'den fazla doğum tarihine izin vermek için gerekli olduğunu, ancak diğerlerinde olmadığını düşünün. Herhangi bir kodu tekrarlamadan sorunu çözmenin bir yolu, BirthDatenesneyi genişletmek ve ayarlayıcıya ek doğrulama koymak olacaktır.

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

Ancak, birçok kez özellikleri birlikte doğrulamanız gerekir (ve yalnızca bireysel olarak değil). Bence "ayarlayıcılara" izin vermek, bağlamı da yakalayamayacağınız anlamına gelir. Doğrulama, bağlamsal olarak yapılmalıdır. Ayrıca, sahip olduğunuz her yöntemde bazı "isValid" bayrağını kontrol etmek zorunda kalacaksınız (ve yanlışsa doğrulama işlemini gerçekleştireceksiniz). Bununla birlikte, ayarlayıcılar, bir Değer Nesnesi (yani Para) olmasını istediğiniz bir özelliğe sahip olduğunuzda olduğu gibi, tür ipucu için yararlı bir yol sağlar.
prograhammer

Bir "isValid" bayrağını kontrol etmek zorunda kalmakla ne demek istediğini anlamıyorum? Değerleri ayarlamanın tek yolu, doğrulama gerçekleştiren ayarlayıcılardan geçiyorsa, verilerin başarıyla ayarlanmış olması nedeniyle geçerli olduğunu bilirsiniz. Özellikleri birlikte doğrulamanız gerekiyorsa, bu özelliklerin ayarlayıcılarının çağırdığı ortak bir doğrulama yöntemi yazabilirsiniz.
FuzzyTree

Diyelim ki setHiredve ile çalışan bir sınıfınız var setHireDate. Çalışanı işe alınmış olarak ayarlamadan birisinin işe alım tarihi belirlemesine izin vermek geçerli değildir. Ama bunu zorlamanın bir yolu yok. Bu ayarlayıcılardan birinde uygularsanız, "ayar" sırasını zorlarsınız ve bunun için bir geliştiricinin bilmesi için daha fazla kod okuması gerekir. Daha sonra, sizin gibi bir yöntem yapmaya gittiğinizde, $employee->promote($newPosition);doğrulama işleminin yapılıp yapılmadığını veya yapılmadığını varsayarak bir bayrağı kontrol etmeniz ve tekrar yapmanız gerekir (gereksiz).
prograhammer

Bunun yerine, etkileşimleri yakalayın. Belki $employee->updateWorkStatus($hired, $hireDate);ya da daha gelişmişse $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. Artık ihtiyacınız olan bağlamda doğrulayabilir ve ekstra doğrulama gerekip gerekmediğine karar verebilirsiniz.
prograhammer

updateWorkStatus aslında 1 değeri yerine 2'yi ayarlayan bir ayarlayıcı işlevidir, ancak kavram aynıdır. Bunu yapmanın bir yolu budur, ancak bağlamsal doğrulamayı yalnızca birlikte doğrulanması gereken tüm özellikler ayarlandığında çalıştırılan ortak bir yönteme koyabilirsiniz; yani doğrulamanın bağlamsal kısmı hem setHiredDate hem de setHired tarafından çağrılır, ancak yalnızca çalışır hem isset işe alınmış hem de isset işe alınmışTarih doğruydu.
FuzzyTree

0

Bu yazı özellikle ilgili değildir __getve __setdaha çok __callyöntem çağrısı dışında aynı fikirdir. Kural olarak, yorumlarda ve yazılarda belirtilen nedenlerle aşırı yüklemeye izin veren her türlü sihirli yöntemden uzak duruyorum , ancak son zamanlarda kullandığım bir SERVICE ve SUB-SERVICE kullanan bir üçüncü taraf API'sına girdim, örnek :

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

Bunun önemli kısmı, bu API'nın bu durumda alt eylem hariç her şeye sahip olmasıdır doActionOne. Fikir geliştirici (ben ve bu sınıfı kullanan diğerleri) gibi bir şey yerine alt hizmet adıyla çağırabilir:

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

Bunun yerine yapabilirim:

 $myClass->doActionOne($args);

Sabit kodlamak için bu çok fazla çoğaltma olacaktır (bu örnek koda çok gevşek bir şekilde benzemektedir):

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

Ancak sihirli yöntemiyle __call()tüm hizmetlere dinamik yöntemlerle erişebiliyorum:

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

Veri dönüşü için bu dinamik çağrının yararı, satıcı başka bir alt hizmet eklerse, sınıfa başka bir yöntem eklemek veya genişletilmiş bir sınıf, vb. Oluşturmak zorunda olmadığımdır. herkes, ama ben bir örnek göstermek düşündüm __set, __get, __callbirincil işlevi verilerinin dönüş olduğundan, vb değerlendirilmesi için bir seçenek olabilir.


DÜZENLE:

Tesadüfen, bunu yayınladıktan birkaç gün sonra gördüğüm senaryo tam olarak senaryomu özetliyor. Bahsettiğim API değil ama yöntemlerin uygulaması aynı:

API'yi doğru kullanıyor muyum?


-2

Güncelleme: Bu cevabı kullanmayın, çünkü bu öğrenirken bulduğum çok aptal bir kod. Sadece düz alıcı ve ayarlayıcı kullanın, çok daha iyi.


Genellikle bu değişken adını işlev adı olarak kullanırım ve isteğe bağlı parametre bu işleve, bu isteğe bağlı parametre arayan tarafından dolduğunda eklenir, sonra özelliğe ayarlayın ve $ bu nesneyi (zincirleme) döndürün ve sonra bu isteğe bağlı parametre tarafından belirtilmediğinde arayan, ben sadece özelliği arayan dönmek.

Örneğim:

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

Şimdi soru kaldı: Bir özelliği boş dizeye nasıl ayarlarsınız? Ve boş dizeye bir özellik ayarlamanın gerçekten başarısız olduğunu ve alıcı olarak çalıştığını nasıl tespit edersiniz? Boş alanları dize olarak gönderen HTML formlarını düşünün ... Hayır: Varsayılan değer olarak NULL gibi farklı bir değer kullanmak sorunu çözmez.
Sven
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.