Qual é a diferença entre self :: $ bar e static :: $ bar em PHP?

125

Qual é a diferença entre usar selfe staticno exemplo abaixo?

class Foo
{
    protected static $bar = 1234;

    public static function instance()
    {
        echo self::$bar;
        echo "\n";
        echo static::$bar;
    }

}

Foo::instance();

produz

1234
1234
cwd
fonte
2
@deceze: Essa é uma pergunta semelhante, mas não é uma duplicata. Este pergunta sobre como usar as palavras-chave com propriedades, enquanto aquele pergunta sobre como usá-las com construtores.
BoltClock

Respostas:

191

Quando você usa selfpara se referir a um membro da classe, está se referindo à classe na qual usa a palavra-chave. Nesse caso, sua Fooclasse define uma propriedade estática protegida chamada $bar. Quando você usa selfna Fooclasse para se referir à propriedade, está fazendo referência à mesma classe.

Portanto, se você tentou usar self::$barem outro lugar em sua Fooclasse, mas tinha uma Barclasse com um valor diferente para a propriedade, ela usaria em Foo::$barvez de Bar::$bar, o que pode não ser o que você pretende:

class Foo
{
    protected static $bar = 1234;
}

class Bar extends Foo
{
    protected static $bar = 4321;
}

Quando você chama um método via static, está invocando um recurso chamado late bindings estáticos (introduzido no PHP 5.3).

No cenário acima, usar selfresultará em Foo::$bar(1234). E usar staticresultará em Bar::$bar(4321) porque com static, o interpretador leva em consideração a redeclaração dentro da Barclasse durante o tempo de execução.

Normalmente, você usa vinculações estáticas tardias para métodos ou até mesmo para a própria classe, em vez de propriedades, visto que não costuma redeclarar propriedades em subclasses; um exemplo de uso da staticpalavra - chave para invocar um construtor de ligação tardia pode ser encontrado nesta questão relacionada: Novo self vs. novo estático

No entanto, isso não impede o uso staticcom propriedades também.

BoltClock
fonte
Você pode facilmente declarar novamente na classe filha, a classe pai pode ser um valor padrão que a classe filha usa, a menos que seja declarada novamente. Se você estiver na classe pai, acho que é seguro usar self ::, e se estiver em uma classe filha, você poderia inventar um argumento para usar qualquer um, mas self :: também funcionará se você não esperar re-declarar sempre.
Andrew
3
acesse phpfiddle.org e execute isto<?php class Foo { public static $bar = 1234; public static function a( ) { echo 'static'.static::$bar; echo 'self'.self::$bar; } } class Bar extends Foo { public static $bar = 4321; } (new Bar())->a(); ?>
Yevgeniy Afanasyev
2
A redação dos dois primeiros parágrafos é confusa, tem um pronome ambíguo, "isso", e também é redundante, já que parágrafos posteriores explicam as mesmas informações de forma mais clara. Sugiro substituir os dois primeiros parágrafos pelo parágrafo posterior que começa com "No cenário acima" no início. Dessa forma, a linha de fundo, a resposta direta está no topo. É claro e fácil de seguir.
ahnbizcad
Outra maneira de pensar sobre isso:, self::$abcquando usado por dentro class Fooé o mesmo que dizer Foo::$abc. Não será afetado por nenhuma nova declaração de $abcem uma subclasse. AFAIK, a única razão para usar selfé como abreviação, para evitar o uso do nome da classe Foo, que pode ser mais longo. [Isso também significa que você pode mudar o nome da classe sem mudar todos aqueles lugares - mas isso não é muito motivo, IMHO.] (A escolha de nomes do PHP é lamentável e parece ao contrário; "estático" é o que pode mudar - que é o oposto do significado coloquial da palavra de linguagem natural "estático".)
ToolmakerSteve
4

Conforme mencionado, uma das principais diferenças é que staticpermite ligações estáticas atrasadas. Um dos cenários mais úteis que encontrei foi para a criação de classes base para classes singleton:

class A { // Base Class
    protected static $name = '';
    protected static function getName() {
        return static::$name;
    }
}
class B extends A {
    protected static $name = 'MyCustomNameB';
}
class C extends A {
    protected static $name = 'MyCustomNameC';
}

echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC

Usar return static::$namena classe Base retornará o que foi anexado estaticamente quando foi estendido. Se você fosse usar, return self::$nameentão B::getName()retornaria uma string vazia, pois é isso que é declarado na classe Base.

ggedde
fonte
0

Com selfchamada:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return self::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "123"
echo (new Bar)->getVar();

Você pode ver acima, embora tenhamos sobrescrito o $varcom nossa Barclasse, ele ainda retorna 123, porque pedimos explicitamente ao PHP pela selfvariável, que por sua vez pede Fooa variável s.

Agora, se trocarmos a chamada com static, obteremos, em vez disso, Baro valor substituído:

Com staticchamada:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return static::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "234"
echo (new Bar)->getVar();
Steve Bauman
fonte