Le variabili globali in PHP sono considerate cattive pratiche? In caso affermativo, perché?


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

Nei miei piccoli progetti PHP di solito vado in modo procedurale. In genere ho una variabile che contiene la configurazione del sistema e quando devo accedere a questa variabile in una funzione, lo faccio global $var;.

Questa è una cattiva pratica?


19
la variabile globale è sinonimo di cattiva pratica
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳


2
Prova a testarlo per unità / accettazione e scoprirai rapidamente perché le globali sono un problema: rendono il tuo codice inaffidabile quando fai cose più di una volta.
Kzqai

Risposte:


102

Quando le persone parlano di variabili globali in altre lingue significa qualcosa di diverso da quello che fa in PHP. Questo perché le variabili non sono realmente globali in PHP. Lo scopo di un tipico programma PHP è una richiesta HTTP. Le variabili di sessione hanno effettivamente un ambito più ampio rispetto alle variabili "globali" di PHP perché in genere comprendono molte richieste HTTP.

Spesso (sempre?) Puoi chiamare funzioni membro in metodi preg_replace_callback()come questo:

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

Vedi i callback per ulteriori informazioni.

Il punto è che gli oggetti sono stati imbullonati su PHP e in qualche modo portano a qualche imbarazzo.

Non preoccuparti eccessivamente dell'applicazione di standard o costrutti da linguaggi diversi a PHP. Un'altra trappola comune è cercare di trasformare PHP in un linguaggio OOP puro incollando modelli di oggetti sopra tutto.

Come ogni altra cosa, usa variabili "globali", codice procedurale, un particolare framework e OOP perché ha senso, risolve un problema, riduce la quantità di codice che devi scrivere o lo rende più manutenibile e più facile da capire, non perché pensi dovresti.


8
Va notato che PHP 5.3 risolve alcuni di questi problemi con le funzioni lambda che consentono di evitare di utilizzare la funzione dichiarata nell'ambito globale per i callback. +1 per consigli sul codice leggibile e gestibile
Jonathan Fingland

Non puoi utilizzare un callback del modulo array ($obj, 'callbackMethod')nelle chiamate a preg_replace_callback()? (Lo so, sono caduto preda di questa trappola OOP ...)
grossvogel

25
La domanda non era "le variabili globali dovrebbero mai essere usate?". La risposta a questa domanda sarebbe "certo a volte, se necessario". La domanda è: sono cattive pratiche. La risposta è "sì, a volte". Per il piccolo progetto dei poster, non può derivarne nulla di male - tuttavia per progetti più grandi con molti membri del team e molte parti in movimento, l'uso pesante di variabili globali renderà il codice difficile da eseguire il debug, quasi impossibile da refactoring e persino un problema leggere. Puoi usarli a volte, .. certo - fanno schifo, .. sì!
eddiemoya

@eddiemoya Ben detto Eddie. Ci sono così tante persone che giustificano cattive pratiche come l'utilizzo di variabili globali. Dovresti evitarli come la peste. Qualsiasi laurea in ingegneria del software decente ti trapanerà questo ... i docenti non te lo dicono solo per il gusto di farlo ... lo sanno per decenni di esperienza. Dovresti usare le funzioni membro dove possibile per accedere ai valori di cui hai bisogno, ad esempio get_query_var () in Wordpress ecc.

27

Le variabili globali, se non utilizzate con attenzione, possono rendere i problemi più difficili da trovare. Supponiamo che tu richieda uno script php e ricevi un avviso che dice che stai cercando di accedere a un indice di un array che non esiste in qualche funzione.

Se l'array a cui stai tentando di accedere è locale rispetto alla funzione, controlla la funzione per vedere se hai commesso un errore lì. Potrebbe essere un problema con un input alla funzione in modo da controllare i punti in cui viene chiamata la funzione.

Ma se quell'array è globale, devi controllare tutti i posti in cui usi quella variabile globale, e non solo quello, devi capire in quale ordine si accede a quei riferimenti alla variabile globale.

Se hai una variabile globale in un pezzo di codice, è difficile isolare la funzionalità di quel codice. Perché dovresti isolare la funzionalità? Quindi puoi testarlo e riutilizzarlo altrove. Se si dispone di codice che non è necessario testare e non è necessario riutilizzarlo, è possibile utilizzare le variabili globali.


Ma l'errore mostra principalmente in quale file / riga lo script si sta interrompendo, quindi .. Non vedo il problema qui
samayo

8
Luogo in cui si è rotto lo script! = Luogo in cui è stato commesso l'errore.
HonoredMule

16

sono d'accordo con Cletus. aggiungerei due cose:

  1. usa un prefisso in modo da poterlo identificare immediatamente come globale (ad esempio $ g_)
  2. dichiarali in un punto, non cospargerli tutto intorno al codice.

i migliori saluti, don


1
Sì, aggiungo sempre un carattere di sottolineatura alle variabili che intendo utilizzare a livello globale.
KRTac

9
@KRTac ma $ _testVariable è generalmente inteso come una variabile privata: è uno standard informale per definire variabili private, non globali.
Aditya MP

6
Una pratica comune è definire variabili globali utilizzando TUTTO MAIUSCOLO. esempio:$DB = 'foo';
pixeline

7

Chi può discutere contro l'esperienza, i diplomi universitari e l'ingegneria del software? Non me. Vorrei solo dire che nello sviluppo di applicazioni PHP a pagina singola orientate agli oggetti, mi diverto di più quando so di poter costruire l'intera cosa da zero senza preoccuparmi delle collisioni nello spazio dei nomi. Costruire da zero è qualcosa che molte persone non fanno più. Hanno un lavoro, una scadenza, un bonus o una reputazione di cui preoccuparsi. Questi tipi tendono a utilizzare così tanto codice precostruito con una posta in gioco alta, che non possono rischiare di utilizzare variabili globali.

