Eu acesso meu banco de dados MySQL via DOP. Estou configurando o acesso ao banco de dados e minha primeira tentativa foi usar o seguinte:
A primeira coisa que pensei foi global
:
$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');
function some_function() {
global $db;
$db->query('...');
}
Isso é considerado uma má prática. Após uma pequena pesquisa, acabei com o padrão Singleton , que
"aplica-se a situações em que precisa haver uma única instância de uma classe."
De acordo com o exemplo no manual, devemos fazer o seguinte:
class Database {
private static $instance, $db;
private function __construct(){}
static function singleton() {
if(!isset(self::$instance))
self::$instance = new __CLASS__;
return self:$instance;
}
function get() {
if(!isset(self::$db))
self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')
return self::$db;
}
}
function some_function() {
$db = Database::singleton();
$db->get()->query('...');
}
some_function();
Por que preciso dessa classe relativamente grande quando posso fazer isso?
class Database {
private static $db;
private function __construct(){}
static function get() {
if(!isset(self::$db))
self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');
return self::$db;
}
}
function some_function() {
Database::get()->query('...');
}
some_function();
Este último funciona perfeitamente e não preciso me preocupar $db
mais.
Como posso criar uma classe singleton menor ou há um caso de uso para singletons que estou ausente no PHP?
php
oop
design-patterns
singleton
seriousdev
fonte
fonte
Respostas:
Ok, eu pensei sobre isso por um tempo quando comecei minha carreira. Implementou de maneiras diferentes e surgiu com duas razões para optar por não usar classes estáticas, mas elas são bem grandes.
Uma é que você encontrará com muita frequência algo que você tem certeza absoluta de que nunca terá mais de uma instância; eventualmente, terá uma segunda. Você pode acabar com um segundo monitor, um segundo banco de dados, um segundo servidor - qualquer que seja.
Quando isso acontece, se você tiver usado uma classe estática, terá um refatorado muito pior do que se tivesse usado um singleton. Um singleton é um padrão duvidoso por si só, mas converte-se facilmente em um padrão de fábrica inteligente - pode até ser convertido para usar injeção de dependência sem muitos problemas. Por exemplo, se seu singleton é obtido através de getInstance (), você pode facilmente mudar isso para getInstance (databaseName) e permitir vários bancos de dados - nenhuma outra alteração de código.
A segunda questão está sendo testada (e honestamente, é a mesma que a primeira). Às vezes, você deseja substituir seu banco de dados por um banco de dados simulado. Com efeito, esta é uma segunda instância do objeto de banco de dados. Isso é muito mais difícil com classes estáticas do que com um singleton, você só precisa zombar do método getInstance (), nem todos os métodos de uma classe estática (o que em alguns idiomas pode ser muito difícil).
Realmente se resume a hábitos - e quando as pessoas dizem que "Globals" são ruins, têm boas razões para dizê-lo, mas isso nem sempre é óbvio até que você resolva o problema.
A melhor coisa que você pode fazer é perguntar (como você fez), depois fazer uma escolha e observar as ramificações de sua decisão. Ter o conhecimento para interpretar a evolução do seu código ao longo do tempo é muito mais importante do que fazer certo em primeiro lugar.
fonte
getInstance(databaseName)
apenas espalhar referências a um repositório global de instâncias em todo o seu código? O código que chamariagetInstance
deve ter as instâncias injetadas nele pelo código do cliente e, portanto, não precisa chamargetInstance
em primeiro lugar.Singletons têm muito pouco uso - se não para dizer não - em PHP.
Nos idiomas em que os objetos vivem na memória compartilhada, os Singletons podem ser usados para manter baixo o uso da memória. Em vez de criar dois objetos, você faz referência a uma instância existente a partir da memória do aplicativo compartilhada globalmente. No PHP não existe tal memória de aplicativo. Um Singleton criado em uma solicitação vive exatamente para essa solicitação. Um Singleton criado em outra Solicitação feita ao mesmo tempo ainda é uma instância completamente diferente. Portanto, um dos dois principais objetivos de um Singleton não é aplicável aqui.
Além disso, muitos dos objetos que podem existir conceitualmente apenas uma vez no aplicativo não exigem necessariamente um mecanismo de linguagem para impor isso. Se você precisar de apenas uma instância, não instale outra . É somente quando você pode não ter outra instância, por exemplo, quando os gatinhos morrem ao criar uma segunda instância, que você pode ter um Caso de Uso válido para um Singleton.
O outro objetivo seria ter um ponto de acesso global a uma instância dentro da mesma solicitação. Embora isso possa parecer desejável, realmente não é, porque cria um acoplamento ao escopo global (como quaisquer globais e estáticos). Isso torna o teste de unidade mais difícil e sua aplicação em geral é menos sustentável. Existem maneiras de mitigar isso, mas, em geral, se você precisar ter a mesma instância em muitas classes, use Injeção de Dependência .
Veja meus slides para Singletons em PHP - Por que eles são ruins e como você pode eliminá-los de seus aplicativos para obter informações adicionais.
Até Erich Gamma , um dos inventores do padrão Singleton, duvida desse padrão hoje em dia:
Leitura adicional
Se, após o exposto, você ainda precisar de ajuda para decidir:
fonte
Quem precisa de singletons em PHP?
Observe que quase todas as objeções a singletons vêm de pontos de vista técnicos - mas elas também são MUITO limitadas em seu escopo. Especialmente para PHP. Primeiro, listarei algumas das razões para o uso de singletons e, em seguida, analisarei as objeções ao uso de singletons. Primeiro, as pessoas que precisam deles:
- As pessoas que estão codificando uma grande estrutura / base de código, que será usada em muitos ambientes diferentes, terão que trabalhar com estruturas / bases de código diferentes existentes anteriormente, com a necessidade de implementar muitas solicitações diferentes, alteradas e até caprichosas de clientes / chefes / gerência / líderes da unidade fazem.
Veja, o padrão singleton é auto-inclusivo. Quando concluída, uma classe singleton é rígida em qualquer código em que você a inclui e age exatamente como você criou seus métodos e variáveis. E é sempre o mesmo objeto em uma determinada solicitação. Como ele não pode ser criado duas vezes para ser dois objetos diferentes, você sabe o que é um objeto singleton em um determinado momento de um código - mesmo que o singleton seja inserido em duas, três diferentes bases de código espaguete, antigas e até espaguetes. Portanto, torna mais fácil em termos de desenvolvimento - mesmo que haja muitas pessoas trabalhando nesse projeto, quando você vê um singleton sendo inicializado em um ponto em qualquer base de código, você sabe o que é, o que faz, como faz e o estado em que está. Se fosse a classe tradicional, você precisaria acompanhar onde foi criado esse objeto pela primeira vez, quais métodos foram invocados nele até aquele momento no código e seu estado específico. Mas solte um singleton lá e, se você soltar métodos de depuração e informações adequados e rastrear o singleton enquanto o codifica, você sabe exatamente o que é. Portanto, torna mais fácil para as pessoas que precisam trabalhar com diferentes bases de código, com a necessidade de integrar o código que foi feito anteriormente com diferentes filosofias ou com pessoas com as quais você não tem contato. (ou seja, fornecedor-projeto-empresa-o que houver, não há suporte, nada). torna mais fácil para as pessoas que precisam trabalhar com diferentes bases de código, com a necessidade de integrar o código que foi feito anteriormente com diferentes filosofias ou com pessoas com as quais você não tem contato. (ou seja, fornecedor-projeto-empresa-o que houver, não há suporte, nada). torna mais fácil para as pessoas que precisam trabalhar com diferentes bases de código, com a necessidade de integrar o código que foi feito anteriormente com diferentes filosofias ou com pessoas com as quais você não tem contato. (ou seja, fornecedor-projeto-empresa-o que houver, não há suporte, nada).
- Pessoas que precisam trabalhar com APIs , serviços e sites de terceiros .
Se você olhar mais de perto, isso não será muito diferente do caso anterior - APIs, serviços e sites de terceiros são exatamente como bases de código externas e isoladas sobre as quais você NÃO tem controle. Nada pode acontecer. Assim, com uma classe de sessão / usuário singleton, você pode gerenciar QUALQUER tipo de implementação de sessão / autorização de fornecedores terceirizados como OpenID , Facebook , Twitter e muito mais - e você pode fazer tudo isso ao mesmo tempo no mesmo objeto singleton - que é facilmente acessível, em um estado conhecido a qualquer momento em qualquer código em que você o conectar. Você pode até criar várias sessões para várias APIs / serviços de terceiros diferentes para o MESMO usuário em seu próprio site / aplicativo e fazer o que quiser com eles.
Obviamente, tudo isso também pode se harmonizar com os métodos tradicionais usando classes e objetos normais - o problema aqui é que o singleton é mais arrumado, mais limpo e, portanto, por causa disso mais fácil de gerenciar / testável em comparação com o uso tradicional de classe / objeto nessas situações.
- Pessoas que precisam desenvolver rápido
O comportamento global dos singletons facilita a criação de qualquer tipo de código com uma estrutura que possui uma coleção de singletons, porque uma vez que você constrói bem suas classes singleton, os métodos estabelecidos, maduros e definidos estarão facilmente disponíveis e utilizável em qualquer lugar, a qualquer hora, de forma consistente. Leva algum tempo para amadurecer suas aulas, mas depois disso, elas são sólidas, consistentes e úteis. Você pode ter tantos métodos em um singleton fazendo o que quiser e, embora isso possa aumentar a área de armazenamento de memória do objeto, ele traz muito mais economia de tempo necessário para o desenvolvimento rápido - um método que você não está usando em uma determinada instância do um aplicativo pode ser usado em outro integrado e você pode simplesmente adicionar um novo recurso que o cliente / chefe / gerente de projeto solicita com apenas algumas modificações.
Você entendeu a ideia. Agora vamos passar às objeções aos singletons e à cruzada profana contra algo que é útil :
- A principal objeção é que torna os testes mais difíceis.
E realmente, até certo ponto, mesmo que possa ser facilmente mitigado, tomando as devidas precauções e codificando rotinas de depuração em seus singletons, com a constatação de que você estará depurando um singleton. Mas veja, isso não é muito diferente de QUALQUER outra filosofia / método / padrão de codificação disponível - é apenas que, os singletons são relativamente novos e não generalizados, portanto os métodos de teste atuais acabam sendo comparativamente incompatíveis com eles. Mas isso não é diferente em nenhum aspecto das linguagens de programação - estilos diferentes exigem abordagens diferentes.
Um ponto em que essa objeção não é clara é que ignora o fato de que os aplicativos desenvolvidos não são para 'teste' e o teste não é a única fase / processo que entra no desenvolvimento de aplicativos. Os aplicativos são desenvolvidos para uso em produção. E, como expliquei na seção 'quem precisa de singletons', os singletons podem reduzir muito a complexidade de ter que fazer um código funcionar COM e DENTRO de muitas bases de código / aplicativos / serviços de terceiros. O tempo que pode ser perdido nos testes é o tempo ganho em desenvolvimento e implantação. Isso é especialmente útil nesta era de autenticação / aplicativo / integração de terceiros - Facebook, Twitter, OpenID, muito mais e quem sabe o que vem a seguir.
Embora seja compreensível - os programadores trabalham em circunstâncias muito diferentes, dependendo de sua carreira. E para pessoas que trabalham em empresas relativamente grandes, com departamentos definidos, cuidando de software / aplicativos diferentes e definidos de maneira confortável e sem a desgraça iminente de cortes / demissões no orçamento e a necessidade de fazer um monte de coisas com muitas coisas diferentes de uma maneira barata / rápida / confiável, os singletons podem não parecer tão necessários. E pode até ser um incômodo / impedimento para o que JÁ têm.
Mas para quem precisa trabalhar nas trincheiras sujas do desenvolvimento 'ágil', tendo que implementar muitas solicitações diferentes (às vezes irracionais) de seu cliente / gerente / projeto, os singletons são uma graça salvadora devido às razões explicadas anteriormente.
- Outra objeção é que sua pegada de memória é maior
Porque um novo singleton existirá para cada solicitação de cada cliente, isso pode ser uma objeção ao PHP. Com singletons mal construídos e usados, o espaço de memória de um aplicativo pode ser maior se muitos usuários forem atendidos pelo aplicativo em um determinado momento.
No entanto, isso é válido para QUALQUER tipo de abordagem que você pode adotar ao codificar as coisas. As perguntas que devem ser feitas são: os métodos, os dados mantidos e processados por esses singletons são desnecessários? Pois, se eles são necessários em muitas solicitações que o aplicativo está recebendo, mesmo que você não use singletons, esses métodos e dados estarão presentes no aplicativo de alguma forma ou de outra através do código. Portanto, tudo se torna uma questão de quanta memória você estará economizando quando você inicializa um objeto de classe tradicional 1/3 no processamento de código e o destrói 3/4 nele.
Veja, quando colocada dessa maneira, a questão se torna bastante irrelevante - não deve haver métodos desnecessários, dados mantidos em objetos em seu código de qualquer maneira - independentemente de você usar singletons ou não. Portanto, essa objeção a singletons se torna realmente hilária, pois ASSUME que haverá métodos desnecessários, dados nos objetos criados a partir das classes que você usa.
- Algumas objeções inválidas como 'tornam impossível / difícil manter várias conexões com o banco de dados'
Eu não posso nem começar a entender essa objeção, quando todos precisam manter várias conexões com o banco de dados, várias seleções de banco de dados, várias consultas ao banco de dados, vários conjuntos de resultados em um determinado singleton, apenas os mantêm em variáveis / matrizes no singleton, desde que eles são necessários. Isso pode ser tão simples quanto mantê-los em matrizes, embora você possa inventar qualquer método que queira usar para efetuar isso. Mas vamos examinar o caso mais simples, o uso de variáveis e matrizes em um determinado singleton:
Imagine o seguinte abaixo dentro de um único banco de dados singleton:
$ this -> connections = array (); (sintaxe incorreta, digitei-a assim para fornecer uma imagem - a declaração apropriada da variável é public $ connections = array (); e seu uso é $ this-> connections ['connectionkey'] naturalmente)
Você pode configurar e manter várias conexões a qualquer momento em uma matriz dessa maneira. E o mesmo vale para consultas, conjuntos de resultados e assim por diante.
$ this -> query (QUERYSTRING, 'queryname', $ this-> connections ['particulrconnection']);
O que pode apenas fazer uma consulta a um banco de dados selecionado com uma conexão selecionada e apenas armazenar no seu
$ this -> resultados
matriz com a chave 'queryname'. Obviamente, você precisará ter seu método de consulta codificado para isso - o que é trivial.
Isso permite que você mantenha um número praticamente infinito de (até onde os limites de recursos permitirem) diferentes conexões com o banco de dados e conjuntos de resultados, conforme necessário. E eles estão disponíveis para QUALQUER parte do código em qualquer ponto em qualquer base de código em que essa classe singleton tenha sido instanciada.
É claro que você naturalmente precisará liberar os conjuntos de resultados e as conexões quando não forem necessários - mas isso não é preciso dizer, e não é específico para singletons ou qualquer outro método / estilo / conceito de codificação.
Neste ponto, você pode ver como manter várias conexões / estados com aplicativos ou serviços de terceiros no mesmo singleton. Não é tão diferente.
Para encurtar a história, no final, os padrões singleton são apenas mais um método / estilo / filosofia para programar, e são tão úteis quanto QUALQUER outro quando usados no lugar correto, da maneira correta. O que não é diferente de nada.
Você notará que na maioria dos artigos em que os singletons são esmagados, você também verá referências a 'globais' como 'maus'.
Vamos ser sinceros - Qualquer coisa que não seja usada corretamente, abusada, mal utilizada, É má. Isso não se limita a nenhum idioma, nenhum conceito de codificação, nenhum método. Sempre que vir alguém emitindo declarações gerais como 'X é mau', fuja desse artigo. As chances são muito altas de que é o produto de um ponto de vista limitado - mesmo que o resultado seja o resultado de anos de experiência em algo específico - que geralmente acaba sendo o resultado de trabalhar demais em um determinado estilo / método - típico conservadorismo intelectual.
Exemplos infinitos podem ser dados para isso, variando de 'globais são maus' a 'iframes são maus'. Há cerca de 10 anos, até propor o uso de um iframe em qualquer aplicativo era heresia. Depois vem o Facebook, iframes em todos os lugares, e veja o que aconteceu - os iframes não são mais tão maus.
Ainda existem pessoas que teimosamente insistem que são 'más' - e às vezes também por boas razões - mas, como você pode ver, há uma necessidade, os iframes preenchem essa necessidade e funcionam bem e, portanto, o mundo inteiro segue em frente.
O principal ativo de um programador / programador / engenheiro de software é uma mente livre, aberta e flexível.
fonte
Singletons são considerados por muitos como antipadrões , pois são realmente apenas variáveis globais glorificadas. Na prática, existem relativamente poucos cenários em que é necessário que uma classe tenha apenas uma instância; geralmente é apenas que uma instância é suficiente ; nesse caso, implementá-lo como um singleton é completamente desnecessário.
Para responder à pergunta, você está certo de que singletons são um exagero aqui. Uma variável ou função simples serve. Uma abordagem melhor (mais robusta), no entanto, seria usar a injeção de dependência para remover completamente a necessidade de variáveis globais.
fonte
No seu exemplo, você está lidando com um único pedaço de informação aparentemente imutável. Neste exemplo, um Singleton seria um exagero e apenas o uso de uma função estática em uma classe funcionará bem.
Mais pensamentos: você pode estar enfrentando um caso de implementação de padrões em prol de padrões e seu intestino está dizendo "não, você não precisa" pelos motivos que enumerou.
MAS: Não temos idéia do tamanho e do escopo do seu projeto. Se esse código é simples, talvez jogue fora, que provavelmente não precisará mudar, sim, vá em frente e use membros estáticos. Mas, se você acha que seu projeto pode precisar ser escalado ou preparado para manutenção de codificação no futuro, sim, convém usar o padrão Singleton.
fonte
Primeiro, só quero dizer que não encontro muitos usos para o padrão Singleton. Por que alguém iria querer manter um único objeto completo em todo o aplicativo? Especialmente para bancos de dados, e se eu quiser conectar-me a outro servidor de banco de dados? Eu tenho que desconectar e reconectar toda vez ...? De qualquer forma...
Existem várias desvantagens no uso de globais em um aplicativo (que é o que o uso tradicional do padrão Singleton faz):
Usar classes estáticas em vez de uma instância singleton também fornece algumas das mesmas desvantagens, porque o maior problema do singleton é a estática
getInstance
método .Você pode limitar o número de instâncias que uma classe pode ter sem usar o
getInstance
método tradicional :Isso ajudará primeiro os pontos mencionados acima: teste de unidade e injeção de dependência; enquanto ainda garante que exista uma única instância da classe no seu aplicativo. Você poderia, por exemplo, apenas passar o objeto resultante para seus modelos (padrão MVC) para que eles usassem.
fonte
Considere simplesmente como sua solução difere da apresentada nos documentos do PHP. De fato, há apenas uma diferença "pequena": sua solução fornece aos chamadores do getter uma
PDO
instância, enquanto a dos documentos fornece aos chamadoresDatabase::singleton
umaDatabase
instância (eles usam o getter para obter umaPDO
instância).Então, a que conclusão chegamos?
Database
instância. ADatabase
classe pode expor (de fato, deve expor se você estiver enfrentando todo esse problema) uma interface mais rica ou de nível superior do que oPDO
objeto que ela envolve.PDO
, as duas implementações serão equivalentes. Não há ganho em se seguir a implementação manual.No lado prático, Singleton é um padrão bastante controverso. Isto é principalmente porque:
Então, como conclusão final: seu singleton está ótimo. Não usar o Singleton também é bom na maioria das vezes.
fonte
Sua interpretação está correta. Singletons têm seu lugar, mas são usados em excesso. Freqüentemente, acessar funções-membro estáticas é suficiente (principalmente quando você não precisa controlar o tempo de construção). Melhor, você pode simplesmente colocar algumas funções e variáveis livres em um espaço para nome.
fonte
Ao programar, não há "certo" e "errado"; existem "boas práticas" e "más práticas".
Singletons geralmente são criados como uma classe para serem reutilizados posteriormente. Eles precisam ser criados de forma que o programador não instancia acidentalmente duas instâncias enquanto codifica bêbado à meia-noite.
Se você tem uma turma simples que não deve ser instanciada mais de uma vez, não precisa torná-la única. É apenas uma rede de segurança, se você o fizer.
nem sempre é uma prática ruim ter objetos globais. Se você sabe que vai usá-lo globalmente / em qualquer lugar / o tempo todo, pode ser uma das poucas exceções. No entanto, as globais são geralmente consideradas "más práticas" da mesma maneira que
goto
são consideradas más práticas.fonte
Não vejo razão para isso. Se você implementasse a classe de forma que a cadeia de conexão fosse tomada como parâmetro para o construtor e mantivesse uma lista de objetos PDO (um para cada cadeia de conexão exclusiva), talvez houvesse algum benefício, mas a implementação de singleton em Neste caso, parece um exercício inútil.
fonte
Você não está perdendo nada, tanto quanto eu posso ver. O exemplo é bastante falho. Isso faria diferença se a classe singleton tivesse algumas variáveis de instância não estáticas.
fonte