Depois de ativar avisos estritos no PHP 5.2, vi uma carga de avisos estritos sobre padrões de um projeto que foi originalmente escrito sem avisos estritos:
Padrões estritos : Função estática Program :: getSelectSQL () não deve ser abstrato em Program.class.inc
A função em questão pertence a um programa de classe pai abstrato e é declarada estática abstrata porque deve ser implementada em suas classes filho, como TVProgram.
Encontrei referências a essa alteração aqui :
Funções de classe estática abstratas descartadas. Devido a uma supervisão, o PHP 5.0.xe 5.1.x permitiram funções estáticas abstratas nas classes. A partir do PHP 5.2.x, somente interfaces podem tê-los.
Minha pergunta é: alguém pode explicar de uma maneira clara por que não deveria haver uma função estática abstrata no PHP?
Respostas:
métodos estáticos pertencem à classe que os declarou. Ao estender a classe, você pode criar um método estático com o mesmo nome, mas na verdade não está implementando um método abstrato estático.
O mesmo vale para estender qualquer classe com métodos estáticos. Se você estender essa classe e criar um método estático da mesma assinatura, na verdade você não estará substituindo o método estático da superclasse
EDIT (16 de setembro de 2009)
Atualização sobre isso. Executando o PHP 5.3, vejo que a estática abstrata está de volta, para o bem ou para o mal. (consulte http://php.net/lsb para mais informações)
A CORREÇÃO (por philfreo)
abstract static
ainda não é permitida no PHP 5.3, o LSB é relacionado, mas diferente.fonte
abstract static
pode ser útil nesse caso.É 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:
Deixando de lado o aviso de modo estrito, o código acima não funciona. A
self::bar()
chamada infoo()
refere-se explicitamente aobar()
método deParentClass
, mesmo quandofoo()
é chamado como método deChildClass
. 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 aself
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 daself
palavra - chave, que sempre se refere à classe na qual o método foi definido ). Se você mudarself::bar()
parastatic::bar()
no meu exemplo acima, ele funciona bem no PHP 5.3 e acima. Você pode ler mais sobreself
vsstatic
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
porstatic
), você está expondo um método públicoParentClass::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 deParentClass
todos singletons ou algo assim - resolveria esse problema, poisParentClass
, 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: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.fonte
Existe uma solução muito simples para esse problema, que na verdade faz sentido do ponto de vista do design. Como Jonathan escreveu:
Portanto, como uma solução alternativa, você pode fazer o seguinte:
E agora você reforça que qualquer classe de subclasse MyFoo implementa um método estático getInstance e um método público getSomeData. E se você não subclassificar o MyFoo, ainda poderá implementar o iMyFoo para criar uma classe com funcionalidade semelhante.
fonte
static::
podem ser úteis.abstract static
métodos, sem PHP reclamando ....Eu sei que isso é velho, mas ....
Por que não lançar uma exceção no método estático da classe pai, dessa forma, se você não a substituir, a exceção será causada.
fonte
Eu argumentaria que uma classe / interface abstrata poderia ser vista como um contrato entre programadores. Ele lida mais com a aparência / comportamento das coisas e não implementa a funcionalidade real. Como visto no php5.0 e 5.1.x, não é uma lei natural que impede os desenvolvedores de php de fazê-lo, mas o desejo de acompanhar outros padrões de design de OO em outros idiomas. Basicamente, essas idéias tentam impedir comportamentos inesperados, se alguém já estiver familiarizado com outros idiomas.
fonte
Não vejo motivo para proibir funções abstratas estáticas. O melhor argumento de que não há razão para proibi-los é que eles sejam permitidos em Java. As perguntas são: - São tecnicamente viáveis? - Sim, já que existiam no PHP 5.2 e eles existem em Java. Então, nós PODEMOS fazê-lo. Devemos fazê-lo? - Eles fazem sentido? Sim. Faz sentido implementar uma parte de uma classe e deixar outra parte de uma classe para o usuário. Faz sentido em funções não estáticas, por que não deveria fazer sentido para funções estáticas? Um uso de funções estáticas são as classes em que não deve haver mais de uma instância (singletons). Por exemplo, um mecanismo de criptografia. Ele não precisa existir em várias instâncias e há razões para evitar isso - por exemplo, você precisa proteger apenas uma parte da memória contra invasores. Portanto, faz todo sentido implementar uma parte do mecanismo e deixar o algoritmo de criptografia para o usuário. Este é apenas um exemplo. Se você está acostumado a usar funções estáticas, encontrará muito mais.
fonte
No php 5.4+, use a característica:
e em sua classe, coloque no início:
fonte
abstract public static function get_table_name();
uma característica e usá-la na minha classe abstrata sem mais avisos E_STRICT! Isso ainda impunha a definição do método estático nas crianças, como eu esperava. Fantástico!Examine os problemas do PHP 'Late Static Binding'. Se você estiver colocando métodos estáticos em classes abstratas, provavelmente o encontrará mais cedo ou mais tarde. Faz sentido que os avisos estritos estejam dizendo para você evitar o uso de recursos de idioma corrompido.
fonte