PHP: Armazenando 'objetos' dentro do $ _SESSION

188

Acabei de descobrir que posso realmente armazenar objetos no $ _SESSION e acho muito legal porque, quando pulo para outra página, ainda tenho meu objeto. Agora, antes de começar a usar essa abordagem, gostaria de descobrir se é realmente uma boa idéia ou se existem armadilhas potenciais envolvidas.

Sei que se eu tivesse um único ponto de entrada, não precisaria fazer isso, mas ainda não estou lá, por isso não tenho um único ponto de entrada e realmente gostaria de manter meu objeto porque não não perco meu estado assim. (Agora também li que devo programar sites sem estado, mas ainda não entendo esse conceito.)

Então, em suma : É OK para armazenar objetos na sessão, há algum problema com ele?


Editar:

Resumo temporário : A essa altura, eu entendo que provavelmente melhor recriar o objeto, mesmo que isso envolva a consulta do banco de dados novamente.

Talvez mais respostas possam ser elaboradas sobre esse aspecto um pouco mais!

markus
fonte
13
Como 'estúpido' I foi em 2008 :-)
Markus
49
mas pergunta útil para 'estúpido é como nós em 2014: D
Momin Al Aziz 02/02
3
Very nice perguntas que você pediu Markus .. :) Eu li isso hoje;)
GKD
1
Você não era estúpido! Você perguntou o que eu estava prestes a perguntar e me fez um sólido, 10 anos depois!
28418 toddmo #
Bem, eu imaginei que você acabou de me salvou de fazer uma pergunta estúpida em 2019
Maxwell

Respostas:

133

Sei que esse tópico é antigo, mas esse problema continua aparecendo e não foi abordado para minha satisfação:

Se você salvar objetos em $ _SESSION ou reconstruí-los com base em dados armazenados em campos de formulário ocultos, ou consultá-los novamente no banco de dados toda vez, você está usando state. O HTTP é sem estado (mais ou menos; mas veja GET vs. PUT), mas quase tudo o que alguém se importa com um aplicativo da Web exige que o estado seja mantido em algum lugar. Agir como se empurrar o estado para cantos e recantos equivale a algum tipo de vitória teórica é errado. Estado é estado. Se você usa o estado, perde as várias vantagens técnicas obtidas por não ter estado. Isso não é algo para se perder o sono, a menos que você saiba com antecedência que deveria estar perdendo o sono por causa disso.

Estou especialmente desconcertado com a bênção recebida pelos argumentos de "golpe duplo" apresentados por Hank Gay. O OP está construindo um sistema de comércio eletrônico distribuído e com balanceamento de carga? Meu palpite é que não; e ainda afirmo que a serialização de sua classe $ User, ou qualquer outra coisa, não prejudicará seu servidor além do reparo. Meu conselho: use técnicas que sejam sensíveis à sua aplicação. Objetos em $ _SESSION são bons, sujeitos a precauções de bom senso. Se seu aplicativo se transformar repentinamente em algo que rivaliza com a Amazon no tráfego atendido, você precisará se adaptar novamente. Isso é vida.

shanusmagnus
fonte
16
Ótima resposta incorporando muitos dos meus pensamentos enquanto eu lia através disso. A internet moderna precisa de estado. Embora alguns aplicativos não precisem de estado e façam sentido para torná-los sem estado, a Internet moderna depende de muitos sistemas baseados em estado (AKA: Logins!) Para simplesmente desistir deles! Os grandes deuses da internet incorporaram esse conceito básico por anos na forma de cookies e, em um nível básico, eles o adicionaram na forma de armazenamento local em HTML. Pode fazer sentido evitar o uso excessivo do estado em alguns aplicativos, mas alguns! = All!
21412 RonLugge
Bem, quando eu fiz essa pergunta logo depois que o homem inventou o fogo, eu não sabia muitas coisas que sei hoje ... o que também é bom. Enquanto isso, eu diria que pode haver alguns bons casos de uso, mas geralmente procuraria outras soluções primeiro. Ainda marcando isso como a nova resposta aceita, porque a outra resposta é categórica.
Markus
Muito poucas respostas me fazem rir alto. Este fez. Bravo +1
toddmo 27/03/18
114

