Referencia:Qué es el alcance de las variables,qué variables son accesibles desde dónde y qué son los errores de las "variables no definidas".

php scope


Nota:Esta es una pregunta de referencia para tratar con el alcance variable en PHP.Por favor,cierre cualquiera de las muchas preguntas que encajan en este patrón como un duplicado de ésta.

¿Qué es el "alcance variable" en PHP? ¿Son accesibles las variables de un archivo .php en otro? ¿Por qué a veces obtengo errores de "variable indefinida" ?




Answer 1 deceze


¿Qué es el "alcance variable"?

Las variables tienen un "alcance" o "lugares desde los cuales son accesibles". Solo porque escribiste $foo = 'bar'; una vez en algún lugar de su aplicación no significa que puede consultar $foo desde cualquier otro lugar dentro de la aplicación. La variable $foo tiene un cierto alcance dentro del cual es válida y solo el código en el mismo alcance tiene acceso a la variable.

¿Cómo se define un alcance en PHP?

Muy simple: PHP tiene alcance de función . Ese es el único tipo de separador de alcance que existe en PHP. Las variables dentro de una función solo están disponibles dentro de esa función. Las variables fuera de las funciones están disponibles en cualquier lugar fuera de las funciones, pero no dentro de ninguna función. Esto significa que hay un alcance especial en PHP: el alcance global . Cualquier variable declarada fuera de cualquier función está dentro de este alcance global.

Example:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$foo está en el ámbito global , $baz está en un ámbito local dentro de myFunc . Solo el código dentro de myFunc tiene acceso a $baz . Solo el código fuera de myFunc tiene acceso a $foo . Ninguno tiene acceso al otro:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

Alcance y archivos incluidos

Los límites del archivo no separan el alcance:

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

Las mismas reglas se aplican para include código d que se aplica a cualquier otro código: solo el alcance separado de la function . Para fines de alcance, puede pensar en incluir archivos como copiar y pegar código:

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

En el ejemplo anterior, a.php se incluyó dentro de myFunc , cualquier variable dentro de a.php solo tiene un alcance de función local. El hecho de que parezcan estar en el ámbito global en a.php no significa necesariamente que lo estén, sino que depende del contexto en el que se incluye / ejecuta ese código.

¿Qué hay de las funciones dentro de las funciones y clases?

Cada nueva declaración de function introduce un nuevo alcance, es así de simple.

Funciones (anónimas)dentro de las funciones

function foo() {
    $foo = 'bar';

    $bar = function () {
        // no access to $foo
        $baz = 'baz';
    };

    // no access to $baz
}

classes

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

¿Para qué sirve el alcance?

Tratar los problemas de alcance puede parecer molesto, ¡pero el alcance variable limitado es esencial para escribir aplicaciones complejas! Si cada variable que declara estaría disponible desde cualquier otro lugar dentro de su aplicación, estaría pasando por encima de sus variables sin una forma real de rastrear qué cambia qué. Solo hay tantos nombres razonables que puede dar a sus variables, probablemente quiera usar la variable " $name " en más de un lugar. Si solo pudiera tener este nombre de variable único una vez en su aplicación, tendría que recurrir a esquemas de nombres realmente complicados para asegurarse de que sus variables sean únicas y que no esté cambiando la variable incorrecta del código incorrecto.

Observe:

function foo() {
    echo $bar;
}

Si no hubiera alcance, ¿qué haría la función anterior? ¿De dónde viene $bar ? ¿Qué estado tiene? ¿Es incluso inicializado? ¿Tienes que revisar cada vez? Esto no es mantenible. Lo que nos lleva a ...

Cruzando los límites del alcance

La forma correcta:pasando variables dentro y fuera

function foo($bar) {
    echo $bar;
    return 42;
}

La variable $bar entra explícitamente en este ámbito como argumento de función. Simplemente mirando esta función queda claro de dónde se originan los valores con los que trabaja. Luego, devuelve explícitamente un valor. La persona que llama tiene la confianza de saber con qué variables trabajará la función y de dónde provienen sus valores de retorno:

$baz   = 'baz';
$blarg = foo($baz);

Extendiendo el alcance de las variables a funciones anónimas

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

La función anónima incluye explícitamente $foo de su alcance circundante. Tenga en cuenta que esto no es lo mismo que el alcance global .

El camino equivocado: global

Como ya se ha dicho,el ámbito global es algo especial,y las funciones pueden importar explícitamente variables de él:

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

Esta función usa y modifica la variable global $foo . ¡No hagas esto! (A menos que realmente realmente sepas lo que estás haciendo, e incluso entonces: ¡no!)

Todo lo que ve el que llama a esta función es esto:

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

No hay indicios de que esta función tenga ningún efecto secundario , pero lo tiene. Esto se convierte fácilmente en un lío enredado ya que algunas funciones se siguen modificando y requieren un estado global. Desea que las funciones no tengan estado , que actúen solo en sus entradas y que devuelvan salidas definidas, por muchas veces que las llame.

