Getter dan Setter?

203

Saya bukan pengembang PHP, jadi saya ingin tahu apakah di PHP lebih populer untuk menggunakan pengambil / penyetel eksplisit, dengan gaya OOP murni, dengan bidang pribadi (seperti yang saya suka):

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

atau hanya bidang publik:

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

Terima kasih

Menandai
sumber
7
Setelah mencoba beberapa kode dari jawaban saya menggunakan kode yang Anda gunakan dalam pertanyaan. Betapa menyedihkan :-(
sumid
9
PHPstorm ... menghasilkan> getter dan setter. == win
DevDonkey
@DevDonkey Tidak menang sama sekali. Untuk menyimpan data terstruktur, gunakan array sebagai gantinya. @: Tandai Ini bukan tujuan atau tujuan objek. Getters dan setter jahat: yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Kubo2

Jawaban:

222

Anda dapat menggunakan metode sulap php __get dan __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;
  }
}
?>
Davis Peixoto
sumber
15
Saya pikir maksud Anda __getdan __set. Ada dua garis bawah, bukan satu. Berikut adalah tautan langsung ke bagian kanan halaman: php.net/manual/en/… (+1 untuk jawaban yang benar)
Computerish
28
Apa manfaatnya terhadap publicproperti, jika tidak ada validasi / sanitasi?
KingCrunch
7
@ KingCrunch, ini hanya sebuah contoh. Contoh yang sangat sangat bodoh untuk sumber daya yang kuat.
Davis Peixoto
10
Itu tidak benar-benar setter dan pengambil. Biasanya saya perlu untuk setiap properti implementasi pengambil yang berbeda!
sumid
79
Tolong jangan: Dengan metode ajaib, Anda akan KURANGI hampir semua fitur terkait kualitas, di banyak IDE (bahkan vim): penyelesaian otomatis, pewarisan PHP eksplisit, interpretasi PHP cepat & pembuatan & keluaran PHPDoc yang bermanfaat. lih. stackoverflow.com/a/6184893/490589
Ronan
113

Mengapa menggunakan getter dan setter?

  1. Skalabilitas : Lebih mudah mereaksikan pengambil daripada mencari semua tugas var dalam kode proyek.
  2. Debugging : Anda dapat menempatkan breakpoint di setter dan getter.
  3. Pembersih : Fungsi sulap bukan solusi yang baik untuk menghasilkan lebih sedikit, IDE Anda tidak akan menyarankan kode. Lebih baik gunakan templat untuk pengambil yang rajutan cepat.

penugasan langsung dan pengambil / penentu

Wiliam
sumber
7
Jika Anda menggunakan @property, IDE Anda akan menyarankan kode (diuji dengan PhpStorm 7)
Alex2php
41

Google sudah menerbitkan panduan tentang optimasi PHP dan kesimpulannya adalah:

Tidak ada pengambil dan penyetel Mengoptimalkan PHP

Dan tidak, Anda tidak harus menggunakan metode sihir . Untuk PHP, Metode Sihir itu jahat. Mengapa?

  1. Mereka sulit di-debug.
  2. Ada dampak kinerja negatif.
  3. Mereka membutuhkan penulisan lebih banyak kode.

PHP bukan Java, C ++, atau C #. PHP berbeda dan dimainkan dengan peran yang berbeda.