tudo bem, desde que a chamada session_start () seja feita, a declaração / definição da classe já foi encontrada pelo PHP ou pode ser encontrada por um carregador automático já instalado. caso contrário, não seria possível desserializar o objeto do armazenamento da sessão.

cruizer
fonte
12
Obrigado! Isso corrigiu um erro para mim: D
Matt Ellen
Suponho que esse problema possa ser evitado se você tiver uma __autoload()função adequada .
Langel
Ao desserializar um objeto serializado, precisamos adicionar a definição de classe ??? No momento de serializar o objeto, ele precisa da definição de classe, que eu concordo. Mas tenho que adicionar a definição de classe também no arquivo em que tenho que desserializar o objeto serializado ???
Rajesh Paul
35

HTTP é um protocolo sem estado por um motivo. Sessões soldam o estado no HTTP. Como regra geral, evite usar o estado da sessão.

UPDATE: Não há conceito de sessão no nível HTTP; os servidores fornecem isso fornecendo ao cliente um ID exclusivo e solicitando que o reenvie a cada solicitação. Em seguida, o servidor usa esse ID como chave em uma grande hashtable de objetos Session. Sempre que o servidor recebe uma solicitação, ele procura as informações da Sessão em seus hashtable de objetos de sessão com base no ID que o cliente enviou com a solicitação. Todo esse trabalho extra é um golpe duplo na escalabilidade (uma grande razão pela qual o HTTP é sem estado).

  • Whammy One: reduz o trabalho que um único servidor pode fazer.
  • Whammy Two: torna mais difícil o dimensionamento, porque agora você não pode simplesmente encaminhar uma solicitação para qualquer servidor antigo - eles nem todos têm a mesma sessão. Você pode fixar todas as solicitações com um determinado ID de sessão no mesmo servidor. Isso não é fácil e é um ponto único de falha (não para o sistema como um todo, mas para grandes partes de seus usuários). Ou então, você pode compartilhar o armazenamento da sessão em todos os servidores do cluster, mas agora tem mais complexidade: memória conectada à rede, um servidor de sessão independente etc.

Dado tudo isso, quanto mais informações você colocar na sessão, maior será o impacto no desempenho (como Vinko aponta). Também como Vinko aponta, se o seu objeto não for serializável, a sessão se comportará mal. Portanto, como regra geral, evite colocar mais do que o absolutamente necessário na sessão.

@Vinko Geralmente, você pode contornar o estado de armazenamento do servidor incorporando os dados que está rastreando na resposta que você envia de volta e fazendo com que o cliente os reenvie, por exemplo, enviando os dados para baixo em uma entrada oculta. Se você realmente precisa do rastreamento de estado no servidor, provavelmente deve estar no seu armazenamento de dados de backup.

(Vinko acrescenta: o PHP pode usar um banco de dados para armazenar informações da sessão e fazer com que o cliente reenvie os dados a cada vez pode resolver possíveis problemas de escalabilidade, mas abre uma grande lata de problemas de segurança que você deve prestar atenção agora que o cliente está no controle de todos seu estado)

