2010-02-23 11 views
5

Me he encontrado con un comportamiento inesperado con variables estáticas definidas dentro de los métodos de objetos que se comparten entre instancias. Este es probablemente un comportamiento conocido, pero cuando navego por la documentación de PHP no puedo encontrar instancias de variables estáticamente definidas dentro de los métodos de objetos.Estático dentro del método no estático se comparte entre las instancias

Aquí es una reducción del comportamiento que he encontrado:

<?php 

class Foo { 
    public function dofoo() { 
    static $i = 0; 
    echo $i++ . '<br>'; 
    } 
} 

$f = new Foo; 
$g = new Foo; 

$f->dofoo(); // expected 0, got 0 
$f->dofoo(); // expected 1, got 1 
$f->dofoo(); // expected 2, got 2 

$g->dofoo(); // expected 0, got 3 
$g->dofoo(); // expected 1, got 4 
$g->dofoo(); // expected 2, got 5 

Ahora, lo que habría esperado $i ser estática por ejemplo, pero en realidad $i es compartida entre las instancias. Para mi propia edificación, ¿podría alguien explicar por qué este es el caso y dónde está documentado en php.net?

Respuesta

6

Este es el very definition de estática.

Si desea que los miembros sean específicas a una instancia de un objeto, a continuación, utiliza class properties

por ejemplo,

<?php 

class Foo 
{ 
    protected $_count = 0; 
    public function doFoo() 
    { 
     echo $this->_count++, '<br>'; 
    } 
} 

Editar: Ok, he vinculado la documentación de las propiedades estáticas de POO. El concepto es el mismo sin embargo. Si usted lee los documentos variable scope verá:

Nota: declaraciones estáticas se resuelven en tiempo de compilación.

Por lo tanto, cuando se compila su secuencia de comandos (antes de que se ejecute), la estática es "configurar" (no estoy seguro de qué término usar). No importa cuántos objetos instancia, cuando esa función está "construida", la variable estática hace referencia a la misma copia que todos los demás.

+0

Esa documentación es para propiedades y métodos de clases estáticas, no variables estáticas dentro de un método. –

+0

Adam: En PHP5 son uno y lo mismo. Static es estático. – hobodave

+0

En mi opinión, '$ f-> dofoo()' no es el mismo método que '$ g-> dofoo()'. Obviamente, los desarrolladores de PHP no son de la misma opinión. :) –

1

Eso es lo que es estático, es la misma variable en todas las instancias de la clase.

Quiere escribir esto para que la variable sea un miembro privado de la instancia de la clase.

class Foo { 
    private $i = 0; 
    public function dofoo() { 
    echo $this->i++ . '<br>'; 
    } 
} 
1

La palabra clave estática puede utilizarse with variables, o usarse with class methods and properties. Las variables estáticas se introdujeron en PHP 4 (creo que podría haber sido anterior). clase miembros/métodos estáticos se introdujeron en PHP 5.

Así, según el manual, una variable estática

Otra característica importante del ámbito de las variables es el variable estática. Una variable estática existe solo en un ámbito de función local , pero no pierde su valor cuando la ejecución del programa deja este ámbito.

Esto es consistente con el comportamiento que describió. Si desea una variable por instancia, use un miembro de clase regular.

2

Acepto que la documentación actual de PHP no es lo suficientemente clara sobre exactamente lo que significa "alcance" para una variable estática dentro de un método no estático.

Por supuesto, es verdad (como hobodave indica) que "estáticos" generalmente significa "por clase", pero las propiedades de clase estática son no variables de exactamente el mismo que estática dentro de un método (no estática), en que los últimos son "delimitados" por método (cada método en una clase puede tener su propia variable $ foo estática, pero puede haber como máximo un miembro de clase estática llamado $ foo).

Y yo diría que, si bien el comportamiento de PHP 5 es consistente ("estática" siempre significa "una instancia compartida por clase"), es no la única manera de que pudiera PHP se comportan.

Por ejemplo, la mayoría de las personas usan variables de función estática para persistir en las llamadas a funciones, y para las funciones globales el comportamiento de PHP es exactamente lo que todos esperarían. Por lo tanto, es posible imaginar un intérprete PHP que mantenga el estado de ciertas variables de método a través de la invocación de métodos y lo haga "por instancia", y eso es lo que esperaba que ocurriera la primera vez que declare que una variable de método local es estática. .

0

Ups 7 años es mucho tiempo, pero de todos modos aquí va.

Todas las clases tienen un constructor predeterminado ¿por qué estoy diciendo esto?!? Porque si defines un comportamiento predeterminado en el constructor, cada instancia de la clase se verá afectada.

Ejemplo:

namespace Statics; 

class Foo 
{ 
    protected static $_count; 

    public function Bar() 
    { 
     return self::$_count++; 
    } 

    public function __construct() 
    { 
     self::$_count = 0; 
    } 
} 

El resultado es:

require 'Foo.php'; 

use Statics\Foo; 

$bar = new Foo(); 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 

$barcode = new Foo(); 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 

0 
1 
2 
0 
1 
2 

Cada nueva instancia de la clase alta se iniciará desde 0! El comportamiento de conteo estático NO se compartirá entre las múltiples instancias ya que comenzará a partir del valor asignado en el constructor.

Si necesita compartir datos en varias instancias, todo lo que necesita hacer es definir una variable estática y asignar datos predeterminados fuera del constructor.

Ejemplo:

namespace Statics; 

class Foo 
{ 
    //default value 
    protected static $_count = 0; 

    public function Bar() 
    { 
     return self::$_count++; 
    } 

    public function __construct() 
    { 
     //do something else 
    } 
} 

Resultando en:

require 'Foo.php'; 

use Statics\Foo; 

$bar = new Foo(); 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 

$barcode = new Foo(); 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 

0 
1 
2 
3 
4 
5 

Como se puede ver los resultados son completamente diferentes, la asignación de espacio de memoria es la misma en entre instancias de la clase pero puede producir resultados diferentes según cómo defines el valor predeterminado.

Espero que haya sido útil, no porque las respuestas anteriores sean incorrectas, pero creo que es importante entender el concepto desde este ángulo.

Saludos, desde Portugal!

Cuestiones relacionadas