Existe um caso de uso para singletons com acesso ao banco de dados em PHP?


138

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 $dbmais.

Como posso criar uma classe singleton menor ou há um caso de uso para singletons que estou ausente no PHP?


Há muitos recursos e discussões nesta pergunta relacionada: 'O que há de tão ruim nos singletons?'
FruitBreak

Respostas:


80

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.


15
Você diz que os singletons se degradam muito bem no DI, mas não é seu exemplo de getInstance(databaseName)apenas espalhar referências a um repositório global de instâncias em todo o seu código? O código que chamaria getInstancedeve ter as instâncias injetadas nele pelo código do cliente e, portanto, não precisa chamar getInstanceem primeiro lugar.
Will Vousden

1
@ Will Vousden Correto, é uma espécie de brecha. Não é realmente DI, mas pode ser bem próximo. Por exemplo, e se fosse getInstance (supportedDatabase) e a instância retornada foi calculada com base em qual banco de dados foi passado? O objetivo é evitar assustar as pessoas com uma estrutura de DI até que estejam prontas para isso.
Bill K

320

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:

"Sou a favor de abandonar Singleton. Seu uso é quase sempre um cheiro de design"

Leitura adicional

Se, após o exposto, você ainda precisar de ajuda para decidir:

Diagrama de Decisão Singleton


1
@Gordon yes. E mesmo que fosse possível manter objetos entre solicitações, os Singletons ainda violam alguns princípios do SOLID e introduzem o Estado Global.
22711 Gordon

4
Desculpe ir contra o fluxo, mas o DI não é realmente uma solução para o problema para o qual o Singleton está sendo usado, a menos que você esteja satisfeito em ter classes com 42 parâmetros de ctor (ou 42 chamadas setFoo () e setBar () necessárias para torná-lo trabalhos). Sim, infelizmente, alguns aplicativos precisam ser acoplados e dependem de muitas coisas externas. PHP é uma linguagem de cola, e às vezes há muitas coisas a serem coladas.
StasM 5/05

14
@StasM, se você estiver usando 42 parâmetros de ctor ou precisar de muitos setters, está fazendo algo errado. Assista as palestras sobre código limpo, por favor. Desculpe, se não me incomodo em explicar isso mais uma vez. Sinta-se à vontade para solicitar mais informações na sala de bate-papo do PHP.
Gordon

@Gordon Onde fica a sala de chat php?
precisa saber é o seguinte

21

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.


2
-1. Embora eu concorde que ter uma mente aberta e flexível é um recurso obrigatório para qualquer desenvolvedor, ele não resgata o Singleton de ser um Antipadrão. A resposta acima contém tantas afirmações imprecisas e conclusões erradas sobre a natureza e os efeitos do Singleton que não posso deixar de votar.
Gordon

-1. Eu tive que experimentar uma estrutura com muitos singletons em primeira mão e o teste automático é impossível. Eu tenho que testar manualmente tudo via tentativa e erro em um navegador. Alguns erros podem ser evitados com a revisão de código (ortografia, erros de sintaxe), mas os erros funcionais geralmente estão ocultos. Esse teste requer muito mais tempo do que os testes de unidade. Com testes de unidade, eu poderia dizer: Esta classe funciona isoladamente, o erro deve estar em outro lugar. Sem a depuração é entediante.
23814 Jim Martens

A estrutura precisava ter construído log e rastreamento de erros. Além disso, uma classe que funcione adequadamente de forma isolada também funcionaria corretamente de forma única quando colocada em um aplicativo mais amplo. O que significa que, nesse caso, o que está quebrando seria outra classe ou função que está interagindo com esse singleton. Isso não é diferente do rastreamento de bug comum em um grande aplicativo. O que é bastante difícil sem o aplicativo ter o registro adequado.
usar o seguinte comando

Impreciso. Toneladas de singletones é definitivamente MAU, porque cria o Testing-HELL. :-) No entanto, um singletone por aplicativo pode ser bom. Por exemplo: como um recurso de registro unificado - para implementar em todos os aplicativos (incluindo alguns de código herdado).
Filip OvertoneSinger Rydlo

