Novo eu versus novo estático

513

Estou convertendo uma biblioteca PHP 5.3 para trabalhar no PHP 5.2. A principal coisa que está no meu caminho é o uso de ligação estática tardia como return new static($options);, se eu converter isso em para return new self($options)obter os mesmos resultados?

Qual é a diferença entre new selfe new static?

Mike
fonte

Respostas:

890

vou obter os mesmos resultados?

Na verdade não. Eu não sei de uma solução alternativa para o PHP 5.2, no entanto.

Qual é a diferença entre new selfe new static?

selfrefere-se à mesma classe em que a newpalavra-chave é realmente escrita.

static, nas ligações estáticas tardias do PHP 5.3, refere-se a qualquer classe na hierarquia em que você chamou o método.

No exemplo a seguir, Bherda os dois métodos de A. A selfinvocação está vinculada a, Aporque é definida na Aimplementação do primeiro método, enquanto staticestá vinculada à classe chamada (também consulte get_called_class()).

class A {
    public static function get_self() {
        return new self();
    }

    public static function get_static() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A
BoltClock
fonte
faz sentido. Eu acho que a melhor aposta é passar o nome da classe para a função que está usando a ligação estática tardia e, em seguida, retorne o novo $ className ($ options);
Mike
12
Você não precisa "passar" o nome da classe, pode sempre fazê-lo get_called_class(), o que é efetivamente o mesmo que __CLASS__, mas compatível com LSB.
shadowhand
7
get_called_class não existe no <PHP5.3. Portanto, se você deseja obter o nome da classe do objeto instanciado em PHP5.2 Esta função não ajuda ao tentar converter uma biblioteca de PHP 5.3 para PHP 5.2
txwikinger
2
A função chamada self: theFunction () se comporta como "Eu executarei no contexto da classe à qual pertenço fisicamente". e a função chamada static: theFunction () se comporta como "Eu executarei no contexto da classe que foi realmente chamada pelo mundo exterior". (Assumindo o cenário de herança). Obrigado
Shubhranshu 31/03/19
2
Na minha cabeça, apenas pego o que é intuitivo e oposto. Você pensaria que, com base na nomeação, selfretornaria a si próprio e staticretornaria algo que não pode ser substituído ... Mas eis que é o contrário. Eu nunca deixo de me impressionar com a nomeação, convenções e estilo geral do PHP. #
214190 #
23

Se o método desse código não for estático, você pode obter uma solução alternativa na 5.2 usando get_class($this).

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

Os resultados:

string(1) "B"
string(1) "B"
Marius Balčytis
fonte
17
Se o método não for estático, as ligações estáticas tardias se tornam totalmente irrelevantes.
BoltClock
1
Por exemplo, você pode usá-lo no método "copy", onde o objeto é copiado sem o uso clone, mas apenas recriando e configurando as propriedades. $copy = new static(); $copy->set($this->get()); return $copy;
Marius Balčytis
9
@BoltClock Certamente não? Se você estiver chamando um método estático substituído de dentro de um método de instância de uma subclasse, sua escolha self::ou static::afetará se a versão da classe base ou subclasse desse método estático é usada. Na ausência de algum motivo para pensar que tal situação ocorra indica inerentemente má prática (e não vejo nenhuma razão para que isso aconteça), a escolha entre self::e static::é tão relevante dentro de métodos não estáticos quanto em métodos estáticos. Eu entendi mal o seu comentário, ou alguém está simplesmente errado?
Mark Amery
4
@ Mark Amery: Hmm, eu não pensei nisso. Você está absolutamente correto. Eu assumi que nenhum método estático seria chamado no método de instância em questão, mas com base no seu exemplo, posso ver como isso seria uma suposição muito ingênua.
BoltClock
Ligações estáticas tardias doc => php.net/manual/en/language.oop5.late-static-bindings.php
DevWL 3/17
7

Além das respostas dos outros:

static :: será calculado usando informações de tempo de execução.

Isso significa que você não pode usar static::em uma propriedade de classe porque os valores das propriedades:

Deve poder ser avaliado em tempo de compilação e não deve depender das informações em tempo de execução.

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

Usando self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

Observe que o comentário do erro Fatal no código que eu fiz não indica onde o erro ocorreu, o erro aconteceu antes de o objeto ser instanciado como @Grapestain mencionado nos comentários

Chuva
fonte
4
Observe que o erro é gerado na linha 2 public $name = static::class;, não na linha 7, conforme sugerido pelo exemplo. O erro diz: "static :: class não pode ser usado para resolução de nomes de classes em tempo de compilação", o que indica que o problema não é onde você tenta acessar o campo $ name, mas muito antes, na compilação da classe PHP. A linha 7 (ou 6) não será alcançada no primeiro exemplo.
sbnc.eu
@Grapestain O comentário que fiz no exemplo foi mostrar o resultado final e não indicar onde realmente ocorreu o erro. Mas de qualquer forma obrigado por apontar isso.
Chuva
Certo, não pretendia criticar, apenas esclareço o que me confundiu primeiro, na esperança de que possa ajudar os outros. Exemplo útil de qualquer maneira!
sbnc.eu