PHP'deki global değişkenler kötü uygulama olarak kabul edilir mi? Öyleyse neden?


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

Küçük PHP projelerimde genellikle yordamsal yoldan gidiyorum. Genelde sistem konfigürasyonunu içeren bir değişkenim var ve bu değişkene bir fonksiyonda erişmeye ihtiyaç duyduğumda var global $var;.

Bu kötü bir uygulama mı?


19
genel değişken, kötü uygulama ile eşanlamlıdır
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳


2
Birim / kabul testini deneyin ve küresellerin neden bir sorun olduğunu çabucak anlayacaksınız: Bir şeyi birden fazla yaptığınızda kodunuzu güvenilmez hale getiriyorlar.
Kzqai

Yanıtlar:


103

İnsanlar diğer dillerdeki küresel değişkenler hakkında konuştuğunda, bu PHP'de yaptıklarından farklı bir anlama gelir. Bunun nedeni değişkenlerin PHP'de gerçekten küresel olmamasıdır . Tipik bir PHP programının kapsamı bir HTTP isteğidir. Oturum değişkenleri aslında PHP "global" değişkenlerinden daha geniş bir kapsama sahiptir, çünkü bunlar genellikle birçok HTTP isteğini kapsar.

Genellikle (her zaman?) Aşağıdaki gibi yöntemlerde üye işlevleri çağırabilirsiniz preg_replace_callback():

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

Daha fazlası için geri aramalara bakın .

Mesele şu ki, nesneler PHP'ye cıvatalanmış ve bazı şekillerde bazı garipliklere yol açıyor.

Standartları veya farklı dillerden yapıları PHP'ye uygulamakla fazla ilgilenmeyin. Diğer bir yaygın tuzak, nesne modellerini her şeyin üzerine yapıştırarak PHP'yi saf bir OOP diline dönüştürmeye çalışmaktır.

Her şey gibi, "global" değişkenler, prosedürel kod, belirli bir çerçeve ve OOP kullanın çünkü bu mantıklıdır, bir sorunu çözer, yazmanız gereken kod miktarını azaltır veya onu daha sürdürülebilir ve anlaşılır hale getirir, çünkü düşündüğünüz için değil malısın.


8
PHP 5.3'ün, geri aramalar için global kapsamda bildirilen işlevi kullanmaktan kaçınmanıza izin veren lambda işlevleriyle bunun bazılarını ele aldığına dikkat edilmelidir.
Sürdürülebilir