magallanes
sumber
10
Saya cenderung setuju dengan gagasan itu; itu $dog->name = 'fido'lebih baik daripada $dog->setName('fido'). Ketika benar-benar mengubah properti (mis: $dog->increaseAge(1)Saya dapat membangun metode yang melakukan validasi yang diperlukan dan mengubah properti itu. Tetapi tidak semua tindakan benar-benar memerlukan mutasi dalam pengertian itu.
Charlie Schliesser
11
Artikel itu tidak mengatakan " jangan ", itu mengatakan 'setter naif dan getter'.
Brett Santore
13
Aman untuk berasumsi bahwa artikel yang ditulis oleh Google yang memiliki judul "tips kinerja PHP" TIDAK dimaksudkan untuk menyarankan gaya pengkodean yang baik, tetapi eksekusi kode yang cepat. Bab yang membahas tentang setter dan getter diberi label "Hindari menulis setter dan getah yang naif", dan contoh kode adalah persis seperti itu: Naif. Ini menetapkan dan mendapatkan hanya variabel tanpa validasi apa pun. Penyetel / pengambil semacam ini tidak berguna. Melakukan validasi di dalam setter (cukup gunakan tip tipe untuk argumen metode) akan membuat setter / getter berguna karena sekarang kode Anda TAHU apa yang sedang dihadapi.
Sven
3
ini seperti mengatakan bahwa gaya inline lebih baik. tentu saja kinerjanya lebih baik, tetapi apakah itu kode yang lebih baik? Saya tidak tahu insinyur google menggunakan php
Claudiu Creanga
13

Enkapsulasi penting dalam bahasa OO apa pun, popularitas tidak ada hubungannya dengan itu. Dalam bahasa yang diketik secara dinamis, seperti PHP, ini sangat berguna karena ada sedikit cara untuk memastikan properti adalah tipe tertentu tanpa menggunakan setter.

Di PHP, ini berfungsi:

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

Di Jawa, itu tidak:

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

Menggunakan metode ajaib ( __getdan __set) juga berfungsi, tetapi hanya ketika mengakses properti yang memiliki visibilitas lebih rendah daripada ruang lingkup saat ini dapat mengakses. Ini dapat dengan mudah membuat Anda sakit kepala ketika mencoba untuk debug, jika tidak digunakan dengan benar.

netcoder
sumber
7
Getters dan setter tidak membawa enkapsulasi. Enkapsulasi == objek melakukan sesuatu dengan datanya sendiri alih-alih memberikannya di luar. Getters dan setter bukan alat untuk menegakkan mengetik dalam bahasa yang diketik secara dinamis seperti PHP.
smentek
14
@smentek: Anda jelas kehilangan setidaknya setengah dari enkapsulasi sebenarnya.
netcoder
2
Sebagai pembaruan untuk ini bagi siapa pun yang melihat, PHP 7.4 akan datang dengan dukungan properti yang diketik. Jadi Anda dapat mendeklarasikan $barsebagai intdalam contoh pertama: wiki.php.net/rfc/typed_properties_v2
Kevin
7

Jika Anda lebih suka menggunakan fungsi __call, Anda dapat menggunakan metode ini. Ini bekerja dengan

  • DAPATKAN>> $this->property()
  • SET => $this->property($value)
  • DAPATKAN>> $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;
    }
}
J-Rou
sumber
2
@ krzysztof-przygoda: Ini "Metode Sihir" selalu datang dengan harga. Mereka harus menggunakan rekursi property_exists(get_class($this), $name)dan rekursi lambat. Ada cara y untuk memitigasi hal ini dengan cache, tetapi masih akan lebih lambat daripada membuat getter dan setter dengan tangan. Saya hanya menulis ini sebagai alternatif. Saya sebenarnya tidak merekomendasikan menggunakan "Metode Sihir". Waktu ekstra untuk membuat getter dan setter biasanya tidak signifikan.
J-Rou
7

Selain jawaban yang sudah sangat bagus dan dihormati di sini, saya ingin mengembangkan PHP yang tidak memiliki setter / getter.

PHP tidak memiliki sintaks pengambil dan penyetel . Ini memberikanmetodesubclassed atau sihir untuk memungkinkan "hooking" dan mengesampingkan proses pencarian properti, seperti yang ditunjukkan oleh Dave .

Magic memungkinkan kita programmer yang malas untuk berbuat lebih banyak dengan lebih sedikit kode pada saat kita secara aktif terlibat dalam suatu proyek dan mengetahuinya secara intim, tetapi biasanya dengan mengorbankan keterbacaan.

Kinerja Setiap fungsi yang tidak perlu, yang dihasilkan dari pemaksaan arsitektur kode pengambil / penyetel-seperti dalam PHP, melibatkan memori tumpukan-bingkai sendiri atas permintaan dan membuang-buang siklus CPU.

Keterbacaan: Basis kode menimbulkan garis kode kembung, yang memengaruhi navigasi kode karena lebih banyak LOC berarti lebih banyak bergulir.

Preferensi: Secara pribadi, sebagai pedoman praktis saya, saya menganggap kegagalan analisis kode statis sebagai tanda untuk menghindari jalan magis selama manfaat jangka panjang yang jelas luput dari saya pada waktu itu.

Kekeliruan:

Argumen yang umum adalah keterbacaan. Misalnya yang $someobject->widthlebih mudah dibaca daripada $someobject->width(). Namun tidak seperti planet circumferenceatau width, yang dapat diasumsikan sebagai static, contoh objek seperti $someobject, yang membutuhkan fungsi lebar, kemungkinan mengambil pengukuran lebar contoh objek.
Oleh karena itu keterbacaan meningkat terutama karena skema penamaan yang asertif dan bukan dengan menyembunyikan fungsi yang menghasilkan nilai properti yang diberikan.

__get / __set gunakan:

  • pra-validasi dan pra-sanitasi nilai properti

  • string misalnya

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

    Dalam hal ini generatelatexakan mematuhi skema penamaan actionname + methodname

  • kasus khusus, jelas

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

Catatan: PHP memilih untuk tidak mengimplementasikan sintaks pengambil / penyetel. Saya tidak mengklaim bahwa getter / setter umumnya buruk.

Lorenz Lo Sauer
sumber
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

Siap!

joas
sumber
Terlalu banyak boilerplate. Bayangkan barang ini ada di setiap kelas. Hindari IMO
DarkNeuron
PHP tidak mendukung getter dan setter untuk alasan yang sama seperti yang Anda sebutkan. Setiap implementasi jenis ini sangat mempengaruhi kinerja skrip sisi server.
joas
Saya pikir ini bertentangan dengan properti 'pribadi'. Anda merangkum mereka, tetapi juga memungkinkan untuk mengakses secara langsung.
Koray Küpe
@ KorayKüpe hanya jika pengambil ditentukan. Saya menggunakan enkapsulasi ini banyak (dengan banyak perbaikan) dan berfungsi dengan baik. Anda juga dapat memperluas kelas dan menggunakannya dalam semua kode dengan mudah.
joas
5

Nah, PHP memang memiliki metode magic __get, __set, __isset& __unset, yang selalu memulai. Sungguh pantas (mengerti?) Properti OO lebih dari sekadar metode ajaib. Masalah utama dengan implementasi PHP adalah bahwa metode ajaib dipanggil untuk semua properti yang tidak dapat diakses. Yang berarti Anda harus Mengulangi Diri Anda (mis. Dengan memanggil property_exists ()) dalam metode ajaib ketika menentukan apakah nama sebenarnya adalah properti dari objek Anda. Dan Anda tidak bisa benar-benar menyelesaikan masalah umum ini dengan kelas dasar kecuali semua kelas Anda mewarisi dari itu. ClassWithProperties, karena PHP tidak memiliki banyak pewarisan.

Sebaliknya, kelas gaya baru Python memberi Anda property(), yang memungkinkan Anda menentukan semua properti Anda secara eksplisit. C # memiliki sintaks khusus.

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

Emanuel Landeholm
sumber
1
Memanggil property_exists, class_vars atau array_key_exists (yaitu, memeriksa apakah properti benar-benar ada) hanyalah langkah untuk menghindari kesalahan fatal runtime. Saya tidak yakin apakah tidak bertingkah sama dengan menjadi berulang dalam pengkodean.
Davis Peixoto
1
Cukup adil. Tetapi dalam Python dan C # pengulangan ini tidak diperlukan. Saya pikir itu kekuatan.
Emanuel Landeholm
4

Saya membuat percobaan menggunakan metode ajaib __call. Tidak yakin apakah saya harus mempostingnya (karena semua peringatan "JANGAN GUNAKAN METODE MAGIK" dalam jawaban dan komentar lain) tetapi saya akan meninggalkannya di sini .. kalau-kalau ada orang yang merasa berguna.


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

Cukup tambahkan metode di atas di kelas Anda, sekarang Anda dapat mengetik:

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


Dengan cara ini Anda bisa mendapatkan / mengatur segala sesuatu di kelas Anda jika ada, jika Anda membutuhkannya hanya untuk beberapa elemen tertentu, Anda bisa menggunakan "daftar putih" sebagai filter.

Contoh:

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

Sekarang Anda hanya bisa mendapatkan / menetapkan "foo" dan "biaya".
Anda juga dapat menggunakan "daftar putih" untuk menetapkan nama khusus untuk mengakses vars Anda.
Sebagai contoh,

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

Dengan daftar itu sekarang Anda dapat mengetik:

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

.
.
.
Itu saja.


Doc: __call () dipicu ketika memanggil metode yang tidak dapat diakses dalam konteks objek.

