É uma história longa e triste.
Quando o PHP 5.2 introduziu esse aviso pela primeira vez, ligações estáticas tardias ainda não estavam no idioma. Caso você não esteja familiarizado com ligações estáticas tardias, observe que códigos como este não funcionam da maneira que você pode esperar:
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
Deixando de lado o aviso de modo estrito, o código acima não funciona. A self::bar()
chamada in foo()
refere-se explicitamente ao bar()
método de ParentClass
, mesmo quando foo()
é chamado como método de ChildClass
. Se você tentar executar esse código com o modo estrito desativado, verá " Erro fatal do PHP: não é possível chamar o método abstrato ParentClass :: bar () ".
Dado isso, métodos estáticos abstratos no PHP 5.2 foram inúteis. O objetivo de usar um método abstrato é que você pode escrever um código que chame o método sem saber para qual implementação ele estará chamando - e, em seguida, fornecer implementações diferentes em diferentes classes filho. Mas como o PHP 5.2 não oferece uma maneira limpa de escrever um método de uma classe pai que chame um método estático da classe filho na qual é chamado, esse uso de métodos estáticos abstratos não é possível. Portanto, qualquer uso do abstract static
PHP 5.2 é um código incorreto, provavelmente inspirado por um mal-entendido de como a self
palavra - chave funciona. Era inteiramente razoável lançar um aviso sobre isso.
Mas, em seguida, surgiu o PHP 5.3, com a capacidade de se referir à classe na qual um método foi chamado através da static
palavra - chave (diferente da self
palavra - chave, que sempre se refere à classe na qual o método foi definido ). Se você mudar self::bar()
para static::bar()
no meu exemplo acima, ele funciona bem no PHP 5.3 e acima. Você pode ler mais sobre self
vs static
em Nova auto vs. nova estática .
Com a palavra-chave estática adicionada, o argumento claro para ter abstract static
emitido um aviso desapareceu. O principal objetivo das ligações estáticas tardias era permitir que os métodos definidos em uma classe pai chamassem métodos estáticos que seriam definidos nas classes filho; permitir métodos estáticos abstratos parece razoável e consistente, dada a existência de ligações estáticas tardias.
Acho que você ainda pode defender o aviso. Por exemplo, você poderia argumentar que, como o PHP permite chamar métodos estáticos de classes abstratas, no meu exemplo acima (mesmo depois de corrigi-lo substituindo self
por static
), você está expondo um método público ParentClass::foo()
que está quebrado e que realmente não deseja expor. Usar uma classe não estática - ou seja, tornar todos os métodos de instância de métodos e tornar filhos de ParentClass
todos singletons ou algo assim - resolveria esse problema, pois ParentClass
, sendo abstrato, não pode ser instanciado e, portanto, seus métodos de instância não podem ser chamado. Eu acho que esse argumento é fraco (porque eu acho que exporParentClass::foo()
não é grande coisa e usar singletons em vez de classes estáticas é muitas vezes desnecessariamente detalhado e feio), mas você pode discordar razoavelmente - é uma chamada um tanto subjetiva.
Então, com base nesse argumento, os desenvolvedores do PHP mantiveram o aviso na linguagem, certo?
Uh, não exatamente .
O relatório de bug 53081 do PHP, vinculado acima, pedia que o aviso fosse eliminado, pois a adição da static::foo()
construção havia tornado métodos estáticos abstratos razoáveis e úteis. Rasmus Lerdorf (criador do PHP) começa rotulando a solicitação como falsa e passa por uma longa cadeia de raciocínios ruins para tentar justificar o aviso. Então, finalmente, essa troca ocorre:
Giorgio
eu sei mas:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
Rasmus
Certo, é exatamente assim que deve funcionar.
Giorgio
mas não é permitido :(
Rasmus
O que não é permitido?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
Isso funciona bem. Você obviamente não pode chamar self :: B (), mas estático :: B () está bom.
A afirmação de Rasmus de que o código em seu exemplo "funciona bem" é falsa; como você sabe, lança um aviso de modo estrito. Eu acho que ele estava testando sem o modo estrito ativado. Independentemente disso, um Rasmus confuso deixou o pedido erroneamente fechado como "falso".
E é por isso que o aviso ainda está no idioma. Essa pode não ser uma explicação totalmente satisfatória - você provavelmente veio aqui esperando que houvesse uma justificativa racional para o aviso. Infelizmente, no mundo real, às vezes as escolhas nascem de erros mundanos e raciocínio ruim, e não de tomada de decisão racional. Este é simplesmente um daqueles momentos.
Felizmente, o estimado Nikita Popov removeu o aviso da linguagem no PHP 7 como parte do PHP RFC: Reclassifique os avisos E_STRICT . Por fim, a sanidade prevaleceu e, uma vez lançado o PHP 7, todos podemos usá-lo com alegria abstract static
sem receber esse aviso bobo.