Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

André Marcondes

Afinal, pra server o Singleton?

Recommended Posts

Olá a todos.

 

Tenho uma dúvida que está me embaralhando a cabeça.

 

Estou aprendendo (tentando aprender) Singleton.

Quando leio na internet sobre o padrão Singleton, todos falam que apenas uma instância daquele determinado objeto vai estar disponível em TODA a aplicação.

Certo, então, por exemplo, se eu possuir uma conexão de banco de dados usando singleton, essa mesma conexão vai ser usada na minha aplicação, certo?

Para falar a verdade agora não sei...

 

Porque, afinal, para um objeto refenciando uma conexão com o banco de dados retornar sempre a mesma conexão, este objeto deveria ser statefull, certo? Pois ele deveria armazenar na memória o valor da conexão em uma variável estática e sempre retornar a mesma conexão, sem tentar abrir outra, MESMO QUE O USUÁRIO MUDE DE PÁGINA, O QUE OCASIONARIA O RECARREGAMENTO DA MESMA, certo?

 

Então para testar isso, incrementei uma classe de teste encontrei na net para ver se eu conseguia verificar essa característica (tirei o exemplo de .http://rubsphp.blogs...09/12/self.html)

 

A idéia é que, toda vez que eu recarregue a página, um valor seja incrementado na classe, mas não é o que está ocorrendo.

 

eis o código:

 


<?php
ini_set('display_errors', 1);
error_reporting(E_ALL | E_STRICT);

class teste_singleton {
   private static $instancia = null;
   private static $numero;

   /**
	* Construtor privado
	*/
   private function __construct() {
       self::$numero++;
   }

   /**
	* Nao permitir clonagem
	*/
   public function __clone() {
       throw new Exception('Singleton nao permite clonagem');
   }

   /**
	* Devolve uma instancia singleton da classe corrente
	* @return teste_singleton
	*/
   public static function get_instancia() {
       if (self::$instancia === null) {
           self::$instancia = new self();
       }
       return self::$instancia;
   }


   public function getNumero(){
       return self::$numero;
   }
}

echo teste_singleton::get_instancia()->getNumero();

?>

 

 

Minha pergunta é:

Onde estou errando? Ou fui eu que não entendi para que server o singleton?

 

Espero que possam me ajudar.

 

Grato.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Na verdade, está correto. O que você deve entender é que, diferentes de linguagens como Java/C#, PHP não está sempre "rodando". A execução de um script PHP possui um início, meio e fim. O fim é o fim mesmo, todos os objetos são destruídos, todas as classes apagadas da memória.

 

Você até poderia colocar a classe em __sleep(). Entretanto, isso não funciona para alguns tipos de dados, tal como resource.

 

O PHP trabalha por requisições. Dentro dessa requisição, o Singleton possuirá uma única instância. Iniciada a requisição, os objetos são criados, o scripts rodado. Assim que todo o script é realizado, o resultado devolvido ao cliente, o ciclo de vida do script acaba, e os objetos são destruídos. Com exceção de algumas coisas (cookies, session), que fazem parte do client-side também, todo o resto, que é apenas server-side, deixa de existir.

 

O artigo abaixo não tem muito haver com o assunto em si, mas o autor fala um pouco sobre o ciclo de vida do PHP ser por requisição:

http://imasters.com.br/artigo/24350/php/php-e-um-saco-mas-eu-gosto

 

Ciclo de vida do aplicativo é por solicitação. Este é realmente um dos aspectos negativos identificados pelo artigo original. Cada solicitação inicia o PHP novamente (bem, não o PHP, mas seu aplicativo PHP). Isso é uma coisa boa, porque (citando Rasmus Lerdorf, criador do PHP, em uma entrevista) “a arquitetura nada comum do PHP… leva à escalabilidade horizontal infinita na própria linguagem.” Isso significa que a transição de um único servidor para múltiplos depois que é feito o deploy no aplicativo é trivial. As únicas restrições são aquelas que o programador coloca artificialmente. Linguagens que usam o estado compartilhado nativamente (como Python, Ruby, JavaScript – NodeJS etc. – e Java) devem ser escritas para não usarem o estado compartilhado que é disponibilizado para que isso funcione.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, estou a par do funcionamento do PHP.

Se é assim, realmente não vejo nenhum motivo para usar o singleton.

 

 

Já que o mesmo só vale para a requisição em que ele foi executado, para fazer o que ele se propõe a fazer, basta chamar o que se precisa uma vez somente (nem precisa ser orientado a objeto) e colocar em variáveis.

 

Por exemplo, em uma conexão com o banco de dados, usando programação estruturada:

 

// inclui conexão com o banco de dados
require 'conexao.php';

//resto do código

 

 

Já com orientação a objetos:

$conexao = BDSingleton->getInstance();

// resto do código

 

 

Na programação orientada a objeto, iria fazer uma nova conexão com o banco de dados TODA vez que a página recarrega

Na programação estruturada, A MESMA COISA

 

Então, qual é a vantagem do Singleton ao utilizá-lo com o PHP?

 

Existe uma maneira de implementar singleton globalmente em um sistema feito com PHP?

Compartilhar este post


Link para o post
Compartilhar em outros sites
Então, qual é a vantagem do Singleton ao utilizá-lo com o PHP?

Garantir que, na execução do script, só exista uma única instancia de um objeto.

 

Em nenhuma programação seria aconselhável utilizar Singleton para conexão com banco de dados, assunto que é amplamente discutido aqui no fórum.

 

Entretanto, para a estrutura DOM e APIs de I/O é extremamente útil, uma vez que uma variável não possui garantia de "não clonagem", o Singleton te impossibilitaria essa funcionalidade.

 

O caso de APIs de I/O, apesar de o PHP não possuir acesso ao client, ele possui acesso ao hardware do servidor. Múltiplas instâncias de uma classe de I/O seria uma "bagunça" total.

 

Pra quem conheceu o Star Office e a maravilha de se enviar "múltiplos" arquivos. Ou conhecer condição de corrida, já basta.

 

O Registry também é uma excelente utilidade para o uso de Singleton.

Compartilhar este post


Link para o post
Compartilhar em outros sites

você diz

 

Já com orientação a objetos:

$conexao = BDSingleton->getInstance();

 

por isso quanto utiliza singleton tem que ser uma classe/objeto estático.

 

assim você não trabalha desse jeito

 

seria

conexao::

Compartilhar este post


Link para o post
Compartilhar em outros sites
A idéia é que, toda vez que eu recarregue a página, um valor seja incrementado na classe, mas não é o que está ocorrendo.

Essa não é a concepção de Singleton.

 

Singleton permite perpetuar uma instância ao longo do Fluxo da Aplicação e não ao longo do Fluxo da Requisição.

 

Conceitualmente, o Fluxo da Aplicação é sempre vertical e crescente, desde o processo de Routing que trabalha diretamente com a requisição feita até o MVC, onde ocorre aquele ciclo entre ele a View e o Controller.

 

Já o Fluxo da Requisição é horizontal e estável, você só pode ir pra frente ou para trás.

 

E apesar de estarem conceitualmente conectados, ambos estão isolados em seus respectivos ambientes.

 

Quando você inicia um Fluxo de Requisição que eventualmente engatilhe uma classe Singleton o qual terá seu getInstance() invocado, a primeira coisa a ser feita é uma verificação se esse método já foi anteriormente invocado, numa requisição anterior.

 

Se não, antes de ser retornada, a propriedade recebe uma nova instância.

 

No seu código, você incrementa a propriedade $numero no construtor, mas o construtor só será invocado na primeira requisição e por isso que o valor é sempre igual, independente do número de requisições ou invocações ao método você fizer.

 

Porque, afinal, para um objeto refenciando uma conexão com o banco de dados retornar sempre a mesma conexão, este objeto deveria ser statefull, certo? Pois ele deveria armazenar na memória o valor da conexão em uma variável estática e sempre retornar a mesma conexão, sem tentar abrir outra, MESMO QUE O USUÁRIO MUDE DE PÁGINA, O QUE OCASIONARIA O RECARREGAMENTO DA MESMA, certo?

Não sei se entendi o que quis dizer, mas vejamos, por causa do Fluxo da Aplicação ser crescente isso não acontece.

 

Vamos ver se eu consigo esquematizar:

 

Requisição >> Routing >> Application Controller >> Singleton >> Dispatcher >> Action Controller

 

Obs.: Imagine esta sequencia ocorrendo de baixo para cima.

 

É feita uma Requisição e seu sistema precisa saber trabalhar com ela. O seu roteador vai trabalhar sobre ela (requisição) e identificar à qual Aplicação ela se refere e qual Action Controller dessa Aplicação a manipulará.

 

Uma vez identificado, antes do fluxo atingir o Dispatcher (que é quem efetivamente invocará a Action do Controller), a Aplicação é instanciada e algumas rotinas de preparação executadas.

 

É nesse momento que entra o Singletonm, principal, mas não exclusivamente, junto de um Registry.

 

Quando uma nova Requisição é feita, o Fluxo se repete, e quando atinge o instanciamento da Aplicação, o Singleton não vai ser executado novamente pois aquilo que te tinha de fazer já foi feito e, se em uso com o Registry, já foi armazenado e já está pronto para usar, desde a requisição anterior.

 

Espero que tenha explicado bem.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Também existe uma segunda parte do Singleton que é explicada no famoso livro de Padrões de Projeto. Para ser fiel, eu prefiro copiar o trecho ao invés de apenas parafrasear:

Garantir que uma classe tenha somente uma instância e fornecer um ponto de acesso global para a mesma.

 

Tirando o erro de português de "para a mesma". Fornecer um ponto de acesso global, você consegue através de um Singleton. Na programação convencional, você irá precisar passar por parâmetro o a classe se quiser ela dentro de outro escopo de uma classe.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Na programação convencional, você irá precisar passar por parâmetro o a classe se quiser ela dentro de outro escopo de uma classe.

Ou pior, usar a palavra-chave global ou o array $GLOBALS

 

Porém, como o Registry citado também é um recurso global também está sujeito ao mesmo problema das variáveis globais: a duplicidade de nomes.

 

Claro, um Registry melhor escrito pode disparar um erro quando houver uma... uma... sobrescrição? (nem sei se essa palavra existe), mas isso não cabe ao escopo do tópico.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ou pior, usar a palavra-chave global ou o array $GLOBALS

Me deu calafrios ao ler isso... :upset:

 

Porém, como o Registry citado também é um recurso global também está sujeito ao mesmo problema das variáveis globais: a duplicidade de nomes.

 

Claro, um Registry melhor escrito pode disparar um erro quando houver uma... uma... sobrescrição? (nem sei se essa palavra existe), mas isso não cabe ao escopo do tópico.

Isso de fato pode acontecer e cabe ao desenvolvedor se "precaver" quanto a esse problema. O importante é salientar que o Singleton ocorre, e se faz da seguinte forma:

- Só existe uma instância de Registry;

- Registry disponibiliza um único acesso global.

 

E a última, mas não menos importante, parte:

https://bitbucket.org/imasters/mvc-na-pratica/src/c8c9dba131c0/application/com/imasters/pro/util/Registry.php

http://forum.imasters.com.br/topic/463107-pdo-registry-design-pattern-phpoo/page__view__findpost__p__1834858

 

Vera que, no João Batista Neto, nesse caso (link 1), não utiliza de validação quanto a duplicidade da key.

Já o Henrique Barcelos utiliza-se de validação.

 

Também vale comentar que, em outro tópico que eu estou procurando ainda, o João Batista Neto utiliza-se exceptions para tratar duplicidade no Registry.

 

Como o @Bruno Augusto já comentou, não é o escopo nem do tópico e nem do Singleton. Mas é bem importante saber que existe. Se ninguém soubesse, eu não saberia :grin:

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.