Bagaimana Anda mengatur dan mengelola objek pembantu Anda seperti mesin database, pemberitahuan pengguna, penanganan kesalahan, dan sebagainya dalam proyek berorientasi objek berbasis PHP?
Katakanlah saya memiliki CMS PHP yang besar. CMS diatur dalam berbagai kelas. Beberapa contoh:
- objek database
- manajemen pengguna
- API untuk membuat / memodifikasi / menghapus item
- objek olahpesan untuk menampilkan pesan kepada pengguna akhir
- pengendali konteks yang membawa Anda ke halaman yang benar
- kelas bilah navigasi yang menunjukkan tombol
- objek penebangan
- mungkin, penanganan error kustom
dll.
Saya berurusan dengan pertanyaan abadi, bagaimana cara terbaik membuat objek ini dapat diakses oleh setiap bagian dari sistem yang membutuhkannya.
Apporach pertama saya, bertahun-tahun yang lalu adalah memiliki $ application global yang berisi instance yang diinisialisasi dari kelas-kelas ini.
global $application;
$application->messageHandler->addMessage("Item successfully inserted");
Saya kemudian beralih ke pola Singleton dan fungsi pabrik:
$mh =&factory("messageHandler");
$mh->addMessage("Item successfully inserted");
tapi saya juga tidak senang dengan itu. Tes unit dan enkapsulasi menjadi semakin penting bagi saya, dan dalam pemahaman saya, logika di balik global / lajang menghancurkan ide dasar OOP.
Maka tentu saja ada kemungkinan memberikan setiap objek sejumlah petunjuk ke objek pembantu yang dibutuhkannya, mungkin cara yang paling bersih, hemat sumber daya, dan ramah pengujian, tetapi saya ragu tentang pemeliharaan ini dalam jangka panjang.
Sebagian besar kerangka kerja PHP yang saya lihat menggunakan pola tunggal, atau fungsi yang mengakses objek yang diinisialisasi. Keduanya merupakan pendekatan yang bagus, tetapi seperti yang saya katakan, saya tidak senang dengan keduanya.
Saya ingin memperluas wawasan saya tentang pola umum apa yang ada di sini. Saya mencari contoh, gagasan tambahan dan pointer terhadap sumber daya yang membahas ini dari jangka panjang , dunia nyata perspektif.
Selain itu, saya tertarik untuk mendengar tentang pendekatan khusus, khusus, atau aneh untuk masalah ini.
sumber
$mh=&factory("messageHandler");
tidak ada gunanya dan tidak menghasilkan manfaat kinerja apa pun. Selain itu, ini tidak digunakan lagi di 5.3.Jawaban:
Saya akan menghindari pendekatan Singleton yang disarankan oleh Flavius. Ada banyak alasan untuk menghindari pendekatan ini. Itu melanggar prinsip OOP yang baik. Blog pengujian google memiliki beberapa artikel bagus di Singleton dan bagaimana menghindarinya:
http://googletesting.blogspot.com/2008/08/by-miko-hevery-so-you-join-new-project.html http://googletesting.blogspot.com/2008/05/tott-using-dependancy -injection-to.html http://googletesting.blogspot.com/2008/08/where-have-all-singletons-gone.html
Alternatif
penyedia layanan
http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html
injeksi ketergantungan
http://en.wikipedia.org/wiki/Dependency_injection
dan penjelasan php:
http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection
Ini adalah artikel bagus tentang alternatif ini:
http://martinfowler.com/articles/injection.html
Menerapkan injeksi ketergantungan (DI):
Saya yakin Anda harus menanyakan apa yang dibutuhkan dalam konstruktor agar objek berfungsi :
new YourObject($dependencyA, $dependencyB);
Anda bisa menyediakan objek (dependensi) yang dibutuhkan secara manual (
$application = new Application(new MessageHandler()
). Tetapi Anda juga dapat menggunakan kerangka DI (halaman wikipedia menyediakan tautan ke kerangka kerja PHP DI ).Yang penting adalah Anda hanya meneruskan apa yang sebenarnya Anda gunakan (memanggil tindakan), BUKAN apa yang Anda teruskan ke objek lain karena mereka membutuhkannya. Berikut posting terbaru dari 'paman Bob' (Robert Martin) membahas DI manual vs menggunakan kerangka kerja .
Beberapa pemikiran lagi tentang solusi Flavius. Saya tidak ingin posting ini menjadi anti-posting tetapi saya pikir penting untuk melihat mengapa injeksi ketergantungan, setidaknya bagi saya, lebih baik daripada global.
Meskipun ini bukan implementasi Singleton yang 'sebenarnya' , saya masih berpikir Flavius salah. Keadaan global itu buruk . Perhatikan bahwa solusi tersebut juga menggunakan metode statis yang sulit untuk diuji .
Saya tahu banyak orang melakukannya, menyetujuinya, dan menggunakannya. Tapi membaca artikel blog Misko Heverys ( pakar google testability ), membaca ulang dan perlahan mencerna apa yang dia katakan benar-benar mengubah cara saya melihat banyak desain.
Jika Anda ingin dapat menguji aplikasi Anda, Anda harus mengadopsi pendekatan yang berbeda untuk mendesain aplikasi Anda. Ketika Anda melakukan pemrograman uji-pertama, Anda akan mengalami kesulitan dengan hal-hal seperti ini: 'selanjutnya saya ingin menerapkan pencatatan pada bagian kode ini; mari kita tulis tes pertama yang mencatat pesan dasar 'dan kemudian menghasilkan tes yang memaksa Anda untuk menulis dan menggunakan logger global yang tidak dapat diganti.
Saya masih berjuang dengan semua informasi yang saya dapatkan dari blog itu, dan penerapannya tidak selalu mudah, dan saya punya banyak pertanyaan. Tapi tidak mungkin saya bisa kembali ke apa yang saya lakukan sebelumnya (ya, status global dan Singletons (S besar)) setelah saya memahami apa yang dikatakan Misko Hevery :-)
sumber
Ini adalah cara saya melakukannya. Ini menciptakan objek sesuai permintaan:
Begitulah cara saya melakukannya, ini menghormati prinsip-prinsip OOP, ini lebih sedikit kode daripada bagaimana Anda melakukannya sekarang, dan objek dibuat hanya ketika kode membutuhkannya untuk pertama kalinya.
Catatan : apa yang saya sajikan bahkan bukanlah pola tunggal yang nyata. Singleton hanya akan mengizinkan satu instance dirinya sendiri dengan mendefinisikan konstruktor (Foo :: __ constructor ()) sebagai privat. Ini hanya variabel "global" yang tersedia untuk semua instance "Aplikasi". Itu sebabnya saya pikir penggunaannya valid karena TIDAK mengabaikan prinsip OOP yang baik. Tentu saja, seperti apapun di dunia ini, "pola" ini juga tidak boleh digunakan secara berlebihan!
Saya telah melihat ini digunakan di banyak kerangka kerja PHP, Zend Framework dan Yii di antaranya. Dan Anda harus menggunakan kerangka kerja. Saya tidak akan memberi tahu Anda yang mana.
Tambahan Bagi Anda yang mengkhawatirkan TDD , Anda masih bisa membuat beberapa kabel untuk menyuntikkan dependensi. Ini bisa terlihat seperti ini:
Ada cukup ruang untuk perbaikan. Ini hanya PoC, gunakan imajinasi Anda.
Kenapa seperti itu? Yah, sebagian besar waktu aplikasi tidak akan diuji unit, itu benar-benar akan dijalankan, semoga dalam lingkungan produksi . Kekuatan PHP adalah kecepatannya. PHP BUKAN dan tidak akan pernah menjadi "bahasa OOP yang bersih", seperti Java.
Dalam sebuah aplikasi, hanya ada satu kelas Aplikasi dan hanya satu contoh dari setiap pembantunya, paling banyak (sesuai dengan lazy loading seperti di atas). Tentu, lajang itu buruk, tapi sekali lagi, hanya jika mereka tidak mengikuti dunia nyata. Dalam contoh saya, mereka melakukannya.
"Aturan" stereotip seperti "lajang itu buruk" adalah sumber kejahatan, itu untuk orang malas yang tidak mau berpikir sendiri.
Ya, saya tahu, manifesto PHP BURUK, secara teknis. Namun itu adalah bahasa yang sukses, dengan caranya yang meretas.
Tambahan
Gaya satu fungsi:
sumber
Saya suka konsep Injeksi Ketergantungan:
Fabien Potencier menulis serangkaian artikel yang sangat bagus tentang Injeksi Ketergantungan dan kebutuhan untuk menggunakannya. Dia juga menawarkan Kontainer Injeksi Ketergantungan yang bagus dan kecil bernama Jerawat yang sangat saya suka gunakan (info lebih lanjut tentang github ).
Seperti yang dinyatakan di atas, saya tidak suka penggunaan Singletons. Ringkasan yang bagus tentang mengapa Singletons bukan desain yang bagus dapat ditemukan di sini di blog Steve Yegge .
sumber
decupling from GOD object
: stackoverflow.com/questions/1580210/… dengan contoh yang sangat bagusPendekatan terbaik adalah memiliki semacam wadah untuk sumber daya tersebut. Beberapa cara paling umum untuk menerapkan penampung ini :
Singleton
Tidak disarankan karena sulit untuk diuji dan menyiratkan status global. (Singletonitis)
Registri
Menghilangkan singletonitis, bug Saya tidak akan merekomendasikan registry juga, karena ini juga sejenis singleton. (Sulit untuk menguji unit)
Warisan
Sayangnya, tidak ada beberapa warisan dalam PHP, jadi ini membatasi semua pada rantai.
Injeksi ketergantungan
Ini adalah pendekatan yang lebih baik, tetapi topik yang lebih besar.
Tradisional
Cara paling sederhana untuk melakukannya adalah menggunakan injeksi konstruktor atau penyetel (meneruskan objek ketergantungan menggunakan penyetel atau dalam konstruktor kelas).
Kerangka
Anda dapat menggulung injektor ketergantungan Anda sendiri, atau menggunakan beberapa kerangka kerja injeksi ketergantungan, misalnya. Yadif
Sumber daya aplikasi
Anda dapat menginisialisasi setiap sumber daya Anda dalam bootstrap aplikasi (yang bertindak sebagai wadah), dan mengaksesnya di mana saja dalam aplikasi yang mengakses objek bootstrap.
Ini adalah pendekatan yang diterapkan di Zend Framework 1.x
Pemuat sumber daya
Semacam objek statis yang memuat (membuat) sumber daya yang dibutuhkan hanya saat diperlukan. Ini adalah pendekatan yang sangat cerdas. Anda mungkin melihatnya beraksi, misalnya mengimplementasikan komponen Injeksi Ketergantungan Symfony
Injeksi ke lapisan tertentu
Sumber daya tidak selalu dibutuhkan di mana pun dalam aplikasi. Terkadang Anda hanya membutuhkannya misalnya di pengontrol (MV C ). Kemudian Anda dapat menyuntikkan sumber daya hanya di sana.
Pendekatan umum untuk ini adalah menggunakan komentar docblock untuk menambahkan metadata injeksi.
Lihat pendekatan saya untuk ini di sini:
Bagaimana cara menggunakan injeksi ketergantungan di Zend Framework? - Stack Overflow
Terakhir, saya ingin menambahkan catatan tentang hal yang sangat penting di sini - caching.
Secara umum, terlepas dari teknik yang Anda pilih, Anda harus memikirkan bagaimana sumber daya akan di-cache. Cache akan menjadi sumber daya itu sendiri.
Aplikasinya bisa sangat besar, dan memuat semua sumber daya pada setiap permintaan sangat mahal. Ada banyak pendekatan, termasuk appserver-in-php ini - Hosting Proyek di Google Code .
sumber
Jika Anda ingin membuat objek tersedia secara global, pola registri mungkin menarik bagi Anda. Untuk inspirasi, lihat Zend Registry .
Begitu juga pertanyaan Registry vs. Singleton .
sumber
Objek di PHP membutuhkan banyak memori, seperti yang mungkin Anda lihat dari pengujian unit Anda. Oleh karena itu, sangat ideal untuk menghancurkan objek yang tidak dibutuhkan secepat mungkin untuk menghemat memori untuk proses lain. Dengan pemikiran itu saya menemukan bahwa setiap benda cocok dengan salah satu dari dua cetakan.
1) Objek mungkin memiliki banyak metode yang berguna atau perlu dipanggil lebih dari sekali dalam hal ini saya menerapkan singleton / registri:
2) Objek hanya ada selama masa aktif metode / fungsi yang memanggilnya dalam hal ini, kreasi sederhana bermanfaat untuk mencegah referensi objek yang tertinggal dari membuat objek hidup terlalu lama.
Menyimpan objek sementara DI MANA SAJA dapat menyebabkan kebocoran memori karena referensi ke objek tersebut mungkin terlupa tentang cara menyimpan objek dalam memori selama sisa skrip.
sumber
Saya akan menggunakan fungsi yang mengembalikan objek yang diinisialisasi:
Dalam lingkungan pengujian, Anda dapat menentukannya untuk mengembalikan mock-up. Anda bahkan bisa mendeteksi di dalam siapa yang memanggil fungsi menggunakan debug_backtrace () dan mengembalikan objek yang berbeda. Anda dapat mendaftar di dalamnya yang ingin mendapatkan objek apa untuk mendapatkan wawasan tentang apa yang sebenarnya terjadi di dalam program Anda.
sumber
Mengapa tidak membaca manual yang bagus?
http://php.net/manual/en/language.oop5.autoload.php
sumber