array ($obj, 'callbackMethod')Çağrılarda formun geri aranmasını kullanamaz preg_replace_callback()mısınız? (Biliyorum, bu OOP
tuzağına düştüm

26
Soru "global değişkenler hiç kullanılmalı mı?" Değildi. Bunun yanıtı, "gerekirse ara sıra elbette" olacaktır. Soru, kötü pratik olmaları. Cevap 'evet, bazen'. Afişler için küçük proje, bundan kötü bir şey çıkmayabilir - ancak çok sayıda ekip üyesi ve çok sayıda hareketli parçası olan daha büyük projeler için, küresel değişkenlerin yoğun kullanımı kodun hatalarını gidermeyi zorlaştıracak, yeniden düzenlemeyi neredeyse imkansız hale getirecek ve hatta acı çekecektir. okuyun. Bazen onları kullanabilir misin, .. tabii - berbat mıdırlar, .. evet!
eddiemoya

@eddiemoya Peki Eddie dedi. Küresel değişkenleri kullanmak gibi kötü uygulamaları haklı çıkaran pek çok insan var. Onlardan veba gibi uzak durmalısın. Herhangi bir iyi yazılım mühendisliği derecesi bunu sizin için derinleştirecektir ... öğretim görevlileri size sadece cehennemini söylemiyor ... onlarca yıllık deneyimlerinden biliyorlar. İhtiyaç duyduğunuz değerlere erişmek için mümkün olduğunda üye işlevlerini kullanmalısınız, örneğin Wordpress'te get_query_var () vb.

27

Global değişkenler dikkatli kullanılmazlarsa problemlerin bulunmasını zorlaştırabilir. Diyelim ki bir php betiği talep ettiniz ve bazı işlevlerde bulunmayan bir dizinin dizinine erişmeye çalıştığınızı söyleyen bir uyarı alıyorsunuz.

Erişmeye çalıştığınız dizi işlev için yerelse, orada bir hata yapıp yapmadığınızı görmek için işlevi kontrol edin. Bu, işleve bir girişte sorun olabilir, bu nedenle işlevin çağrıldığı yerleri kontrol edin.

Ancak bu dizi global ise, bu global değişkeni kullandığınız tüm yerleri kontrol etmeniz gerekir ve sadece bu değil, global değişkene bu referanslara hangi sırayla erişildiğini bulmanız gerekir.

Bir kod parçasında global bir değişkeniniz varsa, bu kodun işlevselliğini izole etmeyi zorlaştırır. Neden işlevselliği izole etmek istersiniz? Böylece onu test edebilir ve başka bir yerde yeniden kullanabilirsiniz. Eğer bir kodunuz varsa, test etmeniz gerekmiyorsa ve tekrar kullanmanız gerekmiyorsa, o zaman global değişkenleri kullanmak iyidir.


Ancak hata çoğunlukla betiğin hangi dosya / satırda kırıldığını gösterir, bu yüzden .. Problemi burada görmüyorum
samayo

8
Komut dosyasının bozulduğu yer! = Hatanın yapıldığı yer.
HonoredMule

16

cletus'a katılıyorum. iki şey eklerdim:

  1. hemen global olarak tanımlayabilmek için bir önek kullanın (örneğin, $ g_)
  2. onları tek bir noktada ilan edin, kodun etrafına serpiştirmeyin.

saygılarımla, don


1
Jeah, ben her zaman global olarak kullanmayı düşündüğüm değişkenlerin önüne bir alt çizgi koyarım.
KRTac

10
@KRTac ancak $ _testVariable genellikle özel bir değişken olarak anlaşılır - bu, özel değişkenleri tanımlamak için resmi olmayan bir standart, global olanları değil.
Aditya MP

6
Genel bir uygulama, TÜM BÜYÜK HARF'leri kullanarak genel değişkenleri tanımlamaktır. örnek:$DB = 'foo';
pixeline

7

Tecrübe, üniversite diplomaları ve yazılım mühendisliğine kim karşı çıkabilir? Ben değilim. Sadece nesne yönelimli tek sayfalı PHP uygulamaları geliştirirken, ad alanı çarpışmaları konusunda endişelenmeden her şeyi sıfırdan oluşturabileceğimi bildiğimde daha çok eğlenirim. Sıfırdan inşa etmek, birçok insanın artık yapmadığı bir şey. İlgilenmeleri gereken bir işi, son tarihi, ikramiyesi veya itibarı vardır. Bu türler, yüksek riskli önceden oluşturulmuş çok fazla kod kullanma eğilimindedir ve küresel değişkenleri kullanma riskini hiçbir şekilde alamazlar.

Global değişkenleri kullanmak, bir programın yalnızca global alanında kullanılsalar bile kötü olabilir, ancak sadece eğlenmek ve bir şeyler yapmak isteyenleri unutmayalım .

Bu, global ad alanında birkaç değişken (<10) kullanmak anlamına geliyorsa, bu yalnızca bir programın global alanında kullanılır, öyle olsun. Evet, evet, MVC, bağımlılık enjeksiyonu, harici kod, blah, blah, blah, blah. Ancak, kodunuzun% 99.99'unu ad alanlarına ve sınıflara dahil ettiyseniz ve harici kod korumalı alana alınmışsa, global bir değişken kullanırsanız dünya sona ermeyecektir (tekrar ediyorum, dünya sona ermeyecektir).

Genel olarak, küresel değişkenleri kullanmanın kötü bir uygulama olduğunu söylemem . Bir programın küresel alanı dışında küresel değişkenler (bayraklar ve benzeri) kullanmanın sorun yarattığını ve (uzun vadede) kötü tavsiye edildiğini söyleyebilirim , çünkü durumlarının izini oldukça kolay kaybedebilirsiniz. Ayrıca, ne kadar çok öğrenirseniz, küresel değişkenlere o kadar az bağımlı olacağınızı söyleyebilirim, çünkü bunların kullanımıyla ilişkili hataları bulmanın "neşesini" deneyimlemiş olacaksınız. Bu tek başına sizi aynı sorunu çözmek için başka bir yol bulmaya teşvik edecektir. Tesadüfen, bu PHP çalışanlarını ad alanlarının ve sınıfların (statik üyeler, vb.) Nasıl kullanılacağını öğrenme yönüne itme eğilimindedir.

Bilgisayar bilimi alanı çok geniştir. Herkesi bir şeyi kötü olarak nitelendirdiğimiz için yapmaktan korkutursak , etiketin arkasındaki mantığı gerçekten anlamanın eğlencesini kaybederler.

Gerekirse global değişkenleri kullanın, ancak sorunu onlarsız çözüp çözemeyeceğinizi görün. Çarpışmalar, testler ve hata ayıklama, yalnızca sorunun bir açıklamasını değil, sorunun gerçek doğasını yakından anladığınızda daha fazla anlama gelir.


3

Biten SO Documentation Beta'dan yeniden yayınlandı

Bu sorunu aşağıdaki sözde kod ile gösterebiliriz

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

Buradaki ilk sorunuz apaçık bir soru

Nereden $bobgeldi

Kafan mı karıştı? İyi. Küresellerin neden kafa karıştırıcı olduğunu ve kötü bir uygulama olarak kabul edildiğini yeni öğrendiniz. Bu gerçek bir program olsaydı, bir sonraki eğlenceniz, tüm örneklerin izini sürmek $bobve doğru olanı bulmanızı ummaktır ( $bobher yerde kullanılırsa bu daha da kötüleşir ). Daha da kötüsü, başka biri gidip tanımlarsa $bob(veya bu değişkeni unutup yeniden kullanırsanız) kodunuz kırılabilir (yukarıdaki kod örneğinde, yanlış nesneye sahip olmak veya hiç nesneye sahip olmamak, ölümcül bir hataya neden olur). Neredeyse tüm PHP programları, include('file.php');sizin işiniz gibi kodu kullandığından, kodun bu şekilde korunması, eklediğiniz dosya sayısı arttıkça katlanarak zorlaşır.

Küresellerden nasıl kaçınırız?

Küresellerden kaçınmanın en iyi yolu, Bağımlılık Enjeksiyonu adı verilen bir felsefedir . Bu, ihtiyaç duyduğumuz araçları işleve veya sınıfa geçirdiğimiz yerdir.

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

Bunu anlamak ve sürdürmek çok daha kolay. Nerede $bobkurulduğuna dair hiçbir tahmin yoktur çünkü arayan kişi bunu bilmekten sorumludur (bilmemiz gereken şeyi bize iletir). Daha da iyisi, iletileni kısıtlamak için tür bildirimlerini kullanabiliriz . Yani bunun $bobya Barsınıfın bir örneği ya da bir alt sınıfın örneği Barolduğunu biliyoruz, yani o sınıfın yöntemlerini kullanabileceğimizi biliyoruz. Standart bir otomatik yükleyici ile birleştirildiğinde (PHP 5.3'ten beri mevcuttur), şimdi nerede Bartanımlandığını izleyebiliriz . PHP 7.0 veya üstü, skaler türleri de ( intveya gibi string) kullanabileceğiniz genişletilmiş tür bildirimlerini içerir .


$ Bob'u her yere iletmek zorunda kalmanın bir alternatifi, Bar sınıfını tekil yapmak, Bar örneğini statik olarak Bar'ın içinde depolamak ve nesneyi başlatmak / getirmek için statik bir yöntem kullanmaktır. O $bob = Bar::instance();zaman ihtiyacın olduğu anda yapabilirsin .
Scoots

1
Sadece Singletonların bir anti-model olarak kabul edildiğini unutmayın . Bağımlılık Enjeksiyonu bu tuzaklardan kaçınır
Machavity

2
Bu gönderi içinde bağlantı kurduğunuz bir dereceye kadar çekişme var (Örneğin, kabul edilen cevaba en çok oy alan yorum ve en çok oy alan ikinci cevap, kabul edilen cevaba kesinlikle katılmıyor), bu da beni Singleton kullanımının gerektiğini iddia etmeye meyilli hale getiriyor. özet olarak elden çıkarılmak yerine, duruma göre değerlendirilmelidir.
Scoots

1

Gibi:

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

kötü bir uygulamadır (Wordpress gibi $pagenow) ... hmmm

Şunu düşünün:

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

PHP hatasıdır Ama:

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

olduğu DEĞİL hata, hypens çatışma olmayacak ile "ortak" kullanıcı gibi değişkenleri ilan $pagenow. Ve BÜYÜK HARF kullanmak, kullanımda olan, kodda kolayca tespit edilebilen veya dosyalarda bulmayla izlenen bir süper küresel olduğunu gösterir.

Tek bir çözüm için her şeyin sınıflarını oluşturmakta tembelysem, kısa çizgi kullanıyorum, örneğin:

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

Ancak daha geniş bir kullanım durumunda kullanıyorum dizi olarak BİR global :

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

İkincisi benim için, her seferinde bazı verileri "önbelleğe almak" için tekli sınıflarla dağınıklık yerine "kola ışık" hedefleri veya kullanımıyla ilgili iyi bir uygulama . Burada yanlışsam veya aptalca bir şey kaçırırsam lütfen yorum yapın ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.