Apakah variabel global dalam PHP dianggap praktik yang buruk? Jika ya, mengapa?

86
function foo () {
    global $var;
    // rest of code
}

Dalam proyek PHP kecil saya, saya biasanya menggunakan cara prosedural. Saya biasanya memiliki variabel yang berisi konfigurasi sistem, dan ketika saya belum mengakses variabel ini dalam suatu fungsi, saya melakukannya global $var;.

Apakah ini praktik yang buruk?

KRTac
sumber
19
variabel global adalah sinonim untuk praktik buruk
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
2
Coba uji unit / penerimaan, dan Anda akan segera menemukan mengapa global menjadi masalah: mereka membuat kode Anda tidak dapat diandalkan ketika Anda melakukan sesuatu lebih dari sekali.
Kzqai

Jawaban:

103

Ketika orang berbicara tentang variabel global dalam bahasa lain, itu berarti sesuatu yang berbeda dengan apa yang dilakukannya di PHP. Itu karena variabel tidak benar - benar global di PHP. Cakupan program PHP tipikal adalah satu permintaan HTTP. Variabel sesi sebenarnya memiliki cakupan yang lebih luas daripada variabel "global" PHP karena biasanya mencakup banyak permintaan HTTP.

Seringkali (selalu?) Anda dapat memanggil fungsi anggota dengan metode preg_replace_callback()seperti ini:

preg_replace_callback('!pattern!', array($obj, 'method'), $str);

Lihat panggilan balik untuk lebih lanjut.

Intinya adalah bahwa objek telah dibaut ke PHP dan dalam beberapa hal menyebabkan beberapa kecanggungan.

Jangan terlalu menyibukkan diri dengan menerapkan standar atau konstruksi dari bahasa berbeda ke PHP. Perangkap umum lainnya adalah mencoba mengubah PHP menjadi bahasa OOP murni dengan menempelkan model objek di atas segalanya.

Seperti yang lainnya, gunakan variabel "global", kode prosedural, kerangka kerja tertentu, dan OOP karena masuk akal, memecahkan masalah, mengurangi jumlah kode yang perlu Anda tulis atau membuatnya lebih mudah dipelihara dan lebih mudah dipahami, bukan karena Anda berpikir kamu harus.

cletus
sumber
8
Perlu dicatat bahwa PHP 5.3 menangani beberapa hal ini dengan fungsi lambda yang memungkinkan Anda menghindari penggunaan fungsi yang dideklarasikan dalam cakupan global untuk callback. +1 untuk saran kode yang dapat dipelihara dan dapat dibaca
Jonathan Fingland
Bisakah Anda tidak menggunakan formulir panggilan balik array ($obj, 'callbackMethod')dalam panggilan ke preg_replace_callback()? (Saya tahu, saya telah menjadi mangsa perangkap OOP ini ...)
grossvogel
26
Pertanyaannya bukanlah "haruskah variabel global digunakan?". Jawabannya adalah, 'yakin pada saat tertentu jika perlu'. Pertanyaannya adalah apakah mereka praktik yang buruk. Jawabannya adalah 'ya, terkadang'. Untuk proyek kecil poster, tidak ada hal buruk yang mungkin terjadi - namun untuk proyek yang lebih besar dengan banyak anggota tim dan banyak bagian yang bergerak, penggunaan variabel global yang berlebihan akan membuat kode sulit untuk di-debug, hampir tidak mungkin untuk refactor, dan bahkan merepotkan Baca. Bisakah Anda menggunakannya kadang-kadang, .. tentu - apakah mereka benar-benar payah, .. ya!
eddiemoya
@eddiemoya Nah kata Edie. Ada begitu banyak orang yang membenarkan praktik buruk seperti menggunakan variabel global. Anda harus menghindari mereka seperti wabah. Setiap gelar teknik perangkat lunak yang layak akan mengebor ini ke Anda ... para dosen tidak hanya memberi tahu Anda untuk itu ... mereka tahu dari pengalaman puluhan tahun. Anda harus menggunakan fungsi anggota jika memungkinkan untuk mengakses nilai yang Anda butuhkan, misalnya get_query_var () di Wordpress dll.
27

Variabel global jika tidak digunakan dengan hati-hati dapat membuat masalah lebih sulit ditemukan. Katakanlah Anda meminta skrip php dan Anda mendapatkan peringatan yang mengatakan Anda mencoba mengakses indeks dari sebuah array yang tidak ada di beberapa fungsi.

Jika array yang Anda coba akses bersifat lokal untuk fungsi tersebut, Anda memeriksa fungsi tersebut untuk melihat apakah Anda telah membuat kesalahan di sana. Mungkin ada masalah dengan masukan ke fungsi sehingga Anda memeriksa tempat di mana fungsi tersebut dipanggil.