Sabaz
sumber
Masalah dengan semua solusi "ajaib" ini adalah bahwa mereka hanya menggunakan metode ajaib ini karena ada di sana, dan mereka berguna karena masalahnya adalah sederhana, generik. Setelah Anda meninggalkan tingkat masalah umum ini, Anda akan menemukan persyaratan khusus yang tidak dapat diselesaikan dengan metode sihir sederhana, tetapi akan membutuhkan metode sihir yang sangat kompleks - atau individu, setter dan getter berkode individu.
Sven
2

Setelah membaca saran lainnya, saya cenderung mengatakan bahwa:

Sebagai aturan GENERIC , Anda tidak akan selalu menentukan setter untuk SEMUA properti, khususnya yang "internal" (semaphores, flag internal ...). Properti read -only tidak akan memiliki setter, jadi beberapa properti hanya akan mendapatkan getter; di situlah __get () datang untuk mengecilkan kode:

  • mendefinisikan __get () (getter global gaib) untuk semua properti yang sama,
  • kelompokkan mereka dalam susunan jadi:
    • mereka akan berbagi karakteristik umum: nilai moneter akan / mungkin muncul dengan format yang benar, tanggal dalam tata letak tertentu (ISO, US, Intl.), dll.
    • kode itu sendiri dapat memverifikasi bahwa hanya properti yang ada & diizinkan sedang dibaca menggunakan metode ajaib ini.
    • setiap kali Anda perlu membuat properti serupa yang baru, cukup deklarasikan dan tambahkan namanya ke array yang tepat dan selesai. Itu jauh lebih cepat daripada mendefinisikan pengambil baru, mungkin dengan beberapa baris kode berulang-ulang di seluruh kode kelas.

Iya! kita bisa menulis metode pribadi untuk melakukan itu, juga, tapi sekali lagi, kita akan memiliki metode BANYAK yang dinyatakan (memori ++) yang akhirnya memanggil metode lain, selalu sama, metode. Mengapa tidak menulis metode TUNGGAL untuk mengatur semuanya ...? [ya! pun benar-benar dimaksudkan! :)]

Magic setters juga dapat merespons HANYA pada properti tertentu, jadi semua properti tipe tanggal dapat disaring terhadap nilai yang tidak valid dalam satu metode saja. Jika properti tipe tanggal dicantumkan dalam array, setternya dapat ditentukan dengan mudah. Contoh saja, tentu saja. ada terlalu banyak situasi.

Tentang keterbacaan ... Ya ... Itu perdebatan lain: Saya tidak suka terikat dengan penggunaan IDE (pada kenyataannya, saya tidak menggunakannya, mereka cenderung memberi tahu saya (dan memaksa saya) bagaimana tulis ... dan saya suka suka mengodekan "keindahan"). Saya cenderung konsisten tentang penamaan, jadi menggunakan ctag dan beberapa alat bantu lain sudah cukup bagi saya ... Pokoknya: begitu semua setter dan getter ajaib ini selesai, saya menulis setter lain yang terlalu spesifik atau "khusus" untuk digeneralisasikan dalam metode __set (). Dan itu mencakup semua yang saya butuhkan tentang mendapatkan dan mengatur properti. Tentu saja: tidak selalu ada kesamaan, atau ada beberapa properti yang tidak sepadan dengan kesulitan pengkodean metode magis, dan kemudian masih ada pasangan setter / pengambil tradisional yang baik.

Bahasa pemrograman hanya itu: bahasa buatan manusia. Jadi, masing-masing dari mereka memiliki intonasi atau aksen, sintaksis dan rasa sendiri, jadi saya tidak akan berpura-pura menulis kode Ruby atau Python menggunakan "aksen" yang sama dengan Java atau C #, saya juga tidak akan menulis JavaScript atau PHP untuk menyerupai Perl atau SQL ... Gunakan cara mereka seharusnya digunakan.

Manuel
sumber
1

Secara umum, cara pertama lebih populer secara keseluruhan karena mereka yang memiliki pengetahuan pemrograman sebelumnya dapat dengan mudah beralih ke PHP dan menyelesaikan pekerjaan dengan cara yang berorientasi objek. Cara pertama lebih universal. Saran saya adalah tetap dengan apa yang dicoba dan benar di banyak bahasa. Kemudian, ketika dan jika Anda menggunakan bahasa lain, Anda akan siap untuk mencapai sesuatu ( alih-alih menghabiskan waktu menciptakan kembali roda ).

Anthony Rutledge
sumber
0