Può essere un male usare le variabili globali, anche se vengono utilizzate solo nell'area globale di un programma, ma non dimentichiamoci di coloro che vogliono solo divertirsi e far funzionare qualcosa .

Se questo significa usare poche variabili (<10) nello spazio dei nomi globale, queste vengono utilizzate solo nell'area globale di un programma, così sia. Sì, sì, MVC, inserimento delle dipendenze, codice esterno, blah, blah, blah, blah. Ma, se hai contenuto il 99,99% del tuo codice in spazi dei nomi e classi, e il codice esterno è sandbox, il mondo non finirà (ripeto, il mondo non finirà) se usi una variabile globale.

In generale, non direi che l'uso di variabili globali è una cattiva pratica . Direi che l'utilizzo di variabili globali (flag e simili) al di fuori dell'area globale di un programma è fonte di guai e (a lungo andare) sconsiderato perché puoi perdere traccia dei loro stati piuttosto facilmente. Inoltre, direi che più impari, meno dipenderai dalle variabili globali perché avrai sperimentato la "gioia" di rintracciare i bug associati al loro utilizzo. Questo da solo ti incentiverà a trovare un altro modo per risolvere lo stesso problema. Per coincidenza, questo tende a spingere le persone PHP nella direzione di imparare a usare gli spazi dei nomi e le classi (membri statici, ecc ...).

Il campo dell'informatica è vasto. Se spaventiamo tutti dal fare qualcosa perché lo etichettiamo male , allora perdono il divertimento di capire veramente il ragionamento dietro l'etichetta.

Usa le variabili globali se devi, ma poi vedi se puoi risolvere il problema senza di esse. Collisioni, test e debug significano di più quando si comprende intimamente la vera natura del problema, non solo una descrizione del problema.


3

Ripubblicato dalla versione beta della documentazione SO terminata

Possiamo illustrare questo problema con il seguente pseudo-codice

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

La tua prima domanda qui è ovvia

Da dove $bobviene?

Sei confuso? Buono. Hai appena imparato perché i globali creano confusione e sono considerati una cattiva pratica. Se questo fosse un programma reale, il tuo prossimo divertimento è rintracciare tutte le istanze $bobe sperare di trovare quello giusto (questo peggiora se $bobviene utilizzato ovunque). Peggio ancora, se qualcun altro va e definisce $bob(o hai dimenticato e riutilizzato quella variabile) il tuo codice può rompersi (nell'esempio di codice sopra, avere l'oggetto sbagliato, o nessun oggetto, causerebbe un errore fatale). Poiché praticamente tutti i programmi PHP fanno uso di codice come il include('file.php');tuo lavoro, mantenere un codice come questo diventa esponenzialmente più difficile con il numero di file aggiunti.

Come evitiamo i Globali?

Il modo migliore per evitare le globali è una filosofia chiamata Dependency Injection . Qui è dove passiamo gli strumenti di cui abbiamo bisogno nella funzione o nella classe.

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

Questo è molto più facile da capire e da mantenere. Non è possibile indovinare dove è $bobstato impostato perché il chiamante è responsabile di saperlo (ci sta trasmettendo ciò che dobbiamo sapere). Meglio ancora, possiamo usare dichiarazioni di tipo per limitare ciò che viene passato. Quindi sappiamo che $bobè un'istanza della Barclasse o un'istanza di un figlio di Bar, il che significa che sappiamo che possiamo usare i metodi di quella classe. In combinazione con un autoloader standard (disponibile da PHP 5.3), ora possiamo rintracciare dove Barè definito. PHP 7.0 o versioni successive include dichiarazioni di tipo espanso, dove puoi anche usare tipi scalari (come into string).


Un'alternativa al dover passare $ bob ovunque, consiste nel rendere la classe Bar un singleton, memorizzare un'istanza di Bar staticamente all'interno di Bar stesso e utilizzare un metodo statico per istanziare / recuperare l'oggetto. Quindi puoi solo $bob = Bar::instance();quando ne hai bisogno.
Scoot

1
Basta essere consapevoli del fatto che i single sono considerati un anti-pattern . Dependency Injection evita queste insidie
Machavity

2
C'è un certo grado di contesa all'interno del post a cui ti sei collegato (ad esempio, il commento più votato alla risposta accettata e la seconda risposta più votata entrambi sono fortemente in disaccordo con la risposta accettata), rendendomi propenso a sostenere che l'uso di Singletons dovrebbe essere considerato caso per caso, piuttosto che licenziato sommariamente.
Scoot

0

Come:

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

è una cattiva pratica (come Wordpress $pagenow) ... hmmm

Considera questo:

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

è un errore PHP Ma:

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

NON è un errore, i trattini non entreranno in conflitto con le variabili dichiarate dall'utente "comuni", come $pagenow. E l'utilizzo di MAIUSCOLO indica un superglobale in uso, facile da individuare nel codice o da tracciare con la ricerca nei file

Uso i trattini, se sono pigro per costruire classi di tutto per una singola soluzione, come:

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

Ma nei casi di un utilizzo più ampio, utilizzo ONE globals come array:

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

Quest'ultimo è per me una buona pratica su obiettivi o utilizzo "cola light", invece di ingombrare ogni volta con classi singleton per "cache" alcuni dati. Per favore, fai un commento se sbaglio o mi manca qualcosa di stupido qui ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.