[Apa itu MVC? 】
MVC adalah sebuah konsep yang memungkinkan Anda menggabungkan "tiga bagian (yaitu nama lengkap MVC, Model, View, dan Controller) secara harmonis untuk membentuk aplikasi yang kompleks. Mobil adalah contoh MVC yang sangat bagus dalam kehidupan nyata. Saat kita melihat sebuah mobil, kita melihat dua bagian Tampilan (tampilan): interior dan eksterior. Kedua hal ini tidak dapat dipisahkan dari seorang Pengendali: sang pengemudi. Sistem rem, roda kemudi, dan sistem kendali lainnya mewakili Model: sistem tersebut mengambil metode kendali dari pengemudi (Pengendali) dan menerapkannya pada interior dan eksterior (Tampilan).
[MVC di Web]
Konsep yang tercakup dalam kerangka MVC cukup sederhana dan sangat fleksibel. Konsep dasarnya adalah Anda memiliki pengontrol tunggal (seperti index.php) yang mengontrol semua aplikasi dalam kerangka kerja yang didasarkan pada permintaan parameter. Pengontrol ini biasanya berisi (minimal) parameter yang mendefinisikan model, peristiwa, dan parameter GET. Dengan cara ini pengontrol dapat menerima semua permintaan dan menjalankan acara yang sesuai. Misalnya, permintaan seperti ini /index.php?module=foo&event=bar mungkin digunakan untuk memuat kelas bernama foo, dan kemudian menjalankan foo::bar()[yang merupakan fungsi bar( )]. Keuntungannya adalah:
memelihara antarmuka untuk semua aplikasi
sambil mempertahankan kode yang tak terhitung jumlahnya dalam suatu aplikasi sangatlah merepotkan, karena setiap bagian kode memiliki jalur relatifnya sendiri, tautan basis data, verifikasi, dll. Melakukan hal ini akan menyelamatkan Anda dari masalah dan memungkinkan Anda menggabungkan dan menggunakan kembali kode
[Mengapa membuat kerangka MVC Anda sendiri? 】
Sejauh ini, saya belum melihat banyak framework MVC yang ditulis dalam PHP. Faktanya, saya hanya mengetahui satu - Solar, yang seluruhnya ditulis dalam PHP5. Yang lainnya adalah Cake, yang mencoba menjadi RoR (Ruby on Rails - kerangka jaringan sumber terbuka untuk bahasa Ruby) dari PHP. Saya sendiri memiliki beberapa ketidakpuasan dengan kedua kerangka tersebut: mereka tidak memanfaatkan kode yang ada yang disertakan dalam PEAR, Smarty, dll.; Akhirnya Cake saat ini masih relatif berantakan, Solar adalah kerangka kerja yang sebagian besar ditulis oleh satu orang (saya punya tidak ada niat untuk mengatakan bahwa penulisnya, Paul, bukanlah orang baik atau programmer yang baik). Pertanyaan-pertanyaan ini mungkin tidak membuat Anda menyangkalnya, dan kemungkinan besar Anda tidak mempedulikannya sama sekali. Namun karena itu, saya meminta Anda untuk melihatnya sesering mungkin.
[Cara lama]
Jika Anda kembali ke tahun 2001 dan melihat kode yang Anda tulis, penulis mungkin menemukan file bernama template.txt, yang terlihat seperti ini: www.phpv.net Harap tunjukkan sumber untuk mencetak ulang
<?php
require_once('config.php'); // Kebutuhan lainnya, info DB, dll.
$APP_DB = 'mydb';
$APP_REQUIRE_LOGIN = false; // Setel ke true jika skrip memerlukan login
$APP_TEMPLATE_FILE = 'foo.php'; // Templat cerdas
$APP_TITLE = 'Aplikasi Saya';
if ($APP_REQUIRE_LOGIN == benar) {
if (!isset($_SESSION['userID'])) {
header("Lokasi: /path/ke/login.php");
KELUAR();
}
}
$db = DB::connect('mysql://'.$DB_USER.':'.$DB_PASS.'@localhost/'.$APP_DB);
jika (!PEAR::isError($db)) {
$db->setFetchMode(DB_FETCHMODE_ASSOC);
} kalau tidak {
mati($db->getMessage());
}
// Letakkan logikamu di sini
// Keluarkan templat
include_once(APP_TEMPLATE_PATH.'/header.php');
include_once(APP_TEMPLATE_PATH.'/'.$APP_TEMPLATE_FILE);
include_once(APP_TEMPLATE_PATH.'/footer.php');
?>
Ya ampun, melihat kode ini saja sudah membuatku ngeri. Konsep kode ini adalah untuk memastikan bahwa setiap aplikasi dapat disesuaikan dengan metode pemrosesan ini. Misalnya, saya cukup menyalin template.txt ke myapp.php, mengubah beberapa variabel, dan voila, itu akan berjalan. Namun, pendekatan yang sangat terorganisir ini memiliki beberapa kelemahan serius: Bagaimana
jika bos saya ingin penulis menggunakan myapp.php untuk menghasilkan PDF dalam beberapa kasus, HTML dalam beberapa kasus, dan SOAP dalam beberapa kasus (permintaan XML dikirimkan langsung), apa yang harus saya lakukan? Mengerjakan?
Apa yang harus saya lakukan jika aplikasi ini memerlukan autentikasi IMAP atau LDAP?
Bagaimana cara menangani berbagai jenis kode (termasuk pengeditan, peningkatan, dan penghapusan)?
Bagaimana cara menangani otentikasi multi-level (admin vs. non-admin)?
Bagaimana cara mengaktifkan cache keluaran? www.phpv.net Harap tunjukkan sumber untuk mencetak ulang
[Cara baru]
Masukkan semuanya ke dalam kerangka MVC ini, dan Anda akan menemukan bahwa hidup ini sangat sederhana. Silakan bandingkan kode berikut:
<?php
kelas aplikasi saya memperluas FR_Auth_User
{
fungsi publik __konstruksi()
{
induk::__konstruksi();
}
fungsi publik __default()
{
// Lakukan sesuatu di sini
}
fungsi publik hapus()
{ }
fungsi publik __destruct()
{
induk::__destruct();
}
}
?>
Perhatikan bahwa kode ini jelas tidak digunakan untuk menghubungkan ke database, menentukan apakah pengguna login, atau mengeluarkan informasi lainnya. Pengontrol memiliki semuanya.
Jika saya ingin mengautentikasi ke LDAP, saya dapat membuat FR_Auth_LDAP. Pengontrol dapat mengenali metode keluaran tertentu (seperti $_GET['output']) dan dapat mengonversi ke PDF atau SOAP kapan saja. Event handler delete hanya bertanggung jawab atas penghapusan dan tidak mempedulikan hal lain. Karena modul ini memiliki instance kelas FR_User, modul ini dapat dengan mudah menentukan apakah pengguna sedang login, dll. Smarty, sebagai mesin templat, secara alami mengontrol cache, tetapi pengontrol juga dapat mengontrol sebagian cache.
Beralih dari cara lama yang disebutkan sebelumnya ke cara MVC mungkin merupakan konsep baru dan asing bagi banyak orang, namun begitu Anda beralih ke konsep seperti itu, akan cukup sulit untuk beralih kembali.
[Membangun lapisan bawah]
Saya penggemar PEAR, terutama kelas PEAR_Error. PHP5 memperkenalkan kelas bawaan baru "Pengecualian" yang menggantikan PEAR_Error. Namun PEAR_Error memiliki beberapa fitur yang lebih praktis daripada Exception. Oleh karena itu, contoh kerangka kerja MVC dalam rangkaian artikel ini akan menggunakannya untuk penanganan kesalahan. Bagaimanapun, saya masih harus menggunakan Exception untuk mendapatkan kesalahan dari konstruktor, karena mereka sendiri tidak dapat mengembalikan kesalahan tersebut.
Tujuan merancang kelas dasar ini adalah sebagai berikut:
Gunakan PEAR untuk dengan cepat menambahkan fungsi ke kelas dasar
untuk membuat kelas abstrak praktis yang kecil dan berulang kali sehingga pengguna dapat dengan cepat mengembangkan aplikasi dalam kerangka ini.
Gunakan
phpDocumentor untuk menghasilkan dokumen untuk semua kelas dasar
hierarki kelas akan terlihat seperti ini:
- FR_Object akan menyediakan fungsionalitas dasar untuk digunakan semua objek lain (termasuk logging, setFrom() umum, toArray())
- FR_Object_DB adalah lapisan kecil yang menyediakan tautan database ke subkelas dan fungsi lainnya
- FR_Module adalah kelas terbawah dari semua aplikasi (juga disebut modul, model, dll.)
- FR_Auth adalah kelas terbawah dari semua mekanisme verifikasi
· FR_Auth_User adalah kelas verifikasi yang digunakan untuk memverifikasi semua modul yang perlu memverifikasi apakah pengguna login
· FR_Auth_No adalah semua "kelas validasi palsu" untuk modul yang tidak memerlukan validasi
- FR_Presenter adalah kelas dasar untuk semua aplikasi yang menangani pemuatan dan tampilan
- FR_Presenter_Smarty adalah lapisan presentasi yang mencakup kemampuan untuk memuat drive yang berbeda. Smarty adalah kelas templat yang sangat bagus. Ia memiliki mekanisme caching bawaan dan grup pengembangan aktif (Catatan Penerjemah: Ini jelas merupakan iklan~)
· FR_Presenter_debug adalah lapisan tampilan dari bagian debugging. Mengandalkannya, pengembang dapat men-debug aplikasi dan men-debugnya
. FR_Presenter_rest adalah lapisan presentasi REST yang memungkinkan pengembang mengeluarkan aplikasi dalam XML.
Dari struktur kelas dasar di atas, Anda seharusnya dapat melihat bagian-bagian berbeda dari MVC. FR_Module menyediakan semua yang dibutuhkan modul, sedangkan FR_Presenter menyediakan metode tampilan yang berbeda. Pada artikel berikutnya di seri ini, saya akan membuat pengontrol yang menyatukan semua kelas dasar di atas.
[Standar Pengkodean]
Sebelum Anda menulis kode secara formal, Anda harus duduk dan mendiskusikan (atau memikirkan tentang) standar pengkodean dengan mitra Anda (atau diri Anda sendiri). Ide keseluruhan pemrograman MVC berkisar pada dua poin: penggunaan kembali kode (mengurangi kebetulan) dan standarisasi kode. Saya merekomendasikan setidaknya hal-hal berikut untuk dipertimbangkan:
Hal pertama yang harus dipertimbangkan adalah standar penamaan dan singkatan variabel. Jangan bertengkar hebat dengan mitra Anda karena hal ini, tetapi setelah standar ditetapkan, standar tersebut harus dipatuhi dari awal hingga akhir, terutama saat menulis kode tingkat rendah (kelas dasar).
Sesuaikan awalan standar untuk digunakan pada semua fungsi, kelas, dan variabel global. Sayangnya, PHP tidak mendukung "namespace (namespace)". Jadi untuk menghindari kebingungan dan konflik dengan nama variabel, sebaiknya gunakan awalan. Saya akan menggunakan "FR_" sebagai awalan di seluruh artikel ini.
[Menulis lapisan bawah]
Perencanaan tingkat file sangat penting. Perencanaan hierarki dasar sederhana dan didefinisikan secara ketat:
/
config.php
indeks.php
termasuk/
Auth.php
Otentikasi/
No.php
Pengguna.php
Modul.php
Objek.php
Obyek/
DB.php
Presenter.php
Pembawa acara/
umum.php
debug.php
smarty.php
Cerdas/
modul/
contoh/
config.php
contoh.php
tpl/
contoh.tpl
tpl/
bawaan/
cache/
konfigurasi/
templat/
templates_c/
Anda mungkin berpikir bahwa hierarki file seperti itu harus mewakili banyak kode! Benar, tapi Anda bisa menyelesaikannya. Di akhir seri ini, Anda akan menemukan bahwa pemrograman Anda akan menjadi lebih mudah dan kecepatan pengembangan Anda akan meningkat pesat.
Dalam hierarki file, semua kelas dasar ada di folder include. Setiap modul fungsional menggunakan file konfigurasi, setidaknya satu file modul dan satu file template. Semua modul terdapat dalam folder modul. Saya sudah terbiasa menempatkan file template di folder eksternal terpisah, yaitu folder tpl.
config.php - file konfigurasi pusat, berisi semua variabel konfigurasi global.
index.php - Controller, akan dijelaskan secara detail pada artikel selanjutnya.
object.php - kelas yang mendasari semua kelas dasar, menyediakan sebagian besar fungsionalitas yang dibutuhkan oleh kelas tersebut. FR_Object_DB mewarisi kelas ini dan menyediakan link database.
Konsep dasar dari sebuah struktur adalah membuat semua subclass mewarisi dari kelas pusat sehingga mereka semua memiliki beberapa fitur yang sama. Anda dapat memasukkan fungsi link ke database ke dalam FR_Object, namun tidak semua kelas memerlukan fungsi ini, sehingga FR_Object_DB memiliki alasan keberadaannya, dan penulis akan membahasnya nanti.
<?php
require_once('Log.php');
/**
*FR_Objek
*
* Kelas objek dasar untuk sebagian besar kelas yang kami gunakan dalam kerangka kerja kami.
* Menyediakan fungsi logging dasar dan set/dapatkan.
*
* @penulis Joe Stump < [email protected] >
* @packageFramework
*/
kelas abstrak FR_Object
{
/**
* $log
*
* @var campuran $log Contoh Log PEAR
*/
dilindungi $log;
/**
*$saya
*
* @var campuran $me Contoh ReflectionClass
*/
dilindungi $saya;
/**
* __konstruksi
*
* @penulis Joe Stump < [email protected] >
* @akses publik
*/
fungsi publik __konstruksi()
{
$ini->log = Log::pabrik('file',FR_LOG_FILE);
$ini->saya = Kelas Refleksi baru($ini);
}
/**
* setDari
*
* @penulis Joe Stump < [email protected] >
* @akses publik
* @param campuran $data Array variabel untuk ditetapkan ke instance
* @pengembalian batal
*/
fungsi publik setFrom($data)
{
if (is_array($data) && hitungan($data)) {
$valid = get_class_vars(get_class($ini));
foreach ($valid sebagai $var => $val) {
if (isset($data[$var])) {
$ini->$var = $data[$var];
}
}
}
}
/**
* ke Array
*
* @penulis Joe Stump < [email protected] >
* @akses publik
* @return Campuran array variabel anggota yang dikunci berdasarkan nama variabel
*/
fungsi publik keArray()
{
$default = $ini->saya->getDefaultProperties();
$kembali = susunan();
foreach ($default sebagai $var => $val) {
if ($ini->$var instanceof FR_Object) {
$return[$var] = $ini->$var->toArray();
} kalau tidak {
$return[$var] = $ini->$var;
}
}
kembalikan $kembali;
}
/**
* __menghancurkan
*
* @penulis Joe Stump < [email protected] >
* @akses publik
* @pengembalian batal
*/
fungsi publik __destruct()
{
if ($this->log instanceof Log) {
$ini->log->tutup();
}
}
}
?>
auth.php – Ini adalah kelas dasar untuk semua fungsi otentikasi. Ini diperluas dari FR_Module, dan fungsi utamanya adalah untuk menentukan cara kerja kelas verifikasi dasar.
Sama seperti FR_Module, beberapa kelas tidak perlu terhubung ke database. Dengan cara yang sama, FR_Auth_No dapat dibuat dan diterapkan ke kelas yang tidak memerlukan fungsi otentikasi.
<?php
kelas abstrak FR_Auth memperluas FR_Module
{
// {{{ __konstruksi()
fungsi__konstruksi()
{
induk::__konstruksi();
}
// }}}
// {{{ autentikasi()
fungsi abstrak autentikasi();
// }}}
// {{{ __destruct()
fungsi __destruct()
{
induk::__destruct();
}
// }}}
}
?>
module.php - inti dari semua modul
<?php
kelas abstrak FR_Module memperluas FR_Object_Web
{
// {{{ properti
/**
* $penyaji
*
* Digunakan di FR_Presenter::factory() untuk menentukan presentasi mana (tampilan)
* kelas harus digunakan untuk modul.
*
* @penulis Joe Stump < [email protected] >
* @var string $presenter
* @lihat FR_Presenter, FR_Presenter_common, FR_Presenter_smarty
*/
publik $presenter = 'pintar';
/**
* $data
*
* Kumpulan data oleh modul yang pada akhirnya akan diteruskan ke tampilan.
*
* @penulis Joe Stump < [email protected] >
* @var mencampur $data Data modul
* @lihat FR_Module::set(), FR_Module::getData()
*/
dilindungi $data = array();
/**
* $nama
*
* @penulis Joe Stump < [email protected] >
* @var string $name Nama kelas modul
*/
publik $nama;
/**
* $tplFile
*
* @penulis Joe Stump < [email protected] >
* @var string $tplFile Nama file templat
* @lihat FR_Presenter_smarty
*/
publik $tplFile;
/**
* $namamodul
*
* @penulis Joe Stump < [email protected] >
* @var string $moduleName Nama modul yang diminta
* @lihat FR_Presenter_smarty
*/
publik $namamodul = nol;
/**
* $pageTemplateFile
*
* @penulis Joe Stump < [email protected] >
* @var string $pageTemplateFile Nama templat halaman luar
*/
publik $pageTemplateFile = nol;
// }}}
// {{{ __konstruksi()
/**
* __konstruksi
*
* @penulis Joe Stump < [email protected] >
*/
fungsi publik __konstruksi()
{
induk::__konstruksi();
$ini->nama = $ini->saya->getName();
$ini->tplFile = $ini->nama.'.tpl';
}
// }}}
// {{{ __bawaan()
/**
* __bawaan
*
* Fungsi ini dijalankan oleh pengontrol jika suatu peristiwa tidak ditentukan
* dalam permintaan pengguna.
*
* @penulis Joe Stump < [email protected] >
*/
fungsi publik abstrak __default();
// }}}
// {{{ set($var,$val)
/**
* mengatur
*
* Tetapkan data untuk modul Anda. Ini pada akhirnya akan diteruskan ke
* kelas presenter melalui FR_Module::getData().
*
* @penulis Joe Stump < [email protected] >
* @param string $var Nama variabel
* @param campuran $val Nilai variabel
* @pengembalian batal
* @lihat FR_Module::getData()
*/
kumpulan fungsi yang dilindungi($var,$val) {
$ini->data[$var] = $val;
}
// }}}
// {{{ getData()
/**
*dapatkanData
*
* Mengembalikan data modul.
*
* @penulis Joe Stump < [email protected] >
* @kembali dicampur
* @lihat FR_Presenter_common
*/
fungsi publik getData()
{
kembalikan $ini->data;
}
// }}}
// {{{ isValid($modul)
/**
*adalah Valid
*
* Menentukan apakah $module adalah modul kerangka kerja yang valid
* pengontrol untuk menentukan apakah modul cocok dengan kerangka kerja kita
* cetakan. Jika memanjang dari FR_Module dan FR_Auth maka seharusnya demikian
* bagus untuk dijalankan.
*
* @penulis Joe Stump < [email protected] >
* @statis
* @param campuran $modul
* @kembalikan bool
*/
fungsi statis publik isValid($modul)
{
kembali (is_object($modul) &&
$modul contoh FR_Module &&
$modul instanceof FR_Auth);
}
// }}}
// {{{ __destruct()
fungsi publik __destruct()
{
induk::__destruct();
}
// }}}
}
?>
presenter.php - inti dari lapisan presentasi.
<?php
kelas FR_Presenter
{
// {{{ pabrik($tipe,FR_Module $modul)
/**
*pabrik
*
* @penulis Joe Stump < [email protected] >
* @akses publik
* @param string $type Tipe presentasi (tampilan kami)
* @param mixed $module Modul kami, yang akan ditampilkan oleh presenter
* @return campuran PEAR_Error karena kegagalan atau presenter yang valid
* @statis
*/
pabrik fungsi publik statis($type,FR_Module $module)
{
$file = FR_BASE_PATH.'/includes/Presenter/'.$type.'.php';
jika (termasuk($file)) {
$kelas = 'FR_Presenter_'.$tipe;
if (kelas_ada($kelas)) {
$presenter = baru $kelas($modul);
if ($presenter instanceof FR_Presenter_common) {
kembalikan $presenter;
}
return PEAR::raiseError('Kelas presentasi tidak valid: '.$type);
}
return PEAR::raiseError('Kelas presentasi tidak ditemukan: '.$type);
}
return PEAR::raiseError('File presenter tidak ditemukan: '.$type);
}
// }}}
}
?>
Pada artikel selanjutnya, saya akan memperkenalkan struktur controller (Controller di MVC, index.php di artikel ini). Pada artikel ketiga, saya akan memperkenalkan lapisan presentasi (Lihat di MVC). Pada artikel keempat, saya akan menggunakan modul tertentu sebagai contoh untuk membuat aplikasi (Modul atau Model di MVC).