Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

PHP $_SESSION = object

Pagina: 1
Acties:

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Hoi allen,

ja ik weet dat ik afwijk van de standaard PHP globals en dat een aantal mensen dit "not done" vinden, maar het is een leuke test, en ik hou van OOP en out of the box denken :)

Als je scripts schrijft doe je meestal standaard een sessions_start().
Echter heb je niet altijd de $_SESSION nodig in je scripts.
Maar meestal gebruik je een framework/portal (index.php) om alles af te handelen.

Met onderstaand script vervang ik $_SESSION met een object.
Je hoeft dan helemaal niet meer session_start() aan te roepen, dit gebeurt gewoon automatisch op het moment dat je een sessie variabele wil uitlezen.

De hack zit hem wel in het feit dat session_write_close() niet meer werkt.
$_SESSION->write_close(); moet dus aangeroepen worden voor het juist functioneren.

Zou het wat zijn om PHP.net in te lichten als feature request?

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
/**
 * Hack to make $_SESSION a dynamic object
 */

error_reporting(E_ALL);
ini_set('display_errors',1);

if (!defined('PHP_SESSION_DISABLED')) {
    // PHP < 5.4
    define('PHP_SESSION_DISABLED', 0);
    define('PHP_SESSION_NONE',     1);
    define('PHP_SESSION_ACTIVE',   2);
}

class Session extends \ArrayObject
{

    public function start()
    {
        if (PHP_SESSION_NONE == self::status() && session_start()) {
            $this->exchangeArray($_SESSION);
            $_SESSION = $this;
            // Use this or session is empty
            register_shutdown_function(function(){
                if (isset($_SESSION) && is_object($_SESSION)) {
                    $_SESSION->write_close();
                }
            });
        }
    }

    public function status()
    {
        if (function_exists('session_status')) {
            return session_status();
        }
        if ('cli' !== php_sapi_name()) {
            return session_id() ? PHP_SESSION_ACTIVE : PHP_SESSION_NONE;
        }
        return PHP_SESSION_DISABLED;
    }

    public function write_close()
    {
        if (PHP_SESSION_ACTIVE == self::status()) {
            $_SESSION = $this->getArrayCopy();
            session_write_close();
            $_SESSION = $this;
        }
    }

    # ArrayAccess
    public function offsetExists($key)
    {
        self::start();
        return parent::offsetExists($key);
    }

    public function offsetGet($key)
    {
        self::start();
        return parent::offsetGet($key);
    }

    public function offsetSet($key, $val)
    {
        self::start();
        parent::offsetSet($key, $val);
    }

    public function offsetUnset($key)
    {
        self::start();
        parent::offsetUnset($key);
    }
}

$_SESSION = new Session(isset($_SESSION) ? $_SESSION : array());
var_dump($_SESSION);
$_SESSION['foo'] = 'bar';

Maak je niet druk, dat doet de compressor maar


  • johnkeates
  • Registratie: Februari 2008
  • Laatst online: 04-07 16:30
Krijg je dan niet problemen met het starten van sessies? Of moeten we er dan ook van uit gaan dat eventuele content via een framework zo gestuurd wordt dat een sessie handler altijd eerst z'n cookies mag zetten voor dat er HTTP body gestuurd wordt.

Dat de sessie gestart moet worden voor dat je hem kan lezen is logisch, maar de sessie moet client-side ook bekend zijn, anders krijg je geen SID of PHPSESSID.

[ Voor 24% gewijzigd door johnkeates op 21-05-2014 14:24 ]


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Goed punt john.
Daarvoor had ik $_SESSION->start(); bedacht.
Als je die niet aanroept heb je inderdaad een cookie probleem.
Echter gebruikt een ieder hopelijk wel ob_start() en zou het niet zo'n probleem moeten zijn.

Je punt blijft natuurlijk wel valide.

De enige oplossing die ik zie, is dat de interne php code wordt aangepast dat de data alleen wordt opgehaald zodra je iets met een $_SESSION[key] doet, zeg: offset*()

Dit zou namelijk best wel eens wat verkeer kunnen schelen naar bestanden/db/mem handler en de eventuele locking.

Maak je niet druk, dat doet de compressor maar


  • simon
  • Registratie: Maart 2002
  • Laatst online: 21-11 14:05
Ik snap niet helemaal wat er mis is met session_start als je 'm niet nodig hebt? Zo groot is de performance impact niet toch?

|>


  • mbarie
  • Registratie: Mei 2011
  • Laatst online: 04-08-2021