Se debe evitar en lo posible utilizar el ámbito global;ciertamente no se debe "sacar" las variables del ámbito global para pasarlas a un ámbito local.




Answer 2 Alex Myznikov


Aunque no se puede acceder a las variables definidas dentro del alcance de una función desde el exterior, eso no significa que no pueda usar sus valores después de que esa función se complete. PHP tiene una palabra clave static bien conocida que se usa ampliamente en PHP orientado a objetos para definir métodos y propiedades estáticos, pero uno debe tener en cuenta que static también se puede usar dentro de las funciones para definir variables estáticas.

¿Qué es 'variable estática'?

La variable estática difiere de la variable ordinaria definida en el ámbito de la función en caso de que no pierda valor cuando la ejecución del programa salga de este ámbito.Consideremos el siguiente ejemplo de utilización de variables estáticas:

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

Result:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

Si hubiéramos definido $counter sin static , cada vez que el valor reflejado sería el mismo que el parámetro $num pasado a la función. El uso de static permite construir este simple contador sin una solución adicional.

Casos de uso de variables estáticas

  1. Para almacenar valores entre las llamadas consecutivas a la función.
  2. Para almacenar valores entre llamadas recursivas cuando no hay manera (o no hay propósito)de pasarlos como parámetros.
  3. Para guardar el valor que normalmente es mejor recuperar una vez.Por ejemplo,el resultado de leer un archivo inmutable en el servidor.

Tricks

La variable estática sólo existe en el ámbito de una función local.No se puede acceder a ella fuera de la función en la que ha sido definida.Así que puede estar seguro de que mantendrá su valor sin cambios hasta la próxima llamada a esa función.

La variable estática sólo puede definirse como un escalar o como una expresión escalar (desde PHP 5.6).Asignarle otros valores conduce inevitablemente a un fracaso,al menos en el momento de escribir este artículo.Sin embargo,es posible hacerlo sólo en la siguiente línea de su código:

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

Result:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

La función estática es algo "compartido" entre los métodos de los objetos de la misma clase.Es fácil de entender viendo el siguiente ejemplo:

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

Esto sólo funciona con objetos de la misma clase.Si los objetos son de diferentes clases (incluso extendiéndose unos a otros)el comportamiento de los vars estáticos será el esperado.

¿Es la variable estática la única forma de mantener valores entre llamadas a una función?

Otra forma de mantener los valores entre las llamadas a funciones es usar cierres.Los cierres fueron introducidos en PHP 5.3.En dos palabras,permiten limitar el acceso a algún conjunto de variables dentro del ámbito de una función a otra función anónima que será la única forma de acceder a ellas.Estando en cierre las variables pueden imitar (con más o menos éxito)conceptos OOP como 'constantes de clase' (si fueron pasadas en cierre por valor)o 'propiedades privadas' (si fueron pasadas por referencia)en programación estructurada.

Este último permite en realidad utilizar cierres en lugar de variables estáticas.Lo que se utilice siempre depende del desarrollador,pero cabe mencionar que las variables estáticas son definitivamente útiles cuando se trabaja con recursividad y merecen ser notadas por los desarrolladores.




Answer 3 miken32


No publicaré una respuesta completa a la pregunta, ya que las existentes y el manual de PHP hacen un gran trabajo al explicar la mayor parte de esto.

Pero un tema que se perdió fue el de las superglobales , incluidos los comúnmente utilizados $_POST , $_GET , $_SESSION , etc. Estas variables son matrices que siempre están disponibles, en cualquier ámbito, sin una declaración global .

Por ejemplo,esta función imprimirá el nombre del usuario que ejecuta el script PHP.La variable está disponible para la función sin ningún problema.

<?php
function test() {
    echo $_ENV["user"];
}

La regla general de "los globos son malos" es típicamente enmendada en PHP a "los globos son malos pero los superglobos están bien",siempre y cuando no se haga un mal uso de ellos.(Todas estas variables son escribibles,así que podrían ser usadas para evitar la inyección de dependencia si fueras realmente terrible.)

No se garantiza que estas variables estén presentes; un administrador puede deshabilitar algunos o todos ellos utilizando la directiva variables_order en php.ini , pero este no es un comportamiento común.


Una lista de los superglobales actuales:

  • $GLOBALS : todas las variables globales en el script actual
  • $_SERVER - Información sobre el servidor y el entorno de ejecución
  • $_GET : valores pasados ​​en la cadena de consulta de la URL, independientemente del método HTTP utilizado para la solicitud
  • $_POST : valores pasados ​​en una solicitud HTTP POST con los tipos MIME application/x-www-form-urlencoded o multipart/form-data
  • $_FILES : archivos pasados ​​en una solicitud HTTP POST con un tipo MIME multipart/form-data
  • $_COOKIE - Cookies pasadas con la solicitud actual
  • $_SESSION - Variables de sesión almacenadas internamente por PHP
  • $_REQUEST : por lo general, una combinación de $_GET y $_POST , pero a veces $_COOKIES . El contenido está determinado por la directiva request_order en php.ini .
  • $_ENV : las variables de entorno del script actual