Saya telah mencoba untuk belajar di PHP akhir-akhir ini, dan saya menemukan diri saya terpaku pada sifat-sifat. Saya memahami konsep penggunaan kembali kode horisontal dan tidak ingin mewarisi dari kelas abstrak. Apa yang saya tidak mengerti adalah: Apa perbedaan penting antara menggunakan sifat versus antarmuka?
Saya sudah mencoba mencari posting blog yang layak atau artikel yang menjelaskan kapan harus menggunakan satu atau yang lain, tetapi contoh-contoh yang saya temukan sejauh ini tampak sangat mirip sehingga identik.
Imagick
benda, mengurangi semua kegembiraan yang dibutuhkan di masa lalu sebelum sifat-sifat.Jawaban:
Antarmuka mendefinisikan serangkaian metode yang harus diterapkan oleh kelas pelaksana.
Ketika suatu sifat adalah
use
implementasi dari metode datang juga - yang tidak terjadi dalamInterface
.Itulah perbedaan terbesar.
Dari Horizontal Reuse untuk PHP RFC :
sumber
Pengumuman Layanan Publik:
Saya ingin menyatakan untuk catatan bahwa saya percaya ciri-ciri hampir selalu berbau kode dan harus dihindari dalam mendukung komposisi. Menurut saya, pewarisan tunggal sering disalahgunakan sampai menjadi anti-pola dan pewarisan berganda hanya menambah masalah ini. Dalam kebanyakan kasus, Anda akan jauh lebih baik dilayani dengan memilih komposisi daripada warisan (baik tunggal atau banyak). Jika Anda masih tertarik dengan sifat dan hubungannya dengan antarmuka, baca terus ...
Mari kita mulai dengan mengatakan ini:
Untuk menulis kode OO, Anda perlu memahami bahwa OOP benar-benar tentang kemampuan objek Anda. Anda harus berpikir tentang kelas dalam hal apa yang dapat mereka lakukan daripada apa yang sebenarnya mereka lakukan . Ini sangat kontras dengan pemrograman prosedural tradisional di mana fokusnya adalah membuat sedikit kode "melakukan sesuatu."
Jika kode OOP adalah tentang perencanaan dan desain, antarmuka adalah cetak biru dan objek adalah rumah yang dibangun sepenuhnya. Sementara itu, sifat hanyalah cara untuk membantu membangun rumah yang ditata dengan cetak biru (antarmuka).
Antarmuka
Jadi, mengapa kita harus menggunakan antarmuka? Sederhananya, antarmuka membuat kode kita kurang rapuh. Jika Anda meragukan pernyataan ini, tanyakan siapa saja yang terpaksa mempertahankan kode lawas yang tidak ditulis terhadap antarmuka.
Antarmuka adalah kontrak antara programmer dan / kode nya. Antarmuka mengatakan, "Selama Anda bermain dengan aturan saya, Anda dapat menerapkan saya sesuka Anda dan saya berjanji saya tidak akan melanggar kode Anda yang lain."
Jadi sebagai contoh, pertimbangkan skenario dunia nyata (tidak ada mobil atau widget):
Anda mulai dengan menulis sebuah kelas untuk menyimpan tanggapan permintaan menggunakan APC:
Kemudian, di objek respons HTTP Anda, Anda memeriksa hit cache sebelum melakukan semua pekerjaan untuk menghasilkan respons aktual:
Pendekatan ini sangat bagus. Tetapi mungkin beberapa minggu kemudian Anda memutuskan ingin menggunakan sistem cache berbasis file alih-alih APC. Sekarang Anda harus mengubah kode pengontrol Anda karena Anda telah memprogram pengontrol Anda untuk bekerja dengan fungsionalitas
ApcCacher
kelas daripada antarmuka yang mengekspresikan kemampuanApcCacher
kelas. Katakanlah bukannya di atas Anda telah membuatController
kelas bergantung padaCacherInterface
bukan betonApcCacher
seperti:Agar sesuai dengan yang Anda tentukan antarmuka Anda seperti:
Pada gilirannya Anda memiliki kedua Anda
ApcCacher
danFileCacher
kelas baru Anda menerapkanCacherInterface
dan Anda memprogramController
kelas Anda untuk menggunakan kemampuan yang dibutuhkan oleh antarmuka.Contoh ini (semoga) menunjukkan bagaimana pemrograman ke antarmuka memungkinkan Anda untuk mengubah implementasi internal kelas Anda tanpa khawatir jika perubahan itu akan merusak kode Anda yang lain.
Sifat
Sifat, di sisi lain, hanyalah sebuah metode untuk menggunakan kembali kode. Antarmuka tidak boleh dianggap sebagai alternatif yang eksklusif untuk sifat. Faktanya, menciptakan ciri-ciri yang memenuhi kemampuan yang dibutuhkan oleh sebuah antarmuka adalah kasus penggunaan yang ideal .
Anda hanya boleh menggunakan ciri-ciri ketika beberapa kelas berbagi fungsi yang sama (kemungkinan didikte oleh antarmuka yang sama). Tidak ada gunanya menggunakan sifat untuk menyediakan fungsionalitas untuk satu kelas: yang hanya mengaburkan apa yang dilakukan kelas dan desain yang lebih baik akan memindahkan fungsionalitas sifat ke kelas yang relevan.
Pertimbangkan penerapan sifat berikut:
Contoh yang lebih konkret: bayangkan Anda
FileCacher
dan AndaApcCacher
dari diskusi antarmuka menggunakan metode yang sama untuk menentukan apakah entri cache basi dan harus dihapus (jelas ini tidak terjadi dalam kehidupan nyata, tetapi ikuti saja). Anda bisa menulis sifat dan memungkinkan kedua kelas untuk menggunakannya untuk kebutuhan antarmuka umum.Satu kata terakhir dari peringatan: berhati-hatilah untuk tidak berlebihan dengan sifat-sifat. Seringkali sifat digunakan sebagai penopang untuk desain yang buruk ketika implementasi kelas yang unik sudah cukup. Anda harus membatasi sifat untuk memenuhi persyaratan antarmuka untuk desain kode terbaik.
sumber
A
trait
pada dasarnya adalah implementasi PHP dari amixin
, dan secara efektif seperangkat metode ekstensi yang dapat ditambahkan ke kelas apa pun melalui penambahantrait
. Metode kemudian menjadi bagian dari implementasi kelas itu, tetapi tanpa menggunakan warisan .Dari Manual PHP (penekanan pada tambang):
Sebuah contoh:
Dengan sifat di atas didefinisikan, sekarang saya dapat melakukan hal berikut:
Pada titik ini, ketika saya membuat instance kelas
MyClass
, ia memiliki dua metode, yang disebutfoo()
danbar()
- yang berasal darimyTrait
. Dan - perhatikan bahwatrait
metode -defined sudah memiliki tubuh metode - yangInterface
metode -defined tidak bisa.Selain itu - PHP, seperti banyak bahasa lainnya, menggunakan a model pewarisan tunggal - yang berarti bahwa suatu kelas dapat diturunkan dari beberapa antarmuka, tetapi tidak dari beberapa kelas. Namun, kelas PHP dapat memiliki beberapa
trait
inklusi - yang memungkinkan programmer untuk memasukkan bagian yang dapat digunakan kembali - seperti yang mungkin terjadi jika menyertakan beberapa kelas dasar.Beberapa hal yang perlu diperhatikan:
Polimorfisme:
Dalam contoh sebelumnya, di mana
MyClass
memanjangSomeBaseClass
,MyClass
adalah turunan dariSomeBaseClass
. Dengan kata lain, array sepertiSomeBaseClass[] bases
dapat berisi instance dariMyClass
. Demikian pula, jikaMyClass
diperluasIBaseInterface
, arrayIBaseInterface[] bases
dapat berisi instance dariMyClass
. Tidak ada konstruksi polimorfik yang tersedia dengantrait
- karena padatrait
dasarnya hanya kode yang disalin untuk kenyamanan programmer ke setiap kelas yang menggunakannya.Hak lebih tinggi:
Seperti yang dijelaskan dalam Manual:
Jadi - pertimbangkan skenario berikut:
Saat membuat instance MyClass, di atas, terjadi hal berikut:
Interface
IBase
memerlukan fungsi parameterless disebutSomeMethod()
yang akan diberikan.BaseClass
menyediakan implementasi metode ini - memenuhi kebutuhan.trait
myTrait
menyediakan fungsi tanpa parameter yang disebutSomeMethod()
juga, yang didahulukan dariBaseClass
versi-class
MyClass
menyediakan versi sendiriSomeMethod()
- yang diutamakan daripadatrait
-versi.Kesimpulan
Interface
tidak dapat memberikan implementasi standar dari tubuh metode, sementara sebuahtrait
kaleng.Interface
adalah polimorfik , mewarisi konstruk - sementaratrait
tidak.Interface
s dapat digunakan di kelas yang sama, dan begitu juga multipletrait
s.sumber
mixin
- dan ketika saya telah meninjau kembali pembukaan jawaban saya, saya telah memperbarui untuk mencerminkan ini. Terima kasih telah berkomentar, @BoltClock!kupikir
traits
berguna untuk membuat kelas yang berisi metode yang dapat digunakan sebagai metode dari beberapa kelas yang berbeda.Sebagai contoh:
Anda dapat memiliki dan menggunakan metode "kesalahan" ini di kelas apa pun yang menggunakan sifat ini.
Sementara dengan
interfaces
Anda hanya dapat mendeklarasikan metode tanda tangan, tetapi tidak kode fungsinya. Juga, untuk menggunakan antarmuka, Anda harus mengikuti hierarki, menggunakanimplements
. Ini tidak terjadi dengan sifat-sifat.Ini benar-benar berbeda!
sumber
to_integer
akan lebih mungkin dimasukkan dalamIntegerCast
antarmuka karena tidak ada cara yang secara fundamental mirip dengan (secara cerdas) melemparkan kelas ke integer.use Toolkit
Anda bisa$this->toolkit = new Toolkit();
atau saya kehilangan beberapa manfaat dari sifat itu sendiri?Something
wadah Anda Anda lakukanif(!$something->do_something('foo')) var_dump($something->errors);
Bagi pemula jawaban di atas mungkin sulit, Ini adalah cara termudah untuk memahaminya:
Sifat
jadi jika Anda ingin memiliki
sayHello
fungsi di kelas lain tanpa membuat ulang seluruh fungsi Anda dapat menggunakan ciri-ciri,Benar keren!
Tidak hanya fungsi, Anda dapat menggunakan apa pun dalam sifat (fungsi, variabel, konst ..). Anda juga dapat menggunakan beberapa sifat:
use SayWorld,AnotherTraits;
Antarmuka
jadi inilah perbedaan antarmuka dari ciri-ciri: Anda harus membuat kembali semua antarmuka di kelas yang diimplementasikan. antarmuka tidak memiliki implementasi. dan antarmuka hanya dapat memiliki fungsi dan konst, tidak dapat memiliki variabel.
Saya harap ini membantu!
sumber
Ini adalah cara berpikir yang baik dalam kebanyakan situasi, tetapi ada beberapa perbedaan kecil di antara keduanya.
Sebagai permulaan, the
instanceof
operator tidak akan bekerja dengan sifat-sifat (yaitu, suatu sifat bukan objek nyata) sehingga Anda tidak dapat kami untuk melihat apakah suatu kelas memiliki sifat tertentu (atau untuk melihat apakah dua kelas yang tidak terkait berbagi suatu sifat ). Itulah yang mereka maksudkan dengan menjadi konstruksi untuk penggunaan kembali kode horizontal.Ada yang fungsi sekarang dalam PHP yang akan membiarkan Anda mendapatkan daftar semua ciri-ciri seorang penggunaan kelas, tapi sifat-warisan berarti Anda harus melakukan pemeriksaan rekursif untuk andal memeriksa apakah kelas di beberapa titik memiliki sifat tertentu (ada contoh kode pada halaman doco PHP). Tapi ya, itu tentu tidak sesederhana dan sebersih instanceofnya, dan IMHO itu fitur yang akan membuat PHP lebih baik.
Juga, kelas abstrak masih kelas, sehingga mereka tidak memecahkan masalah terkait penggunaan ulang beberapa warisan. Ingat Anda hanya dapat memperluas satu kelas (nyata atau abstrak) tetapi mengimplementasikan beberapa antarmuka.
Saya telah menemukan ciri-ciri dan antarmuka yang benar-benar baik untuk digunakan bersama untuk membuat pseudo multiple inheritance. Misalnya:
Melakukan ini berarti Anda dapat menggunakan instanceof untuk menentukan apakah objek Pintu tertentu diketik atau tidak, Anda tahu Anda akan mendapatkan seperangkat metode yang konsisten dll, dan semua kode berada di satu tempat di semua kelas yang menggunakan KeyedTrait.
sumber
Ciri - ciri hanya untuk penggunaan kembali kode .
Antarmuka hanya menyediakan tanda tangan dari fungsi yang harus didefinisikan di kelas di mana ia dapat digunakan tergantung pada kebijaksanaan pemrogram . Dengan demikian memberi kami prototipe untuk sekelompok kelas .
Untuk referensi- http://www.php.net/manual/en/language.oop5.traits.php
sumber
Anda dapat menganggap suatu sifat sebagai "salin-tempel" kode secara otomatis.
Menggunakan sifat-sifat berbahaya karena tidak ada artinya untuk mengetahui apa yang dilakukannya sebelum eksekusi.
Namun, sifat-sifat lebih fleksibel karena kurangnya keterbatasan seperti pewarisan.
Ciri dapat berguna untuk menyuntikkan metode yang memeriksa sesuatu ke dalam kelas, misalnya, keberadaan metode atau atribut lain. Artikel bagus tentang itu (tapi dalam bahasa Prancis, maaf) .
Untuk orang-orang yang membaca bahasa Prancis yang bisa mendapatkannya, GNU / Linux Magazine HS 54 memiliki artikel tentang hal ini.
sumber
Jika Anda tahu bahasa Inggris dan tahu apa
trait
artinya, itu persis seperti namanya. Ini adalah paket metode dan properti tanpa kelas yang Anda lampirkan ke kelas yang ada dengan mengetikuse
.Pada dasarnya, Anda bisa membandingkannya dengan satu variabel. Fungsi penutupan dapat
use
variabel-variabel ini dari luar lingkup dan dengan cara itu mereka memiliki nilai di dalamnya. Mereka kuat dan dapat digunakan dalam segala hal. Hal yang sama terjadi pada sifat-sifat jika mereka digunakan.sumber
Jawaban lain berhasil menjelaskan perbedaan antara antarmuka dan sifat. Saya akan fokus pada contoh dunia nyata yang berguna, khususnya yang menunjukkan bahwa sifat dapat menggunakan variabel instan - memungkinkan Anda menambahkan perilaku ke kelas dengan kode boilerplate minimal.
Sekali lagi, seperti yang disebutkan oleh orang lain, sifat-sifat berpasangan dengan baik dengan antarmuka, memungkinkan antarmuka untuk menentukan kontrak perilaku, dan sifat untuk memenuhi implementasi.
Menambahkan kemampuan mempublikasikan / berlangganan acara ke kelas dapat menjadi skenario umum di beberapa basis kode. Ada 3 solusi umum:
use
sifat tersebut, alias impor, untuk mendapatkan kemampuan.Seberapa baik masing-masing bekerja?
# 1 Tidak bekerja dengan baik. Itu akan, sampai hari Anda menyadari Anda tidak dapat memperpanjang kelas dasar karena Anda sudah memperpanjang sesuatu yang lain. Saya tidak akan menunjukkan contoh ini karena harus jelas betapa terbatasnya untuk menggunakan warisan seperti ini.
# 2 & # 3 keduanya bekerja dengan baik. Saya akan menunjukkan contoh yang menyoroti beberapa perbedaan.
Pertama, beberapa kode yang akan sama antara kedua contoh:
Antarmuka
Dan beberapa kode untuk menunjukkan penggunaan:
Ok, sekarang mari kita tunjukkan bagaimana implementasi dari
Auction
kelas akan berbeda ketika menggunakan ciri-ciri.Pertama, beginilah penampilan # 2 (menggunakan komposisi):
Beginilah penampilan # 3 (ciri-ciri):
Perhatikan bahwa kode di dalam
EventEmitterTrait
persis sama dengan apa yang ada di dalamEventEmitter
kelas kecuali sifat menyatakantriggerEvent()
metode yang dilindungi. Jadi, satu-satunya perbedaan yang perlu Anda perhatikan adalah implementasiAuction
kelas .Dan perbedaannya besar. Saat menggunakan komposisi, kami mendapatkan solusi hebat, memungkinkan kami untuk menggunakan kembali
EventEmitter
kelas kami sebanyak yang kami suka. Namun, kelemahan utama adalah kita memiliki banyak kode boilerplate yang perlu kita tulis dan pelihara karena untuk setiap metode yang didefinisikan dalamObservable
antarmuka, kita perlu mengimplementasikannya dan menulis kode boilerplate yang membosankan yang hanya meneruskan argumen ke metode yang sesuai di kami menyusunEventEmitter
objek. Menggunakan sifat dalam contoh ini memungkinkan kita menghindari itu , membantu kita mengurangi kode boilerplate dan meningkatkan rawatan .Namun, mungkin ada saat-saat di mana Anda tidak ingin
Auction
kelas Anda mengimplementasikanObservable
antarmuka penuh - mungkin Anda hanya ingin mengekspos 1 atau 2 metode, atau bahkan mungkin tidak ada sama sekali sehingga Anda dapat menentukan tanda tangan metode Anda sendiri. Dalam kasus seperti itu, Anda mungkin masih lebih suka metode komposisi.Tapi, sifat ini sangat menarik di sebagian besar skenario, terutama jika antarmuka memiliki banyak metode, yang menyebabkan Anda menulis banyak boilerplate.
* Anda sebenarnya bisa melakukan keduanya - tentukan
EventEmitter
kelas jika Anda ingin menggunakannya secara komposisional, dan tentukanEventEmitterTrait
sifatnya juga, menggunakanEventEmitter
implementasi kelas di dalam sifat tersebut :)sumber
Sifatnya sama dengan kelas yang dapat kita gunakan untuk beberapa tujuan pewarisan dan juga penggunaan kembali kode.
Kita dapat menggunakan sifat di dalam kelas dan juga kita dapat menggunakan beberapa sifat di kelas yang sama dengan 'menggunakan kata kunci'.
Antarmuka menggunakan untuk penggunaan kembali kode sama dengan suatu sifat
antarmuka memperluas beberapa antarmuka sehingga kita dapat memecahkan beberapa masalah warisan tetapi ketika kita mengimplementasikan antarmuka maka kita harus membuat semua metode di dalam kelas. Untuk info lebih lanjut klik tautan di bawah ini:
http://php.net/manual/en/language.oop5.traits.php http://php.net/manual/en/language.oop5.interfaces.php
sumber
Antarmuka adalah kontrak yang mengatakan "objek ini mampu melakukan hal ini", sedangkan sifat adalah memberikan objek kemampuan untuk melakukan hal itu.
Suatu sifat pada dasarnya adalah cara untuk "menyalin dan menempel" kode antar kelas.
Coba baca artikel ini, Apa itu ciri-ciri PHP?
sumber
Perbedaan utama adalah bahwa, dengan antarmuka, Anda harus menentukan implementasi aktual dari setiap metode dalam setiap kelas yang mengimplementasikan antarmuka tersebut, sehingga Anda dapat memiliki banyak kelas yang mengimplementasikan antarmuka yang sama tetapi dengan perilaku yang berbeda, sementara sifat-sifat hanyalah potongan-potongan kode yang disuntikkan ke dalam kelas; Perbedaan penting lainnya adalah bahwa metode sifat hanya dapat berupa metode kelas atau metode statis, tidak seperti metode antarmuka yang juga dapat (dan biasanya) menjadi metode instan.
sumber