simon schreef op woensdag 21 mei 2014 @ 14:52:
Ik snap niet helemaal wat er mis is met session_start als je 'm niet nodig hebt? Zo groot is de performance impact niet toch?
Het onnodig openhouden van een sessie maakt asynchrone requests blocking, en dus effectief synchroon. PHP kan het volgende verzoek pas serveren als een eerdere sessie van dezelfde gebruiker is afgesloten. Een sessie openen zonder dat dat nodig is kan zodoende ongewenst zijn, afhankelijk van de use-case.

[ Voor 27% gewijzigd door mbarie op 21-05-2014 15:18 ]

Storyteller @ soundcloud


  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 21-11 14:12
Als je flexibele/OOP sessions wil, kan je niet gewoon Symfony's session management gebruiken?
En ik weet niet wat je verder doet in je request, maar je loopt wel het risico dat je al output gestuurd hebt voordat je de session_start() aanroept toch?

  • storeman
  • Registratie: April 2004
  • Laatst online: 12:00
Wat is het voordeel van de global vernaggelen ten opzichte van gewoon gebruiken van een Singleton object? Meerdere frameworks doen dat zo.

Welke functie ik mis, is deze:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
     * Reopen the a session
     * 
     * The session should be started before
     */
    public static function restartQuietly ()
    {
        $newSettings = array(
            'session.use_only_cookies'=>false,
            'session.use_cookies'=>false,
            'session.use_trans_sid'=>false,
            'session.cache_limiter'=>null,
        );
        $originalSettings = array();
        foreach ($newSettings as $key => $newVal) {
            $originalSettings[$key] = ini_get($key);
            ini_set($key, $newVal);
        }
        
        parent::start();
        
        foreach ($originalSettings as $k => $v) {
            ini_set($k, $v);
        }
    }


Zoals arie zegt, is een sessie blocking. Soms wil ik toch meerdere keren naar een sessie schrijven omdat foutmeldingen in een sessie worden opgeslagen. Daarvoor gebruik ik bovenstaande functie. Als je session_start() namelijk normaal meerdere keren aanroept, verandert je sessionid.

Edit:

En zou je de magic function __destruct ook niet implementeren zodat je de sessie data goed wegschrijft ook al heb je hem niet netjes afgesloten?

[ Voor 6% gewijzigd door storeman op 21-05-2014 15:42 ]

"Chaos kan niet uit de hand lopen"


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
storeman schreef op woensdag 21 mei 2014 @ 15:23:
Wat is het voordeel van de global vernaggelen ten opzichte van gewoon gebruiken van een Singleton object? Meerdere frameworks doen dat zo.
Ik zie overal PHP "programmeurs" en ze denken allemaal dat ze kunnen programmeren.
Frameworks zijn en blijven een hobbel, het is immers iets dat je extra moet leren.
Hoe meer frameworks hoe meer je moet leren.
En, als je al weet dat PHP werkt met $_SESSION is een foutje zo gemaakt om een framework functie/object niet te gebruiken.

Frameworks zijn er omdat men functionaliteit mist in PHP zelf, en daar gaat het dus fundamenteel mis.

Ik vind het daarom leuker om te kijken of we PHP in het hart kunnen aanpakken zonder de standaard functionaliteit te dwarsbomen.
Voordeel is namelijk dat men niets extra's hoeft te leren.

Ik heb het geintje al uitgehaald met $_FILES, $_GET en $_POST en dat werkt prima.
Je kan dan namelijk iets doen zoals:
$_GET['id'] = object met een __toString().
$_GET['id']->asInt(); stuurt het nummer terug of NULL

Het zijn allemaal test opstellingen, maar het lijkt PHP een stuk beter OOP te maken.

Maak je niet druk, dat doet de compressor maar


  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 21-11 14:12
Maar nou maak je het voor nieuwe gebruikers toch nog veel verwarrender? Want dan heeft een $_GET ineens allemaal methodes, die hij normaal nooit zou hebben. Lijkt mij nogal vreemd als ik zo'n project in handen krijg. Net als $_SESSION die ineens nèt iets anders gedraagd als een normale session.

En wat als andere scripts/modules/libraries ook gebruik maken van $_GET of $_SESSION en je bent net een edge-case vergeten?
En het is nu toch niet OOP? Je hebt gewoon een global met wat meer functies. Het idee van OOP is toch dat je het kan loskoppelen van elkaar en los kan testen etc. en dat is niet zo door gewoon je superglobals te gebruiken.

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 20-11 11:59

NMe

Quia Ego Sic Dico.

DJMaze schreef op woensdag 21 mei 2014 @ 17:28:
[...]