Tetapi jika array itu global, Anda perlu memeriksa semua tempat di mana Anda menggunakan variabel global itu, dan tidak hanya itu, Anda harus mencari tahu bagaimana urutan referensi ke variabel global itu diakses.

Jika Anda memiliki variabel global dalam sebuah kode, maka fungsionalitas kode tersebut akan sulit diisolasi. Mengapa Anda ingin memisahkan fungsionalitas? Jadi, Anda dapat mengujinya dan menggunakannya kembali di tempat lain. Jika Anda memiliki beberapa kode, Anda tidak perlu menguji dan tidak perlu menggunakan kembali maka menggunakan variabel global tidak masalah.

rojoca
sumber
Tetapi kesalahan sebagian besar menunjukkan di file / baris mana skrip rusak jadi .. Saya tidak melihat masalah di sini
samayo
8
Place where script break! = Tempat kesalahan dibuat.
HonoredMule
16

saya setuju dengan cletus. saya akan menambahkan dua hal:

  1. gunakan awalan sehingga Anda dapat segera mengidentifikasinya sebagai global (mis. $ g_)
  2. mendeklarasikannya di satu tempat, jangan menaburkannya di sekitar kode.

salam, don

Don Dickinson
sumber
1
Ya, saya selalu memberi awalan variabel yang ingin saya gunakan secara global dengan garis bawah.
KRTac
10
@KRTac tetapi $ _testVariable biasanya dipahami sebagai variabel privat - itu adalah standar informal untuk mendefinisikan variabel privat, bukan variabel global.
Aditya MP
6
Praktik umum adalah mendefinisikan vars global menggunakan ALL CAPS. contoh:$DB = 'foo';
pixeline
7

Siapa yang dapat membantah pengalaman, gelar sarjana, dan rekayasa perangkat lunak? Bukan saya. Saya hanya akan mengatakan bahwa dalam mengembangkan aplikasi PHP satu halaman berorientasi objek, saya lebih bersenang-senang ketika saya tahu saya dapat membangun semuanya dari awal tanpa khawatir tentang tabrakan namespace. Membangun dari awal adalah sesuatu yang tidak lagi dilakukan banyak orang. Mereka memiliki pekerjaan, tenggat waktu, bonus, atau reputasi yang harus diperhatikan. Jenis ini cenderung menggunakan begitu banyak kode yang dibuat sebelumnya dengan taruhan tinggi, sehingga mereka tidak dapat mengambil risiko menggunakan variabel global sama sekali.

Menggunakan variabel global mungkin buruk, meskipun hanya digunakan di area global suatu program, tapi jangan lupakan mereka yang hanya ingin bersenang-senang dan membuat sesuatu berfungsi .

Jika itu berarti menggunakan beberapa variabel (<10) di namespace global, yang hanya digunakan di area global program, biarlah. Ya, ya, MVC, injeksi ketergantungan, kode eksternal, bla, bla, bla, bla. Tetapi, jika Anda telah memasukkan 99,99% kode Anda ke dalam namespace dan kelas, dan kode eksternal di-sandbox, dunia tidak akan berakhir (saya ulangi, dunia tidak akan berakhir) jika Anda menggunakan variabel global.

Secara umum, saya tidak akan mengatakan penggunaan variabel global adalah praktik yang buruk . Saya akan mengatakan bahwa menggunakan variabel global (bendera dan semacamnya) di luar area global suatu program akan menimbulkan masalah dan (dalam jangka panjang) tidak disarankan karena Anda dapat kehilangan jejak statusnya dengan mudah. Juga, saya akan mengatakan bahwa semakin banyak Anda belajar, semakin tidak bergantung Anda pada variabel global karena Anda akan mengalami "kegembiraan" melacak bug yang terkait dengan penggunaannya. Ini saja akan mendorong Anda untuk menemukan cara lain untuk menyelesaikan masalah yang sama. Secara kebetulan, ini cenderung mendorong orang-orang PHP ke arah belajar bagaimana menggunakan namespace dan kelas (anggota statis, dll ...).

Bidang ilmu komputer sangat luas. Jika kita menakut-nakuti semua orang agar tidak melakukan sesuatu karena kita menyebutnya buruk , maka mereka kehilangan kesenangan untuk benar-benar memahami alasan di balik label tersebut.

Gunakan variabel global jika Anda harus, tetapi kemudian lihat apakah Anda dapat menyelesaikan masalah tanpa variabel tersebut. Tabrakan, pengujian, dan debugging akan lebih berarti jika Anda benar-benar memahami sifat sebenarnya dari masalah, bukan hanya deskripsi masalah.

