venerdì, agosto 30, 2013

Php - Alcune cose sulle variabili

Questo post fa parte di una serie preparata qualche anno fa per delle lezioni su PHP.

Ambito di validità delle variabili

Esistono diversi ambiti di validità (scope) di una variabile:
  • locale (la variabile è visibile solo nella funzione in cui è definita)
  • globale (la variabile è definita fuori dalla funzione, ma è specificatamente richiamata)
  • superglobale (la variabile è accessibile ovunque senza bisogno di specificazioni
A differenza di altri linguaggi:
  1. le variabili globali non sono visibili, in assenza di specificazione, all'interno di una funzione (come invece succede, ad esempio, in Pascal);
  2. non esiste uno scope per un blocco (come invece succede, ad esempio, in C).

Si consideri il seguente frammento di codice:

ini_set('error_reporting', E_ALL);
function foo()
{
  echo $k;
}
$k=1;
foo();

Quello che si ottiene è:
Notice:  Undefined variable: k in ... on line ...
Se si deve usare la variabile globale all'interno della funzione (anche se non è una buona pratica), ci sono due possibilità.

La prima è di dichiararla esplicitamente come globale:

function foo()
{
  global $k;
  echo $k;
}
$k=1;
foo();

La seconda è di usare l'array globale $GLOBALS:

function foo()
{
  echo $GLOBALS['k'];
}
$k=1;
foo();

Le variabili superglobali

Alcuni array speciali mettono a disposizione di tutte le funzioni valori specifici collegati all'ambiente di esecuzione ($_ENV), ai valori inviati dal browser ($_GET, $_POST, ecc.). In linea di massima, è bene evitare di accedere direttamente a queste variabili e utilizzare invece delle classi che si occupano di fornire i dati in forma "controllata".

Ad esempio, si consideri di usare un codice simile a questo:

class WebRequest
{
  public function getParameter($name, $default=null)
  {
    if (array_key_exists($name, $_GET))
    {
      return htmlentities($_GET[$name]);
      // eventualmente qui si possono aggiungere altre sostituzioni...
    }
    else
    {
      return $default;
    }
  }
}

$request = new WebRequest();
echo 'con pulizia: ' . $request->getParameter('bar') . "\n";
echo 'senza pulizia: ' . $_GET['bar'] . "\n";

Richiamando il codice con una query string di questo tipo:

?bar=5>3

si otterrà:

con pulizia: 5>3
senza pulizia: 5>3

con evidenti vantaggi in termini di sicurezza (e con il bonus di poter specificare dei valori di default).

Nota storica: in vecchie versioni di PHP (precedenti alla versione 4.2.0), l'impostazione predefinita (register_globals=on) faceva sì che venissero automaticamente create delle variabili con il nome del parametro ($bar nell'esempio). Questa impostazione è deprecata per motivi di sicurezza, ma è bene conoscerla per il caso in cui ci si debba cimentare nella manutenzione/sostituzione di vecchio software.

Variabili statiche

Una funzione può contenere variabili statiche:

function baz()
{
  static $number;
  $number++;
  return 'foo ' . $number . "\n";
}
echo baz();
echo baz();
echo baz();

produce
foo 1
foo 2
foo 3

Variabili di variabili

Una variabile può contenere il nome di un'altra variabile:

$name="Mario";
$var='name';
echo $$var . "\n"; 
produce

Mario

Nota: il meccanismo funziona anche con diversi livelli di indirezione.

La funzione eval()

Con la funzione eval() si possono eseguire istruzioni costruite al volo:

$expression='$a=5+3;';
eval($expression);
echo $a . "\n";

Attenzione: è bene non abusare di queste cose, che minano la sicurezza del codice e ne mettono a rischio la portabilità. «Se eval() è la risposta, vuol dire che quasi certamente hai posto la domanda sbagliata.» (attribuita a Rasmus Lerdorf)

Nessun commento:

Posta un commento