Ik zie overal PHP "programmeurs" en ze denken allemaal dat ze kunnen programmeren.
Frameworks zijn en blijven een hobbel, het is immers iets dat je extra moet leren.
Hoe meer frameworks hoe meer je moet leren.
En, als je al weet dat PHP werkt met $_SESSION is een foutje zo gemaakt om een framework functie/object niet te gebruiken.
Ik zie vooral non-argumenten. Voorkomen dat je per ongeluk $_SESSION gebruikt doe je natuurlijk gewoon door de variabele te legen in je framework.

De superglobal misbruiken om je eigen sessiemodel te gebruiken is gewoon niet handig. Gebruik dan netjes een session-class die je via een framework apart beschikbaar maakt. Niet eens een singleton zoals hierboven geroepen wordt trouwens, want het is best denkbaar dat je iemand wil impersonaten en daarvoor zou je best eens zijn session willen kunnen overnemen.

Met jouw manier lijk je op het eerste gezicht te pretenderen dat je gewoon de sessions gebruikt zoals ze standaard in PHP zitten, maar ineens zit je er methods op aan te roepen. Probeer dan de code nog maar eens te doorgronden als buitenstaander. Alleen al daarom zou ik nooit superglobals repurposen.
DJMaze schreef op woensdag 21 mei 2014 @ 17:28:
[...]

Ik heb het geintje al uitgehaald met $_FILES, $_GET en $_POST en dat werkt prima.
Je kan dan namelijk iets doen zoals:
$_GET['id'] = object met een __toString().
$_GET['id']->asInt(); stuurt het nummer terug of NULL

Het zijn allemaal test opstellingen, maar het lijkt PHP een stuk beter OOP te maken.
Nee, het gebruikt objecten. Dat is niet hetzelfde als "beter OOP" zijn. Objecten gebruiken om het objecten gebruiken is geen verbetering.

Een goed framework maakt de superglobals beschikbaar via een logische interface. Ons in-house ontwikkelde framework heeft een MVC-model waarin je vanuit controllers gewoon $this->getRequest() kan roepen. Daar zit vervolgens het bekende spul in: $this->getRequest()->getPostParameter('bla') returnt wat normaal in $_POST['bla'] zou staan, of null als die parameter niet bestaat. Als optionele tweede parameter kun je een andere default dan null opgeven. Maar daarnaast heeft onze Request-class dus ook spul als getMethod(), getPath(), getQuerystring(), etc. Sessions zijn globaal beschikbaar via onze Application class die elke controller kent.

Je kan niet domweg de standaardfunctionaliteit van PHP in een object gooien en denken dat je dan goed bezig bent met OOP. PHP zit als framework helemaal niet goed in elkaar en daar op een betere manier mee omgaan vergt een design dat wél geschikt is voor moderne websites.