Ada banyak cara untuk membuat kode sumber dalam konvensi netbeans. Ini bagus. Itu membuat berpikir lebih mudah === SALAH. Cukup gunakan tradelel, khususnya jika Anda tidak yakin properti mana yang harus dienkapsulasi dan mana yang tidak. Saya tahu, ini adalah boi .... kode ... pla, tetapi untuk debugging-works dan banyak lainnya berpikir itu adalah cara yang lebih baik dan jelas. Jangan menghabiskan banyak waktu dengan thousend seni cara membuat getter dan setter sederhana. Anda tidak dapat menerapkan terlalu banyak pola desain seperti aturan-demeter dan sebagainya, jika Anda menggunakan sihir. Dalam situasi tertentu Anda dapat menggunakan magic_calls atau untuk solusi kecil, cepat dan jelas. Tentu Anda bisa membuat solusi untuk desain-patters dengan cara ini juga, tetapi mengapa membuat Anda hidup lebih sulit.

Dennis Komnenovic
sumber
0

Memvalidasi + Memformat / Menurunkan Nilai

Setters memungkinkan Anda untuk memvalidasi data dan getter memungkinkan Anda memformat atau menurunkan data. Objek memungkinkan Anda untuk merangkum data dan validasinya serta memformat kode ke dalam paket rapi yang mendorong KERING.

Misalnya, pertimbangkan kelas sederhana berikut yang berisi tanggal lahir.

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

Anda ingin memvalidasi bahwa nilai yang ditetapkan adalah

  • Tanggal yang valid
  • Tidak di masa depan

Dan Anda tidak ingin melakukan validasi ini di seluruh aplikasi Anda (atau lebih dari beberapa aplikasi dalam hal ini). Alih-alih, lebih mudah membuat variabel anggota terlindungi atau pribadi (untuk menjadikan setter sebagai satu-satunya titik akses) dan untuk memvalidasi dalam setter karena Anda akan tahu bahwa objek tersebut berisi tanggal lahir yang valid tidak peduli bagian mana dari aplikasi objek berasal dan jika Anda ingin menambahkan lebih banyak validasi maka Anda dapat menambahkannya di satu tempat.

Anda mungkin ingin menambahkan beberapa pemformat yang beroperasi pada variabel anggota yang sama yaitu getAge()dan getDaysUntilBirthday()dan Anda mungkin ingin menerapkan format yang dapat dikonfigurasi dalam getBirthDate()tergantung pada lokal. Oleh karena itu saya lebih suka mengakses nilai secara konsisten melalui getter daripada berbaur $date->getAge()dengan $date->birth_date.

getter dan setter juga berguna saat Anda memperluas objek. Misalnya, anggap aplikasi Anda perlu mengizinkan 150+ tahun tanggal lahir di beberapa tempat tetapi tidak di tempat lain. Salah satu cara untuk memecahkan masalah tanpa mengulangi kode apa pun adalah dengan memperluas BirthDateobjek dan memasukkan validasi tambahan dalam 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);
    }
}
FuzzyTree
sumber
Namun, berkali-kali Anda perlu memvalidasi properti bersama (dan bukan hanya secara individual). Saya pikir mengizinkan "setter" berarti Anda juga tidak menangkap konteks. Validasi harus dilakukan berdasarkan kontekstual. Selain itu, Anda akan dipaksa untuk memeriksa beberapa tanda "isValid" pada setiap metode yang Anda miliki (dan melakukan validasi jika salah). Yang sedang berkata, setter memang memberikan cara yang berguna untuk mengetik-petunjuk, seperti ketika Anda memiliki properti yang Anda ingin menjadi Obyek Nilai (mis. Uang).
Pemrogram
Saya tidak mengerti apa yang Anda maksud dengan dipaksa untuk memeriksa bendera "isValid"? Jika satu-satunya cara untuk menetapkan nilai adalah melalui setter yang melakukan validasi, maka Anda tahu datanya valid dengan fakta bahwa itu berhasil disetel. Jika Anda perlu memvalidasi properti bersama-sama, Anda dapat menulis metode validasi umum yang dipanggil oleh setter properti tersebut.
FuzzyTree
Katakanlah Anda memiliki kelas karyawan dengan setHireddan setHireDate. Tidaklah sah untuk membiarkan seseorang menetapkan tanggal perekrutan tanpa juga menetapkan karyawan sebagai karyawan sewaan. Tetapi tidak ada cara Anda menegakkan ini. Jika Anda menerapkannya di salah satu setter ini, berarti Anda memaksakan urutan "pengaturan", dan itu membutuhkan lebih banyak membaca kode dari pengembang untuk mengetahuinya. Kemudian ketika Anda pergi untuk melakukan metode seperti $employee->promote($newPosition);Anda harus memeriksa bendera untuk melihat apakah validasi telah dilakukan atau menganggap itu belum dilakukan dan melakukannya lagi (berlebihan).
prograhammer
Alih-alih, tangkap interaksi. Mungkin $employee->updateWorkStatus($hired, $hireDate);atau jika lebih maju $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. Sekarang Anda dapat memvalidasi dalam konteks yang Anda butuhkan dan memutuskan apakah validasi tambahan diperlukan sama sekali.
prograhammer
updateWorkStatus pada dasarnya adalah fungsi setter yang menetapkan 2 bukannya 1 nilai tetapi konsepnya sama. Itu salah satu cara untuk melakukannya tetapi Anda juga dapat menempatkan validasi kontekstual dalam metode umum yang hanya berjalan ketika semua properti yang perlu divalidasi bersama ditetapkan yaitu bagian kontekstual dari validasi akan dipanggil oleh setHiredDate dan setHired tetapi hanya akan berjalan jika kedua isset yang disewa dan issed hiredDate benar.
FuzzyTree
0

