On 7/14/2019 10:01 AM, Dennis Munding wrote:
> Har fået flg. forespørgsel:
>
> "I .net hedder de application.
>
> Application ("test") = "blabla"
>
> Du gemmer blabla i test når siden starter.
>
> Alle steder, alle brugere kan så tilgå den application
>
> Findes den i PHP ?"
>
> Jeg foreslog at bruge enten globals eller super globals, men spørger
> påstår, at det ikke virker...
>
> Har php virkelig ikke noget tilsvarende?
Du har allerede fået flere svar, men lad mig alligevel prøve
at forklare lidt. Det bliver en lidt lang post men der er mange
aspekter af spørgsmålet.
Først begreber:
session = container (dictionary/map/associativt array med
keys og values) med en instans per user session
(identificeret ved session id)
application = container (dictionary/map/associativt array med
keys og values) med en enkelt instans for hele applikationen
Får både session og application gælder det at de er ret simple
for en enkelt server, men at det bliver kompliceret med et
cluster hvor man vil dele dem mellem serverne.
De er begge ret bredt supporteret under disse navne.
ASP classic demo:
<%
if IsEmpty(Session("V")) then
Session("V") = 1
Else
Session("V") = Session("V") + 1
End If
if IsEmpty(Application("V")) then
Application("V") = 1
Else
Application("V") = Application("V") + 1
End If
%>
Session = <%=Session("V")%>
<br>
Application = <%=Application("V")%>
ASP.NET demo:
<%@ Page Language="C#" Inherits="Test.Test" %>
Session = <asp:label id="sessionV" runat="server"/>
<br>
Application = <asp:label id="applicationV" runat="server"/>
og code behind:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Test
{
public partial class Test : Page
{
protected Label sessionV;
protected Label applicationV;
public void Page_Load(Object src, EventArgs e)
{
if(Session["V"] == null)
{
Session["V"] = 1;
}
else
{
Session["V"] = (int)Session["V"] + 1;
}
if(Application["V"] == null)
{
Application["V"] = 1;
}
else
{
Application["V"] = (int)Application["V"] + 1;
}
sessionV.Text = Session["V"].ToString();
applicationV.Text = Application["V"].ToString();
}
}
}
JSP demo (både uden og med EL):
<%
if(session.getAttribute("V") == null) {
session.setAttribute("V", 1);
} else {
session.setAttribute("V", (Integer)session.getAttribute("V") + 1);
}
if(application.getAttribute("V") == null) {
application.setAttribute("V", 1);
} else {
application.setAttribute("V",
(Integer)application.getAttribute("V") + 1);
}
%>
Session = <%=session.getAttribute("V")%>
<br>
Application = <%=application.getAttribute("V")%>
<br>
Session = ${sessionScope['V']}
<br>
Application = ${applicationScope['V']}
JSF facelet demo:
<html xmlns="
http://www.w3.org/1999/xhtml"
xmlns:h="
http://java.sun.com/jsf/html"
xmlns:f="
http://java.sun.com/jsf/core">
<h:head>
<f:event type="preRenderView" listener="#{testBean.check}"/>
</h:head>
<h:body>
<f:view>
Session: <h:outputText value="#{sessionScope['V']}"/>
<br/>
Application: <h:outputText value="#{applicationScope['V']}"/>
</f:view>
</h:body>
</html>
og backing bean:
package test;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
@ManagedBean
@RequestScoped
public class TestBean {
public void check(ComponentSystemEvent event){
Map<String, Object> session =
FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
if(!session.containsKey("V")) {
session.put("V", 1);
} else {
session.put("V", (Integer)session.get("V") + 1);
}
Map<String, Object> application =
FacesContext.getCurrentInstance().getExternalContext().getApplicationMap();
if(!application.containsKey("V")) {
application.put("V", 1);
} else {
application.put("V", (Integer)application.get("V") + 1);
}
}
}
Disse eksempler er faktisk ret ens i måden de håndterer session og
application på.
PHP er lidt anderledes. IIS/
ASP.NET og servlet container er begge
processer hvor det er nemt at implmentere noget fælles hukommelse.
PHP har flere forskellige execution modeller. De fleste af disse
(bl.a. CGI, FastCGI, mod_php med prefork, worker og event) har
flere procsser kørende. Kun få af dem (ISAPI og mod_php med winnt)
er enkelt process.
Som alle ved så understøtter PHP sessioner. Det gør de ved
at serialisere/deserialisere til/fra fil (som default - det
er muligt at hooke sin egen handler ind).
Så session er nemt:
<?php
session_start();
if(!isset($_SESSION['V'])) {
$_SESSION['V'] = 1;
} else {
$_SESSION['V'] = $_SESSION['V'] + 1;
}
?>
Session = <?php echo $_SESSION['V']; ?>
Men PHP har ikke et tilsvarende $_APPLICATION objekt.
Og en implementation af $_APPLICATION ligesom $_SESSION
(default) ville performe meget dårligt - det ville
de facto serialisere alle requests som brugte det.
Der er mindst 3 måder at arbejde sig omkring problemet på:
A) bruge serialisering og fil men minimere låsningstiden
på den fil - d.v.s. ikke fra request start til request
slut men fra brug start til brug slut og gerne
flere filer for forskellige formål
B) traditionel database (MySQL, PostgreSQL etc.)
C) en distribueret cache (memcached, Redis etc.)
Det er mit klare indtryk at de store PHP løsninger
foretrækker #C og jeg vil derfor formode at det er
en god løsning.
memcached var dominerende på området, men idag har
Redis taget over.
Implementereting med memcached:
<?php
session_start();
if(!isset($_SESSION['V'])) {
$_SESSION['V'] = 1;
} else {
$_SESSION['V'] = $_SESSION['V'] + 1;
}
$memcache = new Memcache();
$memcache->connect('localhost', 11211) or die ("Could not connect to
memcached");
if(!$memcache->get('V')) {
$memcache->set('V', 1);
} else {
$memcache->set('V', $memcache->get('V') + 1);
}
?>
Session = <?php echo $_SESSION['V']; ?>
<br>
Application = <?php echo $memcache->get('V'); ?>
<?php
$memcache->close();
?>
Implementering med Redis:
<?php
session_start();
if(!isset($_SESSION['V'])) {
$_SESSION['V'] = 1;
} else {
$_SESSION['V'] = $_SESSION['V'] + 1;
}
$redis = new Redis();
$redis->connect('localhost', 6379);
if(!$redis->get('V')) {
$redis->set('V', 1);
} else {
$redis->set('V', $redis->get('V') + 1);
}
?>
Session = <?php echo $_SESSION['V']; ?>
<br>
Application = <?php echo $redis->get('V'); ?>
<?php
$redis->close();
?>
Vigtig note: al koden ovenfor virker til at illustrere session og
application begreberne, men intet af koden er korrekte tællere
p.g.a. samtidighedsproblemer.
Men det er et generelt problem og ikke specielt for PHP
løsningerne.
Slut på skriv.
Arne