[ Voor 38% gewijzigd door NMe op 21-05-2014 18:13 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
NMe schreef op woensdag 21 mei 2014 @ 18:06:
Een goed framework maakt de superglobals beschikbaar via een logische interface. Ons in-house ontwikkelde framework heeft een MVC-model waarin je vanuit controllers gewoon $this->getRequest() kan roepen. Daar zit vervolgens het bekende spul in: $this->getRequest()->getPostParameter('bla') returnt wat normaal in $_POST['bla'] zou staan, of null als die parameter niet bestaat. Als optionele tweede parameter kun je een andere default dan null opgeven. Maar daarnaast heeft onze Request-class dus ook spul als getMethod(), getPath(), getQuerystring(), etc. Sessions zijn globaal beschikbaar via onze Application class die elke controller kent.
Doe je dan ook: getPostParameter('bla[sub]') ?
En hoe handel je verschillende types af, schrijf je in elk bestand if (is_numeric()....) etc. ?

Maak je niet druk, dat doet de compressor maar


  • kokx
  • Registratie: Augustus 2006
  • Laatst online: 18-11 12:58

kokx

WIN

DJMaze schreef op woensdag 21 mei 2014 @ 18:28:
[...]


Doe je dan ook: getPostParameter('bla[sub]') ?
En hoe handel je verschillende types af, schrijf je in elk bestand if (is_numeric()....) etc. ?
Het zou eerder logisch zijn als getPostParameter('bla') gewoon een array terug geeft.

Maar met het op deze wijze veranderen van de globals ga je alleen maar het jezelf moeilijker maken. Veel PHP frameworks benaderen daarom juist sessies via een wrapper. Deze wrapper zal dan dus session_start() aanroepen op het moment dat het nodig is. Dat lijkt me ook voor jou een beter idee dan het aanpassen van $_SESSION, wat alleen maar verwarring oplevert.

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 20-11 11:59

NMe

Quia Ego Sic Dico.

DJMaze schreef op woensdag 21 mei 2014 @ 18:28:
[...]

Doe je dan ook: getPostParameter('bla[sub]') ?
Nee, $this->getPostParameter('bla')['sub'] als je het in dat soort context wil gebruiken. Al heb je voor dat soort dingen 99 van de 100 keer gewoon numerieke indices en gebruik je het dus bijvoorbeeld zo:
PHP:
1
2
foreach ($this->getPostParameter('items', []) as $item)
    // doe spul met $item

...in plaats van zo:
PHP:
1
2
3
4
5
if (array_key_exists('items', $_POST) && is_array($_POST['items']))
{
    foreach ($_POST['items'] as $item)
    // doe spul met $item
}
En hoe handel je verschillende types af, schrijf je in elk bestand if (is_numeric()....) etc. ?
Postparameters zijn per definitie strings, dat is hoe het protocol werkt. Omdat PHP dynamically weak typed is maakt het vrijwel nooit uit of iets nou een int of een string is. Wat wel uitmaakt is of de waarde in die string in een toegestaan domein valt. Dat zou je inderdaad met ctype_int() of is_numeric() en consorten kunnen checken, maar je kan ook denken aan onze String::validateEmail($string)-method. Jouw asInt zou je ook kunnen wegstoppen in een String::asInt, of je gebruikt in dit geval gewoon de native aanwezige checks.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • MueR
  • Registratie: Januari 2004
  • Laatst online: 12:49

MueR

Admin Devschuur® & Discord

is niet lief

Daarbij is asInt() een ontiegelijke rukmethode, want dat maakt er gewoon altijd een int van. Als ik een int verwacht en een string "aap" krijg, wil ik daar gewoon een foutmelding op gooien, niet zomaar 0 in mn database gooien.

Anyone who gets in between me and my morning coffee should be insecure.


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 20-11 11:59

NMe

Quia Ego Sic Dico.

MueR schreef op woensdag 21 mei 2014 @ 20:10:
Daarbij is asInt() een ontiegelijke rukmethode, want dat maakt er gewoon altijd een int van. Als ik een int verwacht en een string "aap" krijg, wil ik daar gewoon een foutmelding op gooien, niet zomaar 0 in mn database gooien.
Daar heeft 'ie aan gedacht:
DJMaze schreef op woensdag 21 mei 2014 @ 17:28:
[...]

$_GET['id']->asInt(); stuurt het nummer terug of NULL
Maar dat maakt het nog niet per se een goed idee.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • storeman
  • Registratie: April 2004
  • Laatst online: 12:00
Wat ik zo uit zijn verhaal opmaak, is dat DjMaze meer experimenteel bezig is en wil kijken of hij wat kan bijdragen aan PHP. In dat licht is het natuurlijk geen gek idee. Deze code implementeren op applicatie/frameworkniveau is inderdaad een slecht idee en zeer verwarrend. Desondanks probeert hij het zo te maken dat het backwards compatibel is, wat een mooi streven is.

Als dit, laten we zeggen, in php6 zou komen, dan wordt het natuurlijk een heel ander verhaal en kan het best z'n toevoeging hebben.

Ik zie echter de toegevoegde waarde niet. De superglobal is gewoon data, en niets meer. Natuurlijk kun je er een object van maken, maar is dat handig? Iedereen zal toch eigen functionaliteit willen kunnen toevoegen en dan kom je toch weer uit op een eigen class/object. PHP is niet prototyped helaas :-P, anders kon je er zo een extra methode aan toevoegen. Als je het dan helemaal goed moet doen, zou je dus ook een sessionclass moeten kunnen instellen in je php.ini of voordat je sessie uberhaupt gestart is.

"Chaos kan niet uit de hand lopen"


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 20-11 11:59

NMe

Quia Ego Sic Dico.

storeman schreef op vrijdag 23 mei 2014 @ 11:18:
Als dit, laten we zeggen, in php6 zou komen, dan wordt het natuurlijk een heel ander verhaal en kan het best z'n toevoeging hebben.
Als PHP breekt met zijn huidige superglobal-model in een nieuwe versie dan zouden ze ronduit achterlijk zijn als ze het niet meteen goed doen. Domweg de oude functionaliteit breken om vervolgens de huidige structuur in een nét iets andere vorm in stand te houden heeft zowel het nadeel van het breken van alle bestaande code én het nadeel dat er nog steeds een maffe structuur gebruikt wordt. Ik zie geen voordeel aan het OO gebruiken om het OO gebruiken. ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Dat gaat toch niet gebeuren, diverse core developers vinden oa dit hoekje een taak voor frameworks. En een beetje framework heeft dan ook een mooi output laagje en session model. Uiteraard leerzaam, maar dikke kans dat als ts door bouwt er iets uit rolt wat lijkt op hoe een bepaald bestaand framework het opgelost heeft. :P

{signature}

Pagina: 1