Anthony Rutledge
sumber
3

Diposting ulang dari SO Dokumentasi Beta

Kami dapat menggambarkan masalah ini dengan pseudo-code berikut

function foo() {
     global $bob;
     $bob->doSomething();
}

Pertanyaan pertama Anda di sini sudah jelas

Dari mana $bobasalnya?

Apakah kamu bingung? Baik. Anda baru saja mempelajari mengapa global itu membingungkan dan dianggap sebagai praktik yang buruk. Jika ini adalah program nyata, kesenangan Anda berikutnya adalah melacak semua contoh $bobdan berharap Anda menemukan yang tepat (ini menjadi lebih buruk jika $bobdigunakan di mana-mana). Lebih buruk lagi, jika orang lain pergi dan mendefinisikan $bob(atau Anda lupa dan menggunakan kembali variabel itu) kode Anda dapat rusak (dalam contoh kode di atas, memiliki objek yang salah, atau tidak ada objek sama sekali, akan menyebabkan kesalahan fatal). Karena hampir semua program PHP menggunakan kode seperti include('file.php');pekerjaan Anda memelihara kode seperti ini menjadi semakin sulit secara eksponensial semakin banyak file yang Anda tambahkan.

Bagaimana kita menghindari Globals?

Cara terbaik untuk menghindari global adalah filosofi yang disebut Injeksi Ketergantungan . Di sinilah kita meneruskan alat yang kita butuhkan ke dalam fungsi atau kelas.

function foo(\Bar $bob) {
    $bob->doSomething();
}

Ini jauh lebih mudah untuk dipahami dan dipertahankan. Tidak ada yang menebak di mana $bobitu diatur karena penelepon bertanggung jawab untuk mengetahui itu (itu menyampaikan apa yang perlu kita ketahui). Lebih baik lagi, kita bisa menggunakan deklarasi tipe untuk membatasi apa yang sedang diteruskan. Jadi kita tahu itu $bobadalah salah satu contoh Barkelas, atau turunan dari anak Bar, artinya kita tahu kita bisa menggunakan metode kelas itu. Dikombinasikan dengan autoloader standar (tersedia sejak PHP 5.3), kita sekarang dapat melacak di mana Bardidefinisikan. PHP 7.0 atau yang lebih baru menyertakan deklarasi tipe yang diperluas, di mana Anda juga dapat menggunakan tipe skalar (seperti intatau string).

Machavity
sumber
Alternatif untuk melewatkan $ bob ke mana-mana, adalah membuat kelas Bar menjadi tunggal, menyimpan instance Bar secara statis di dalam Bar itu sendiri, dan menggunakan metode statis untuk membuat instance / mengambil objek. Kemudian Anda bisa $bob = Bar::instance();kapan saja Anda membutuhkannya.
Scoots
1
Sadarilah bahwa Singletons dianggap anti-pola . Injeksi Ketergantungan menghindari jebakan tersebut
Machavity
2
Ada beberapa tingkat perselisihan dalam kiriman yang Anda tautkan (Misalnya, komentar peringkat teratas untuk jawaban yang diterima dan jawaban yang paling disukai kedua sangat tidak setuju dengan jawaban yang diterima), membuat saya cenderung berpendapat bahwa penggunaan Singletons harus dipertimbangkan atas dasar kasus per kasus, bukannya diberhentikan begitu saja.
Scoots
1

Sebagai:

global $my_global; 
$my_global = 'Transport me between functions';
Equals $GLOBALS['my_global']

adalah praktik yang buruk (Seperti Wordpress $pagenow) ... hmmm

Pertimbangkan ini:

$my-global = 'Transport me between functions';

adalah kesalahan PHP Tapi:

$GLOBALS['my-global'] = 'Transport me between functions';

adalah TIDAK kesalahan, hypens tidak akan berbenturan dengan "umum" pengguna menyatakan variabel, seperti $pagenow. Dan Menggunakan UPPERCASE menunjukkan superglobal sedang digunakan, mudah dikenali dalam kode, atau dilacak dengan menemukan dalam file

Saya menggunakan tanda hubung, jika saya malas membuat kelas dari segalanya untuk satu solusi, seperti:

$GLOBALS['PREFIX-MY-GLOBAL'] = 'Transport me ... ';

Tetapi dalam kasus penggunaan yang lebih luas, saya menggunakan SATU global sebagai array:

$GLOBALS['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... ';
$GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... ';

Yang terakhir bagi saya, praktik yang baik tentang tujuan atau penggunaan "cola light", daripada mengacaukan kelas tunggal setiap kali "menyimpan" beberapa data. Tolong beri komentar jika saya salah atau melewatkan sesuatu yang bodoh di sini ...

Jonas Lundman
sumber