"O tempo que pode ser perdido nos testes ..." Essa é uma prática e um modo de pensar realmente muito ruins. Todos os aplicativos herdados por aí foram desenvolvidos com isso em mente e tornou-se impossível mantê-los, para que precisassem ser reescritos. Se não houver testes, o tempo será perdido quando um novo recurso for desenvolvido e interromperá algo em alguma outra parte do sistema. Tempo perdido na depuração, tempo perdido pelos usuários que podem usar esse recurso corretamente, a confiança no aplicativo perdeu etc.
bogdancep

15

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.


Mas os singletons podem se degradar de maneira muito suave no DI, as classes estáticas não, o que é o verdadeiro problema das classes estáticas.
Bill K

@ Bill: É verdade, mas então é por isso que eu defendem uma abordagem DI para começar, em vez de funções soltas ou métodos estáticos :)
Will Vousden

Em algumas linguagens (como Java), as classes estáticas (ou métodos estáticos de classes) não podem ser estendidas. Então você cria problemas em potencial (ou, na melhor das hipóteses, mais trabalho) para futuros desenvolvedores. Portanto, alguns sugerem que os métodos estáticos geralmente devem ser evitados, a menos que você tenha uma necessidade específica deles.
Marvo

8

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.


1
Uau, simplesmente errado. O ponto principal da diferença (a resposta à pergunta) é quanto mais difícil é consertar seu código posteriormente para adicionar uma segunda instância. É muito mais difícil fazer isso se você usou métodos estáticos. É como dizer "Globals estão bem sob suas condições limitadas" quando todo o problema com Globals é que as condições mudam.
Bill K

@ Bill K: Eu concordo com você e eu usaria um singleton se houvesse alguma complexidade. Mas eu estava tentando responder à pergunta do ponto de vista do OP e pensei: bem, sim, acho que é um exagero neste caso muito limitado. É claro que eu estava ignorando as preocupações de arquitetura ou escalabilidade e várias outras considerações. Deveria ter incluído isso como uma advertência na minha resposta, com uma explicação sobre por que alguém sempre deveria usar um singleton ... o que certamente teria causado votos negativos de outras pessoas?
Paul Sasik

5

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):

  • Teste de unidade difícil
  • Problemas de injeção de dependência
  • Pode criar problemas de bloqueio (aplicativo multiencadeado)

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 getInstancemétodo tradicional :

class Single {

    static private $_instance = false;

    public function __construct() {
        if (self::$_instance)
           throw new RuntimeException('An instance of '.__CLASS__.' already exists');

        self::$_instance = true;
    }

    private function __clone() {
        throw new RuntimeException('Cannot clone a singleton class');
    }

    public function __destruct() {
        self::$_instance = false;
    }

}

$a = new Single;
$b = new Single; // error
$b = clone($a); // error
unset($a);
$b = new Single; // works

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.


5

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 PDOinstância, enquanto a dos documentos fornece aos chamadores Database::singletonuma Databaseinstância (eles usam o getter para obter uma PDOinstância).

Então, a que conclusão chegamos?

  • No código da documentação, os chamadores obtêm uma Databaseinstância. A Databaseclasse pode expor (de fato, deve expor se você estiver enfrentando todo esse problema) uma interface mais rica ou de nível superior do que o PDOobjeto que ela envolve.
  • Se você alterar sua implementação para retornar outro tipo (mais rico) que 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:

  • É muito usado. Programadores iniciantes entendem Singleton muito mais facilmente do que outros padrões. Eles então aplicam seus novos conhecimentos em todos os lugares, mesmo que o problema em questão possa ser melhor resolvido sem Singleton (quando você está segurando um martelo, tudo parece um prego).
  • Dependendo da linguagem de programação, implementar um Singleton de maneira hermética e sem vazamentos pode ser uma tarefa titânica (especialmente se tivermos cenários avançados: um singleton dependendo de outro singleton, singletons que podem ser destruídos e recriados etc.) ) Apenas tente procurar a implementação Singleton "definitiva" em C ++, eu te desafio (sou o proprietário do inovador Modern C ++ Design de Andrei Alexandrescu, que documenta grande parte da bagunça).
  • Ele impõe carga de trabalho adicional ao codificar o Singleton e ao escrever código para acessá-lo, carga de trabalho que você pode fazer sem seguir algumas restrições auto-impostas sobre o que você tenta fazer com as variáveis ​​do programa.

Então, como conclusão final: seu singleton está ótimo. Não usar o Singleton também é bom na maioria das vezes.


2

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.


2

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 gotosão consideradas más práticas.


2

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.


1

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.