[PHP] Static variabelen blijven niet bewaard

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • ruurdkrekt
  • Registratie: November 2003
  • Laatst online: 27-03-2023
Goedemiddag,

Ik ben gisteren begonnen met een website die ik aan het bouwen ben in de taal PHP. Nu heb ik al ervaring met betrekking tot statische functies, classes en variabele in andere talen zoals C# alleen kom ik er in PHP nu net even niet uit.

Ik zit het met volgende. Ik heb een class gemaakt genaamd config met hierin een statische functie parseIniFile() zoals hieronder weergegeven:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Class Config
{
  private $config;

  public static function parseIniFile()
  {
    $config = parse_ini_file("path/naar/ini/file", true);
  }

  public static function getDatabaseServer()
  {
    return $config['dbase']['server'];
  }
}


Nu roep ik deze code aan in mijn index op de volgende manier:
PHP:
1
2
  Config::parseIniFile();
  echo Config::getDatabaseServer();


Bij de eerste regel wordt inderdaad keurig het configuratie bestand ingelezen. Zet ik een echo in de statische functie die dus het bestand inleest dan werkt het prima. Maar als ik in mijn index de statische functie getDatabaseServer() aanroep, dan is plotseling de $config variabele leeg.

Is dit normaal in PHP?
Want ik heb in C# toch wel vaker zulke constructies gemaakt dat je bijvoorbeeld een statische database class hebt en die kun je (zolang het programma draait) oneindig vaak gebruiken nadat er een verbinding is gelegd.

Ter informatie:
Ik draai op PHP 5.3.0.

Acties:
  • 0 Henk 'm!

  • HenkEisDS
  • Registratie: Maart 2004
  • Laatst online: 01:11
Kijk eens of er uberhaupt wat in die var zit met print_r

Acties:
  • 0 Henk 'm!

  • hostname
  • Registratie: April 2009
  • Laatst online: 11:33
Om in PHP een class-variable dus ($config) aan te roepen moet je er $this-> (bij een instance) of self:: (als het een static variable is) voorzetten. Dan krijg je dus self::$config = parse_init_file(...) en return self::$config[...]. Nu zijn het gewoon 2 verschillende lokale variablen, welke worden weggegooid als de functie wordt verlaten.

En als je hem als static wilt gebruiken moet je bij de declaratie ook nog 'static' bij zetten. 'private static $config' dus.

Zie ook de php manual m.b.t. static.

[ Voor 22% gewijzigd door hostname op 18-07-2010 15:44 . Reden: linkje naar php manual ]


Acties:
  • 0 Henk 'm!

  • kluyze
  • Registratie: Augustus 2004
  • Niet online
Met ^^ die $config variabele bestaat alleen in de scope van je functie. In getDatabaseServer is $config een totaal andere variabele. Als je je errors wat stricter had ingesteld had hij volgens mij wel komen klagen dat $config niet bestaat of dat hij de index 'dbase' niet had gevonden en dus ook niet returned kan worden.

Acties:
  • 0 Henk 'm!

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Dat de functie static is, betekend niet dat de variabelen die je in die functiescope aanmaakt dat ook zijn.

Je dient een static variabele toe te voegen welke je gebruikt om je waarde in op te slaan. Die zal wel behouden blijven

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class Config
{
  protected static $config;

  public static function parseIniFile()
  {
    self::$config = parse_ini_file("path/naar/ini/file", true);
  }

  public static function getDatabaseServer()
  {
    return self::$config['dbase']['server'];
  }
}

  Config::parseIniFile();
  echo Config::getDatabaseServer();

Acties:
  • 0 Henk 'm!

Verwijderd

Statische variabelen van een klasse roep je aan als self::$config, anders krijgt de parser verwarring met klasseconstanten. :-)

Acties:
  • 0 Henk 'm!

  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 24-08 20:35
PHP heeft een uitgebreide manual. Waarin onder andere het static keyword in wordt besproken.

If I can't fix it, it ain't broken.


Acties:
  • 0 Henk 'm!

  • Lye
  • Registratie: Januari 2010
  • Laatst online: 16:10

Lye

frickY schreef op zondag 18 juli 2010 @ 16:00:
Dat de functie static is, betekend niet dat de variabelen die je in die functiescope aanmaakt dat ook zijn.

Je dient een static variabele toe te voegen welke je gebruikt om je waarde in op te slaan. Die zal wel behouden blijven

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class Config
{
  protected static $config;

  public static function parseIniFile()
  {
    self::config = parse_ini_file("path/naar/ini/file", true);
  }

  public static function getDatabaseServer()
  {
    return self::config['dbase']['server'];
  }
}

  Config::parseIniFile();
  echo Config::getDatabaseServer();
Dit gaat dus niet werken, self::config bestaat namelijk niet (dit zou een constante zijn), wat jij bedoelt is self::$config. Voor de rest is dit inderdaad de oplossing :)