Hank Gay
fonte
1
Não há conceito de sessão no nível HTTP; os servidores fornecem isso fornecendo ao cliente um ID exclusivo e solicitando que o reenvie a cada solicitação. Em seguida, o servidor usa esse ID como chave em uma grande hashtable de objetos Session. Para ser continuado ...
Hank Gay
1
Sempre que o servidor recebe uma solicitação, ele procura as informações da Sessão em seus hashtable de objetos de sessão com base no ID que o cliente enviou com a solicitação. Todo esse trabalho extra é um golpe duplo na escalabilidade (uma grande razão pela qual o HTTP é sem estado). Para ser continuado ...
Hank Gay
1
Pergunto-me como é que você implementar aplicações complexas sobre HTTP sem soldagem estado de alguma forma
Vinko Vrsalovic
3
edite sua resposta para incluir todos esses comentários. é mais fácil de ler e melhor para o wiki e, de qualquer maneira, não posso escolher sua resposta como a aceita, se tudo de importante estiver nos comentários. obrigado!
Markus
6
"whammy one" Eu gostaria de poder rebater isso mais. Conheça o seu tempo. Uma referência de memória custa 100 nano segundos ou 0,0001 ms. Portanto, pesquisar uma hashtable armazenada na memória principal não custa literalmente tempo. Será que O(1)dizer-lhe alguma coisa? @ whammy dois: apenas não roteie aleatoriamente todos os pedidos para servidores aleatórios? faça round robin e mantenha o roteamento para o mesmo servidor do mesmo usuário. Isso é uau, super óbvio. Você deve
revisar
19
  • Objetos que não podem ser serializados (ou que contêm membros não serializáveis) não sairão do $ _SESSION como seria de esperar
  • Sessões enormes sobrecarregam o servidor (serializar e desserializar megas de estado cada vez que é caro)

Fora isso, não vi problemas.

Vinko Vrsalovic
fonte
9

Na minha experiência, geralmente não vale a pena por algo mais complicado do que um StdClass com algumas propriedades. O custo da desserialização sempre foi mais do que recriar de um banco de dados, devido a um identificador armazenado em sessão. Parece legal, mas (como sempre), a criação de perfil é a chave.

Greg
fonte
Algum comentário sobre o desempenho entre consultar uma tabela de dados 5x2 a cada solicitação e armazenar em cache o resultado na sessão e usá-lo?
musicliftsme
6

Eu sugeriria não usar o estado, a menos que você absolutamente precise. Se você pode reconstruir o objeto sem usar sessões, faça-o. Ter estados em seu aplicativo da Web torna o aplicativo mais complexo para criar, para cada solicitação que você precisa ver em que estado o usuário está. É claro que há momentos em que você não pode evitar o uso da sessão (por exemplo: o usuário deve manter o login durante a sessão em o aplicativo da web). Por último, sugiro manter o objeto da sessão o menor possível, pois isso afeta o desempenho para serializar e desserializar objetos grandes.

Johnny
fonte
Então, é melhor reconstruir o objeto, incluindo fazer todas as consultas do banco de dados novamente? Porque um dos meus pensamentos para fazer isso foi que não preciso consultar o banco de dados pelo mesmo material novamente.
Markus
3
Se for importante para você que ele não consulte o banco de dados novamente, use o cache em vez de armazená-lo na sessão. Mas, por favor, antes de fazer algo como criar cache, verifique se é realmente um problema de desempenho.
Johnny
Obrigado, acho que não é. Eu deveria apenas consultar novamente.
markus
4

Você precisará lembrar que os tipos de recursos (como conexões db ou ponteiros de arquivo) não persistirão entre os carregamentos da página e será necessário recriá-los invisivelmente.

Considere também o tamanho da sessão, dependendo de como ela é armazenada, você pode ter restrições de tamanho ou problemas de latência.

Marc Gear
fonte
0

Eu também mencionava ao atualizar as bibliotecas de software - atualizamos nosso software e a versão antiga tinha objetos em sessão com os nomes de classe do software V1, o novo software estava travando quando tentava criar os objetos que estavam na sessão - como o V2 o software não usava mais essas mesmas classes, não as encontrava. Tivemos que inserir algum código de correção para detectar objetos da sessão, excluir a sessão, se encontrada, recarregar a página. A maior dor inicialmente lembrou que você estava recriando esse bug quando foi relatado pela primeira vez (familiar demais, "bem, funciona para mim"), pois afetava apenas as pessoas que entravam e saíam dos sistemas novos e antigos recentemente - no entanto, bom trabalho que encontramos antes do lançamento, pois todos os nossos usuários certamente teriam as variáveis ​​de sessão antigas em suas sessões e teriam potencialmente travado para todos,

De qualquer forma, como você sugere na sua alteração, também acho melhor recriar o objeto. Então, talvez apenas armazenar a identificação e, a cada solicitação, extrair o objeto do banco de dados, seja melhor / mais seguro.

Martyn
fonte