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
php
oop
coding-style
Menandai
sumber
sumber
Jawaban:
Anda dapat menggunakan metode sulap php
__get
dan__set
.sumber
__get
dan__set
. Ada dua garis bawah, bukan satu. Berikut adalah tautan langsung ke bagian kanan halaman: php.net/manual/en/… (+1 untuk jawaban yang benar)public
properti, jika tidak ada validasi / sanitasi?Mengapa menggunakan getter dan setter?
sumber
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?
PHP bukan Java, C ++, atau C #. PHP berbeda dan dimainkan dengan peran yang berbeda.
sumber
$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.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:
Di Jawa, itu tidak:
Menggunakan metode ajaib (
__get
dan__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.sumber
$bar
sebagaiint
dalam contoh pertama: wiki.php.net/rfc/typed_properties_v2Jika Anda lebih suka menggunakan fungsi __call, Anda dapat menggunakan metode ini. Ini bekerja dengan
$this->property()
$this->property($value)
$this->getProperty()
$this->setProperty($value)
kalsdas
sumber
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.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->width
lebih mudah dibaca daripada$someobject->width()
. Namun tidak seperti planetcircumference
atauwidth
, yang dapat diasumsikan sebagaistatic
, 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
Dalam hal ini
generatelatex
akan mematuhi skema penamaan actionname + methodnamekasus khusus, jelas
Catatan: PHP memilih untuk tidak mengimplementasikan sintaks pengambil / penyetel. Saya tidak mengklaim bahwa getter / setter umumnya buruk.
sumber
Siap!
sumber
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)
sumber
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.
Cukup tambahkan metode di atas di kelas Anda, sekarang Anda dapat mengetik:
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:
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,
Dengan daftar itu sekarang Anda dapat mengetik:
.
.
.
Itu saja.
Doc: __call () dipicu ketika memanggil metode yang tidak dapat diakses dalam konteks objek.
sumber
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:
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.
sumber
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 ).
sumber
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.
sumber
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.
Anda ingin memvalidasi bahwa nilai yang ditetapkan adalah
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()
dangetDaysUntilBirthday()
dan Anda mungkin ingin menerapkan format yang dapat dikonfigurasi dalamgetBirthDate()
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
BirthDate
objek dan memasukkan validasi tambahan dalam setter.sumber
setHired
dansetHireDate
. 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).$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.Posting ini tidak secara khusus tentang
__get
dan__set
melainkan__call
merupakan 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 :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:Saya bisa melakukannya:
Untuk hardcode ini hanya akan banyak duplikasi (contoh ini sangat mirip dengan kode):
Tetapi dengan metode ajaib
__call()
saya dapat mengakses semua layanan dengan metode dinamis: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?
sumber
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:
sumber