Posting ini tidak secara khusus tentang __getdan __setmelainkan __callmerupakan ide yang sama kecuali untuk pemanggilan metode. Sebagai aturan, saya tinggal jauh dari semua jenis metode ajaib yang memungkinkan untuk kelebihan karena alasan yang diuraikan dalam komentar dan posting NAMUN , saya baru-baru ini berlari ke API pihak ke-3 yang saya gunakan yang menggunakan LAYANAN dan SUB-LAYANAN, contoh :

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

Bagian penting dari ini adalah bahwa API ini memiliki segalanya yang sama kecuali sub-tindakan, dalam hal ini doActionOne. Idenya adalah bahwa pengembang (saya dan orang lain yang menggunakan kelas ini) dapat memanggil sub-layanan dengan nama yang bertentangan dengan sesuatu seperti:

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

Saya bisa melakukannya:

 $myClass->doActionOne($args);

Untuk hardcode ini hanya akan banyak duplikasi (contoh ini sangat mirip dengan kode):

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

Tetapi dengan metode ajaib __call()saya dapat mengakses semua layanan dengan metode dinamis:

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

Manfaat dari panggilan dinamis ini untuk pengembalian data adalah bahwa jika vendor menambahkan sub-layanan lain, saya tidak perlu menambahkan metode lain ke dalam kelas atau membuat kelas tambahan, dll. Saya tidak yakin apakah ini berguna untuk siapa pun, tapi kupikir aku akan menunjukkan contoh di mana __set, __get, __call, dll dapat menjadi pilihan untuk dipertimbangkan karena fungsi utama adalah kembalinya data.


EDIT:

Secara kebetulan, saya melihat ini beberapa hari setelah posting yang menguraikan persis skenario saya. Ini bukan API yang saya maksudkan tetapi penerapan metode ini identik:

Apakah saya menggunakan api dengan benar?

Rasclatt
sumber
-2

Pembaruan: Jangan gunakan jawaban ini karena ini adalah kode yang sangat bodoh yang saya temukan saat saya belajar. Cukup gunakan pengambil dan penyetel biasa, ini jauh lebih baik.


Saya biasanya menggunakan nama variabel itu sebagai nama fungsi, dan menambahkan parameter opsional ke fungsi itu sehingga ketika parameter opsional diisi oleh penelepon, kemudian mengaturnya ke properti dan mengembalikan $ objek ini (rantai) dan kemudian ketika parameter opsional itu tidak ditentukan oleh penelepon, saya hanya mengembalikan properti ke penelepon.

Contoh saya:

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;
          }
     }
}
ajiyakin
sumber
Sekarang pertanyaannya tetap: Bagaimana Anda mengatur properti ke string kosong? Dan bagaimana Anda mendeteksi bahwa menyetel properti ke string kosong sebenarnya gagal dan berfungsi sebagai pengambil? Pikirkan saja formulir HTML yang mengirimkan bidang kosong sebagai string ... Dan tidak: Menggunakan nilai berbeda seperti NULL sebagai nilai default tidak menyelesaikan masalah.
Sven