PHP é minha primeira linguagem de programação. Não consigo entender quando usar classes estáticas versus objetos instanciados.
Sei que você pode duplicar e clonar objetos. No entanto, em todo o meu tempo usando php, qualquer objeto ou função sempre terminava como um único retorno (array, string, int) ou nulo.
Entendo conceitos em livros como uma aula de personagem de videogame. duplicar objeto de carro e deixar o novo vermelho , tudo faz sentido, mas o que não faz é a sua aplicação em aplicativos php e web.
Um exemplo simples. Um blog. Quais objetos de um blog seriam melhor implementados como objetos estáticos ou instanciados? A classe DB? Por que não instanciar o objeto db no escopo global? Por que não tornar cada objeto estático? E o desempenho?
É tudo apenas estilo? Existe uma maneira adequada de fazer isso?
Os dois principais motivos contra o uso de métodos estáticos são:
Ter uma chamada de método estático dentro de outro método é realmente pior do que importar uma variável global. No PHP, as classes são símbolos globais; portanto, toda vez que você chama um método estático, depende de um símbolo global (o nome da classe). Este é um caso em que global é mau. Eu tive problemas com esse tipo de abordagem com algum componente do Zend Framework. Existem classes que usam chamadas de método estático (fábricas) para construir objetos. Era impossível fornecer outra fábrica para essa instância para obter um objeto personalizado retornado. A solução para esse problema é usar apenas instâncias e instalar métodos e aplicar singletons e similares no início do programa.
Miško Hevery , que trabalha como treinador ágil no Google, tem uma teoria interessante, ou melhor, aconselha que devemos separar o tempo de criação do objeto do momento em que o usamos. Portanto, o ciclo de vida de um programa é dividido em dois. A primeira parte (
main()
digamos o método), que cuida de toda a fiação do objeto em seu aplicativo e da parte que faz o trabalho real.Então, ao invés de ter:
Devemos fazer:
E então, na página principal / índice, faríamos (esta é a etapa de fiação do objeto ou o tempo para criar o gráfico de instâncias a serem usadas pelo programa):
A idéia principal é separar as dependências de suas classes. Dessa forma, o código é muito mais extensível e, a parte mais importante para mim, testável. Por que é mais importante ser testável? Como nem sempre escrevo o código da biblioteca, a extensibilidade não é tão importante, mas a testabilidade é importante quando refatoro. De qualquer forma, o código testável geralmente gera código extensível, portanto, não é realmente uma situação do tipo "ou-ou".
Miško Hevery também faz uma distinção clara entre singletons e singletons (com ou sem S maiúsculo). A diferença é muito simples. Singletons com minúsculas "s" são aplicados pela fiação no índice / principal. Você instancia um objeto de uma classe que não implementa o padrão Singleton e cuida para que somente passe essa instância para qualquer outra instância que precise. Por outro lado, Singleton, com letra maiúscula "S", é uma implementação do padrão clássico (anti). Basicamente um disfarçado global que não tem muito uso no mundo PHP. Eu não vi um até este ponto. Se você deseja que uma única conexão de banco de dados seja usada por todas as suas classes, é melhor fazê-lo assim:
Ao fazer o exposto, fica claro que temos um singleton e também temos uma boa maneira de injetar um mock ou um stub em nossos testes. É surpreendente como os testes de unidade levam a um design melhor. Mas faz muito sentido quando você pensa que os testes o forçam a pensar na maneira como você usaria esse código.
A única situação em que eu usaria (e os usei para imitar o objeto de protótipo JavaScript no PHP 5.3) membros estáticos é quando eu sei que o respectivo campo terá o mesmo valor entre instâncias. Nesse ponto, você pode usar uma propriedade estática e talvez um par de métodos estáticos getter / setter. De qualquer forma, não se esqueça de adicionar a possibilidade de substituir o membro estático por um membro da instância. Por exemplo, o Zend Framework estava usando uma propriedade estática para especificar o nome da classe do adaptador DB usada nas instâncias de
Zend_Db_Table
. Faz algum tempo desde que eu os usei, para que não seja mais relevante, mas é assim que me lembro.Métodos estáticos que não lidam com propriedades estáticas devem ser funções. PHP tem funções e devemos usá-las.
fonte
Assim, no PHP estático pode ser aplicado a funções ou variáveis. Variáveis não estáticas estão vinculadas a uma instância específica de uma classe. Métodos não estáticos agem em uma instância de uma classe. Então, vamos criar uma classe chamada
BlogPost
.title
seria um membro não estático. Ele contém o título dessa postagem no blog. Também podemos ter um método chamadofind_related()
. Não é estático porque requer informações de uma instância específica da classe de postagem do blog.Essa classe seria algo parecido com isto:
Por outro lado, usando funções estáticas, você pode escrever uma classe como esta:
Nesse caso, como a função é estática e não está atuando em nenhuma postagem do blog em particular, você deve transmiti-la como argumento.
Fundamentalmente, essa é uma pergunta sobre design orientado a objetos. Suas classes são os substantivos em seu sistema, e as funções que atuam sobre eles são os verbos. As funções estáticas são procedurais. Você passa o objeto das funções como argumentos.
Atualização: eu também acrescentaria que a decisão raramente ocorre entre métodos de instância e métodos estáticos e mais entre o uso de classes e o uso de matrizes associativas. Por exemplo, em um aplicativo de blog, você lê postagens de blog do banco de dados e as converte em objetos ou as deixa no conjunto de resultados e as trata como matrizes associativas. Em seguida, você escreve funções que usam matrizes associativas ou listas de matrizes associativas como argumentos.
No cenário OO, você escreve métodos em sua
BlogPost
classe que atuam em postagens individuais e métodos estáticos que atuam em coleções de postagens.fonte
Um longo caminho, sim. Você pode escrever programas perfeitamente orientados a objetos sem usar membros estáticos. De fato, algumas pessoas argumentam que os membros estáticos são uma impureza em primeiro lugar. Eu sugeriria que - como iniciante no oop - você tente evitar membros estáticos todos juntos. Isso o forçará a escrever em um estilo orientado a objetos e não a procedimentos .
fonte
Eu tenho uma abordagem diferente para a maioria das respostas aqui, especialmente ao usar PHP. Eu acho que todas as classes devem ser estáticas, a menos que você tenha um bom motivo. Alguns dos motivos "por que não" são:
Deixe-me dar um exemplo. Como todo script PHP produz código HTML, minha estrutura possui uma classe de gravador html. Isso garante que nenhuma outra classe tente escrever HTML, pois é uma tarefa especializada que deve ser concentrada em uma única classe.
Normalmente, você usaria a classe html assim:
Toda vez que get_buffer () é chamado, ele redefine tudo para que a próxima classe a usar o gravador html inicie em um estado conhecido.
Todas as minhas classes estáticas têm uma função init () que precisa ser chamada antes que a classe seja usada pela primeira vez. Isso é mais por convenção do que uma necessidade.
A alternativa para uma classe estática nesse caso é confusa. Você não gostaria que todas as classes que precisam escrever um pouquinho de html tivessem que gerenciar uma instância do gravador de html.
Agora vou dar um exemplo de quando não usar classes estáticas. Minha classe de formulário gerencia uma lista de elementos de formulário, como entradas de texto, listas suspensas e muito mais. É normalmente usado assim:
Não há como você fazer isso com classes estáticas, especialmente considerando que alguns dos construtores de cada classe adicionada fazem muito trabalho. Além disso, a cadeia de herança de todos os elementos é bastante complexa. Portanto, este é um exemplo claro de onde classes estáticas não devem ser usadas.
A maioria das classes de utilitários, como as que convertem / formatam strings, são boas candidatas por serem uma classe estática. Minha regra é simples: tudo fica estático no PHP, a menos que haja uma razão para isso não acontecer.
fonte
"Ter uma chamada de método estático dentro de outro método é realmente pior do que importar uma variável global". (defina "pior") ... e "Métodos estáticos que não lidam com propriedades estáticas devem ser funções".
Essas são duas declarações bastante amplas. Se eu tiver um conjunto de funções relacionadas ao assunto, mas os dados da instância forem totalmente inapropriados, prefiro defini-los em uma classe e não cada um no espaço de nomes global. Estou apenas usando a mecânica disponível no PHP5 para
é apenas uma maneira conveniente de impor maior coesão e menor acoplamento.
E FWIW - não existe, pelo menos no PHP5, como "classes estáticas"; métodos e propriedades podem ser estáticos. Para impedir a instanciação da classe, pode-se declarar abstrata também.
fonte
Primeiro pergunte a si mesmo: o que esse objeto vai representar? Uma instância de objeto é boa para operar em conjuntos separados de dados dinâmicos.
Um bom exemplo seria o ORM ou a camada de abstração do banco de dados. Você pode ter várias conexões com o banco de dados.
Agora essas duas conexões podem operar independentemente:
Agora, dentro deste pacote / biblioteca, pode haver outras classes, como Db_Row, etc. para representar uma linha específica retornada de uma instrução SELECT. Se essa classe Db_Row fosse uma classe estática, isso supõe que você tenha apenas uma linha de dados em um banco de dados e seria impossível fazer o que uma instância de objeto poderia. Com uma instância, agora você pode ter um número ilimitado de linhas em um número ilimitado de tabelas em um número ilimitado de bancos de dados. O único limite é o hardware do servidor;).
Por exemplo, se o método getRows no objeto Db retornar uma matriz de objetos Db_Row, agora você poderá operar em cada linha independentemente uma da outra:
Um bom exemplo de uma classe estática seria algo que lida com variáveis de registro ou variáveis de sessão, pois haverá apenas um registro ou uma sessão por usuário.
Em uma parte do seu aplicativo:
E em outra parte:
Como sempre haverá um usuário por vez por sessão, não há sentido em criar uma instância para a Sessão.
Espero que isso ajude, juntamente com as outras respostas para ajudar a esclarecer as coisas. Como nota lateral, consulte " coesão " e " acoplamento ". Eles descrevem algumas práticas muito, muito boas para usar ao escrever seu código que se aplica a todas as linguagens de programação.
fonte
Se sua classe é estática, isso significa que você não pode passar seu objeto para outras classes (já que não há instância possível). Isso significa que todas as suas classes usarão diretamente essa classe estática, o que significa que seu código agora está fortemente associado à classe .
Um acoplamento rígido torna seu código menos reutilizável, frágil e propenso a erros. Você deseja evitar classes estáticas para poder passar a instância da classe para outras classes.
E sim, essa é apenas uma das muitas outras razões, algumas das quais já foram mencionadas.
fonte
Em geral, você deve usar variáveis de membro e funções de membro, a menos que seja absolutamente necessário compartilhar entre todas as instâncias ou a menos que você esteja criando um singleton. O uso de dados e funções de membro permite reutilizar suas funções para várias partes de dados diferentes, enquanto você só pode ter uma cópia dos dados nos quais opera se usar dados e funções estáticas. Além disso, embora não seja aplicável ao PHP, funções e dados estáticos fazem com que o código não seja reentrante, enquanto os dados da classe facilitam a reentrada.
fonte
Eu gostaria de dizer que há definitivamente um caso em que eu gostaria de variáveis estáticas - em aplicativos em vários idiomas. Você pode ter uma classe para a qual passa uma linguagem (por exemplo, $ _SESSION ['language']) e, por sua vez, acessa outras classes projetadas da seguinte forma:
O uso de Strings :: getString ("somestring") é uma boa maneira de abstrair o uso do idioma do seu aplicativo. Você poderia fazê-lo como quisesse, mas nesse caso, cada arquivo de strings possui constantes com valores de strings acessados pela classe Strings, que funcionam muito bem.
fonte