EDIT: Zie dus net dat iemand me al voor was :(

Acties:
  • 0 Henk 'm!

  • ruurdkrekt
  • Registratie: November 2003
  • Laatst online: 27-03-2023
Erg bedankt voor de vele snelle reacties!
Ik was zelf al bezig geweest met this, maar dit mag natuurlijk niet in een statische omgeving. Nu zie ik dat het self moest zijn.
frickY schreef op zondag 18 juli 2010 @ 16:00:
Dat de functie static is, betekend niet dat de variabelen die je in die functiescope aanmaakt dat ook zijn.

Je dient een static variabele toe te voegen welke je gebruikt om je waarde in op te slaan. Die zal wel behouden blijven

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class Config
{
  protected static $config;

  public static function parseIniFile()
  {
    self::config = parse_ini_file("path/naar/ini/file", true);
  }

  public static function getDatabaseServer()
  {
    return self::config['dbase']['server'];
  }
}

  Config::parseIniFile();
  echo Config::getDatabaseServer();
Ik heb bovenstaande toegepast met de verbetering die werden genoemd door Hostname, Jexus en Lye en het werkt inderdaad precies zoals het zou moeten.

Bedankt voor de hulp. _/-\o_

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Om het topic eens te ontsporen met een OOP discussie: Moet je config uberhaupt wel static (en dus global) zijn? Kun je niet je configuratie in een object stoppen en dat doorgeven aan alleen de objecten die het echt nodig hebben? Is 'protected' wel de juiste keuze voor je static variabele? Heeft het opslaan van je databaseconfiguratie in een apart .ini file wel voordelen tegenover bijvoorbeeld constanten, danwel zit er een redenatie achter?

Ik zou nog toevoegen 'moet je parseIniFile wel apart aanroepen ipv gelijk het functieresultaat van parse_ini_file toekennen aan de variabele, maar heb het even opgezocht, en dat ken niet in PHP.

Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 09:34
YopY schreef op maandag 19 juli 2010 @ 09:11:
Om het topic eens te ontsporen met een OOP discussie: Moet je config uberhaupt wel static (en dus global) zijn?
Een configuratie is haast altijd statisch (alsin, verandert niet tussen objecten), deze static maken lijkt me dan een prima keuze?
Kun je niet je configuratie in een object stoppen en dat doorgeven aan alleen de objecten die het echt nodig hebben?
In PHP betekend dit al vrij snel dat je objecten gaat kopieeren (het default gedrag tenzij je er expliciet een reference van maakt bij elke call), en waarom zou je? Het is statische globale data (je DB login zal niet ineens veranderen bij een ander object), een heel config object doorgeven is dan niet nodig. Je zou wel als alternatief een singleton Config object kunnen gebruiken maar het effect is hetzelfde: je laadt 1 keer je config file in en daarna gebruik je altijd die data.
Is 'protected' wel de juiste keuze voor je static variabele? Heeft het opslaan van je databaseconfiguratie in een apart .ini file wel voordelen tegenover bijvoorbeeld constanten, danwel zit er een redenatie achter?
Ik zou'm zelf private maken, gok dat je niet snel een config class gaat lopen extenden, maar dat is een redelijk vrije keuze. PHP's magic set/get methods zijn erg nuttig hier om transparante toegang tot je configuratie-instellingen te geven (in plaats van dat je zelf in die array gaat lopen klieren). Aangaande je configuratie in een ini file gooien: het zorgt ervoor dat je makkelijk en snel de instellingen van je applicatie kan inzien en bewerken. Kwestie van smaak, maar het heeft mijn voorkeur boven alles in php files gooien.
Ik zou nog toevoegen 'moet je parseIniFile wel apart aanroepen ipv gelijk het functieresultaat van parse_ini_file toekennen aan de variabele, maar heb het even opgezocht, en dat ken niet in PHP.
De reden waarom ik liever voor een singleton ga in plaats van static methods, maakt het wat makkelijker om in je constructor de parseIniFile te gooien in plaats van bij elke get te controleren of je config wel geladen is. Extern je parseIniFile aanroepen vind ik dan weer wat minder netjes, zodra je dan op meer plekken config data nodig hebt moet je hard op gaan letten in welke volgorde die aangeroepen wordt, of je loopt continue overbodige calls naar parseIniFile te maken. Al is het, zeker bij kleinere projecten, een beheersbaar en niet noemenswaardig probleem.

[ Voor 18% gewijzigd door FragFrog op 19-07-2010 09:43 ]

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 12:59
FragFrog schreef op maandag 19 juli 2010 @ 09:36:
In PHP betekend dit al vrij snel dat je objecten gaat kopieeren (het default gedrag tenzij je er expliciet een reference van maakt bij elke call), en waarom zou je? Het is statische globale data (je DB login zal niet ineens veranderen bij een ander object), een heel config object doorgeven is dan niet nodig. Je zou wel als alternatief een singleton Config object kunnen gebruiken maar het effect is hetzelfde: je laadt 1 keer je config file in en daarna gebruik je altijd die data.
Dit is niet waar. Objecten worden sinds PHP5 altijd by reference doorgegeven. In PHP4 moest je hier nog het &teken voor het functie-argument zetten.

Probeer dit voor de gein:

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
<?php

class MyConfig{
    public $value;
}

function setValueToAbc( MyConfig $obj ){
    $obj->value = 'abc';
}

function setValueToDef( MyConfig $obj ){
    $obj->value = 'def';
}

$myObj = new MyConfig();

echo '<pre>';
var_dump( $myObj->value );

setValueToAbc( $myObj );
var_dump( $myObj->value );

setValueToDef( $myObj );
var_dump( $myObj->value );


output:
code:
1
2
3
NULL
string(3) "abc"
string(3) "def"


Ik gebruik hiervoor ook meestal statische functies. Dit is vooral omdat de config door het hele systeem wordt aangeroepen vanaf een centrale plaats, ik vind dit transparanter. Zeker in het MVC model vind ik dit handig. Configuratie-gegevens haal ik ook meestal als parameter uit de bootstrap.

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 09:34
storeman schreef op maandag 19 juli 2010 @ 09:47:
Dit is niet waar. Objecten worden sinds PHP5 altijd by reference doorgegeven. In PHP4 moest je hier nog het &teken voor het functie-argument zetten.
Mea culpa, je hebt gelijk - wist niet dat dit voor objecten veranderd is sinds PHP4 :)

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

  • DexterDee
  • Registratie: November 2004
  • Laatst online: 13:59

DexterDee

I doubt, therefore I might be

Een nuttige toevoeging op het gebruik van statics welke niet veel mensen weten:

In PHP bestaan ook static variabelen die géén class variabelen zijn. Ze zijn qua scope beperkt tot de method waarin ze aangemaakt zijn, maar overleven wél meerdere aanroepen.

Een voorbeeld:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Teller {
    public static function tel() {
        static $aantal = 0;
        $aantal++;
        return $aantal;
    }
}

echo Teller::tel();
// resultaat: 1

echo Teller::tel();
// resultaat: 2

echo Teller::tel();
echo Teller::tel();
echo Teller::tel();
// resultaat: 5


Dit design pattern kan onder andere nuttig zijn om bepaalde waarden te cachen.

Klik hier om mij een DM te sturen • 3245 WP op ZW


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 12:59
Handig!! Hier was ik niet van op de hoogte, maar erg praktisch voor caching inderdaad!

PHP:
1
2
3
4
5
6
7
8
9
class Teller {
    public static function tel() {
        if( isset($cache) ) return $cache;
        static $cache= null;
        // Ingewikkelde rotzooi
       $cache = $result;
       return $cache
    }
}


Zoiets moet dan werken?

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik zou de declaratie/initialisatie van de variabele wel voor het if statement zetten.

Het is in feite gewoon een normale static variabele, alleen dan met een kleinere scope.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Het probleem natuurlijk, met statische variabelen is dat testen ineens een heel stuk moeilijker wordt.

Voor snel debuggen is het soms wel handig (maximaal iteraties om een oneindige lus te testen &c.) maar verder is het praktische nut niet aanwezig.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

DexterDee schreef op dinsdag 20 juli 2010 @ 20:05:
Dit design pattern kan onder andere nuttig zijn om bepaalde waarden te cachen.
Geh, zijn local statics nu ook al een design pattern? :+

Pas trouwens op met references in statics (en globals trouwens). Een static variabele definitie binnen de functie definieert eigenlijk ruimte voor de variabele in de global table, en de local wijst daar vervolgens naar. Als je een reference van de variabele wijzigt dan laat je de local dus wijzen naar iets anders - het is niet zo dat je daarmee de waarde in de global table aanpast.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
class myobj { public $var; }

function foo($b)
{
    static $a = 0;
    if ($b)
        $a =& new myobj();
    return $a;
}

var_dump(foo(true));
var_dump(foo(false));

Dit returnt dus eerst een myobj, maar daarna gewoon weer 0. Dit maakt het in PHP4 dus onmogelijk om een static (of global) naar een object te laten wijzen zonder een kopie te maken.

Overigens zijn local statics vrij standaard in programmeertalen. Kan me niet voorstellen dat "niet veel mensen het weten".

[ Voor 67% gewijzigd door .oisyn op 21-07-2010 17:03 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • DexterDee
  • Registratie: November 2004
  • Laatst online: 13:59

DexterDee

I doubt, therefore I might be

.oisyn schreef op woensdag 21 juli 2010 @ 16:12:
[...]

Geh, zijn local statics nu ook al een design pattern? :+
Ik bedoelde het eigenlijk andersom, een design pattern voor een caching strategie zou gebruik kunnen maken van static variables
Overigens zijn local statics vrij standaard in programmeertalen. Kan me niet voorstellen dat "niet veel mensen het weten".
Niet veel mensen weten dit die (uitsluitend) PHP en een handjevol scripttalen kennen. Oneerbiedig gezegd 'de scripters'. Een beetje goede programmeur zou dit wel bekend moeten voorkomen. Helaas is de overlap nogal klein. Met jouw ervaring met 3GL talen en lager heb je wellicht een iets ander referentiekader ;)

Klik hier om mij een DM te sturen • 3245 WP op ZW

Pagina: 1