request class
Pagina: « vorige 1 2 3 4 5 volgende »
Precies... maar het includen van een bestand is dan toch geen request?
Als je een HTTP-request bedoeld (dus aantal bestanden downloaden voor bekijken website): nee.
Als je het als interne PHP-aanroep ziet wel.
Ozzie, het is niet het includen van een bestand het is het aanroepen van een compleet nieuwe controller...
Ja, snap ik... maar in jouw voorbeeld heeft dat toch geen toegevoegde waarde (omdat de action in dezelfde class staat)?
Ik bedoel met een request een http-request, ofwel een pagina-aanroep. Jij verstaat onder een request ook een interne (controller/method) aanroep. Daar zit 'm het verschil. Een request zoals ik het bedoel, daarvan kun je er maar een per pagina-aanroep hebben.
Om meteen weer een ander onderwerp erin te gooien: Je moet nooit super globals gebruiken in je klasse. Wat je nu hebt is dus naar mijn mening fout. Gebruik de server array bij het aanmaken van de request klasse, niet in de request klasse.
Om het aanmaken van een request object dan wat te versimpelen zou je een factory kunnen maken, zie bijv. de symfony request klasse en zijn Request::createFromGlobals method.
Zou het dan bijv. beter zijn als ik in de construct van de request class zou zetten:
$this->server = $_SERVER;
en vervolgens overal die $this->server gebruiken?
Ik wil het allemaal ook niet te moeilijk maken, en vooral zo effectief mogelijk programmeren. Anders ben ik over 2 jaar nog bezig. Het gaat er mij vooral om dat de code logisch in elkaar zit en er geen "gevaar" in de code schuilt waardoor ik gehackt zou kunnen worden. Dat vind ik het meest belangrijk. De code moet voor mij vooral goed zijn, maar hoeft niet per se "mooi" te zijn. Vergelijk het met een auto. Je hebt hele mooie dure auto's die er supergelikt uitzien en waarbij ieder detail op de juiste plek zit. Zo hoeft mijn framework niet te zijn. Ik heb liever een goede middenklasser die me veilig van A naar B brengt. Mja, rare vergelijking, maar ik hoop dat je begrijpt wat ik bedoel.
Ozzie, omdat je dan als klasse dingen gaat gebruiken uit de buitenwereld, dat is ten strengste verboden. Iets in de constructor zetten is alsnog de server super global gebruiken. De basis is:
Code (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
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
<?php
class
class Request
{
/**
* @var array (of ParameterBag als je dat gebruikt)
*/
private $server;
/**
* @param array $server The server details
*/
public function __construct($server, ...)
{
$this->setServer($server);
}
/**
* @return array // wordt dan ParameterBag als je dat gebruikt
*/
public function getServer()
{
return $this->server;
}
private function setServer(array $server)
{
$this->server = $server; // eventueel een ParameterBag maken
}
}
$request = new Request($_SERVER, ...);
// of, om het makkelijker te maken en niet telkens elke superglobal te moeten inserten
$request = Request::createFromGlobals();
class Request
{
// ...
public static createFromGlobals()
{
return new static($_SERVER);
}
}
?>
class
class Request
{
/**
* @var array (of ParameterBag als je dat gebruikt)
*/
private $server;
/**
* @param array $server The server details
*/
public function __construct($server, ...)
{
$this->setServer($server);
}
/**
* @return array // wordt dan ParameterBag als je dat gebruikt
*/
public function getServer()
{
return $this->server;
}
private function setServer(array $server)
{
$this->server = $server; // eventueel een ParameterBag maken
}
}
$request = new Request($_SERVER, ...);
// of, om het makkelijker te maken en niet telkens elke superglobal te moeten inserten
$request = Request::createFromGlobals();
class Request
{
// ...
public static createFromGlobals()
{
return new static($_SERVER);
}
}
?>
$request = new Request($_SERVER, ...);
Ik snap alleen niet wat dit doet:
return new static($_SERVER);
??
Quote:
Ik snap alleen niet wat dit doet:
return new static($_SERVER);
return new static($_SERVER);
Die createFromGlobals method is een factory method, hij maakt het object aan en geeft hem terug. In dit geval maken we het object aan met de parameter $_SERVER, later krijg je nog meer parameters (alle $_* arrays).
Static verwijst naar de klasse waarin de static method leeft.
Ik zou dus op deze manier mijn request moeten ophalen...
$request = Request::createFromGlobals();
En in die functie staat dan bijvoorbeeld...
return new static($_SERVER, $_POST);
1) Wat zit er nu in de variabele $request?
2) Nu wil ik uit de server array de variabele HTTP_HOST hebben. Hoe doe ik dit dan?
Wat ik vooral niet snap is wat dit doet "return new static($_SERVER, $_POST)" en wat ik daar vervolgens mee moet doen.
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
return Return het geen hierachter staat
new maak een nieuw object aan
static static verwijst naar het object waar we inzitten, Request in dit
geval. Maak dus een nieuw request object aan
( het begin van de parameters
$_SERVER, eerste parameter is de $_SERVER super global
$_POST 2e parameter is de $_POST super global
) sluit de parameters
; sluit de regel
new maak een nieuw object aan
static static verwijst naar het object waar we inzitten, Request in dit
geval. Maak dus een nieuw request object aan
( het begin van de parameters
$_SERVER, eerste parameter is de $_SERVER super global
$_POST 2e parameter is de $_POST super global
) sluit de parameters
; sluit de regel
Quote:
1) Wat zit er nu in de variabele $request?
Hetgeen geretourneerd wordt door Request::createFromGlobals(), een nieuwe request object dus, opgemaakt uit de super globals.
Quote:
2) Nu wil ik uit de server array de variabele HTTP_HOST hebben. Hoe doe ik dit dan?
Code (php)
1
2
3
4
5
2
3
4
5
<?php
$request = Request::createFromGlobals();
echo ($request->getServer())['HTTP_HOST'];
?>
$request = Request::createFromGlobals();
echo ($request->getServer())['HTTP_HOST'];
?>
Of als je een ParameterBag gebruikt, wat ik mooier vind:
Oké.. weer een paar vragen...
1) Wat is nu precies het verschil van deze manier met "mijn" manier? En dan bedoel ik wat het verschil is met $_SERVER meegeven en $_SERVER rechtstreeks gebruiken. Is het op jouw manier zo dat de class property $server wel de inhoud van $_SERVER bevat, maar niet daadwerkelijk de $_SERVER array is? Je spreekt dus niet rechtstreeks de $_SERVER array aan? Klopt dit zoals ik het nu uitleg?
2) ($request->getServer())['HTTP_HOST'] Is dit PHP 5.4 schrijfwijze, waarbij je de key 'HTTP_HOST' ui de array opvraagt? Werkt het ook zonder haken, dus zo $request->getServer()['HTTP_HOST']. Ik zou het overigens dan liever zo doen: $request->getServer('HTTP_HOST'). Of gewoon $request->getHttpHost();
3) Dat ziet er mooi uit, maar hoe krijg je dat voor elkaar? ParameterBag zegt me (nog) niks.
Thanks alvast voor de antwoorden!
vraag 2...nee dat is een algemene schrijfwijze..en zonder die haakjes gaat waarschijnlijk niet, omdat hij eerst de variabele moet returnen en dan pas de value van die key uit lezen..
vraag 3. heel simpel...impv een array retourneer je een object waar de $_SERVER variabele ingestopt is die heeft dan getters en setters.
2) Dat is inderdaad de PHP5.4 schrijfwijze waarbij je meteen een key van de array kunt ophalen zonder hem eerst in een variabele op te slaan. Dit werkt niet zonder haken.
$request->getServer('HTTP_HOST') ziet er leuk uit, maar ik zou dan de methodnaam veranderen naar getServerParameter en dan ga je eigenlijk al teveel weten in de Request klasse over die server parameter. De laatste methode ($request->getHttpHost()) is natuurlijk helemaal niet goed omdat HttpHost helemaal geen eigenschap (property) van Request is.
3) Een ParameterBag is gewoon een klasse. Voorbeeldje:
Code (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
82
83
84
85
86
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
82
83
84
85
86
<?php
class ParameterBag extends \IteratorAggregate,
{
/**
* @var array
*/
private $parameters;
private $froozen = false;
/**
* @param array $parameters
*/
public function __construct($parameters = array())
{
$this->setParameters($parameters);
}
public function set($id, $value)
{
if ($this->isFroozen()) {
throw new \OverflowException('You cannot change a froozen parameterbag');
}
$this->parameters[$id] = $value;
}
public function get($id)
{
if (!$this->has($id)) {
throw new \OutOfBoundsException(sprintf('The parameter "%s" is not found', $id));
}
return $this->parameters[$id];
}
public function has($id)
{
return array_key_exists($id, $this->getParameters());
}
/**
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
public function freeze()
{
if ($this->isFroozen()) {
throw new \BadMethodCallException('The parameterbag is already froozen');
}
$this->froozen = true;
}
public function isFroozen()
{
return $this->froozen;
}
/**
* {@inheritDoc}
*/
public function getIterator()
{
return new \ArrayIterator($this->getParameters());
}
/**
* {@inheritDoc}
*/
public function count()
{
return count($this->getParameters());
}
private function setParameters(array $parameters)
{
$this->parameters = $parameters;
}
}
?>
class ParameterBag extends \IteratorAggregate,
{
/**
* @var array
*/
private $parameters;
private $froozen = false;
/**
* @param array $parameters
*/
public function __construct($parameters = array())
{
$this->setParameters($parameters);
}
public function set($id, $value)
{
if ($this->isFroozen()) {
throw new \OverflowException('You cannot change a froozen parameterbag');
}
$this->parameters[$id] = $value;
}
public function get($id)
{
if (!$this->has($id)) {
throw new \OutOfBoundsException(sprintf('The parameter "%s" is not found', $id));
}
return $this->parameters[$id];
}
public function has($id)
{
return array_key_exists($id, $this->getParameters());
}
/**
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
public function freeze()
{
if ($this->isFroozen()) {
throw new \BadMethodCallException('The parameterbag is already froozen');
}
$this->froozen = true;
}
public function isFroozen()
{
return $this->froozen;
}
/**
* {@inheritDoc}
*/
public function getIterator()
{
return new \ArrayIterator($this->getParameters());
}
/**
* {@inheritDoc}
*/
public function count()
{
return count($this->getParameters());
}
private function setParameters(array $parameters)
{
$this->parameters = $parameters;
}
}
?>
De request klasse ziet er dan zo uit:
Code (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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
In het gebruik:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$request = new Request::createFromGlobals();
echo $request->server->get('HTTP_HOST');
$request->server->set('HTTP_HOST', 'foo'); // exception: "You cannot change a froozen parameterbag"
?>
$request = new Request::createFromGlobals();
echo $request->server->get('HTTP_HOST');
$request->server->set('HTTP_HOST', 'foo'); // exception: "You cannot change a froozen parameterbag"
?>
Ik wil het een beetje simpel houden hè Wouter :)
Nou, weer een paar vragen dan maar...
1) Eerder schreef je dit "return new static($_SERVER);". Is dat exact hetzelfde als dit "return new Request($_SERVER);"
2) In mijn huidige request class heb ik een functie die mij bijvoorbeeld het subdomein teruggeeft: $request->getSubdomain();
Hoe zou je dat dan in jouw voorbeeld implementeren? Wel gewoon in de request class een functie getSubdomain maken, maar dan in die functie gewoon de http_host opvragen via via $this->server->get('HTTP_HOST')?
3) Ik zie in het voorbeeld wat jij geeft allerlei typen Exceptions staan. Waarom gebruik je niet gewoon 1 (algemeen) type?
4) Het voorbeeld van die ParameterBag (waarom heet het zo?) komt dat uit Symfony, of is het iets wat je zelf hebt gemaakt?
5) Dit wordt een leuke... probeer mij nou eens 100% te overtuigen waarom ik van de Request class geen Singleton ga maken (het argument van Unit testing moet je even achterwege laten). Hoe ik het zie... stel ik heb straks in mijn framework op meerdere plekken het request object nodig. De gegevens uit $_SERVER, $_POST etc. zullen tijden een request niet veranderen. Stel ik heb het request op 10 plekken nodig. Als het geen Singleton is, dan moet ik 10x een object aanmaken, parameters instellen enz. Als ik een Singleton gebruik, roep ik telkens hetzelfde object aan. Ik verbruik geen extra geheugen en behaal performance winst omdat niet telkens alle parameters opnieuw hoeven te worden geset. Mij lijkt het dus (in dit specifieke geval!!!) een hele hoop voordelen bieden.
1) Ja, maar new static is wat dynamischer zodat als je de Request klasse gaat extenden in bijv. een JsonRequest klasse hij `return new JsonRequest($_SERVER)` doet.
2) Nee, een subdomein is geen eigenschap van de request, maar eentje van de SERVER headers. Wat je kan doen is deze als key toevoegen in de SERVER array (die in je klasse staat, niet de $_SERVER array)
3) Je moet zo precies mogelijk zijn met exceptions. Sommige wil je direct opvangen, andere laat je opborrelen tot het einde en nog andere vang je halverwege op. Tevens helpt dit je debug message, je kan dan precies zien wat er fout is gegaan aan de exception klasse en ook waar ong. (door bijv. exceptions in namespaces te zetten)
4) Het idee van ParameterBag komt uit de Symfony HttpFoundation Component (het geen waar Request en zijn factory ook vandaan komen), het idee van het bevriezen van een Registery komt uit de Symfony DependencyInjection Component. De code zelf heb ik zojuist gemaakt
5) Correct, behalve 1 heeeele grote fout en dat is dat je niet met singletons moet gaan werken om een klasse in een andere klasse te krijgen. Je moet dan werken met Dependency Injection. Je maakt 1 keer de request klasse aan, slaat die ergens op en gebruikt die telkens weer. Als we eens de Pimple Container van Fabien erbij pakken wordt het:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$container = new Pimple();
$container['request.class'] = 'Request';
$container['request'] = $container->share(function ($c) {
return $c['request.class']::createFromGlobals();
});
$container['foo.class'] = 'FooClass';
$container['foo'] = function ($c) {
return new $c['foo.class']($c['request']); // voer het eerder aangemaakte Request object in
};
$container['bar.class'] = 'BarClass';
$container['bar'] = function ($c) {
return new $c['bar.class']($c['request']); // we maken hem niet nogmaals aan, maar gebruiken de eerder aangemaakte Request
};
?>
$container = new Pimple();
$container['request.class'] = 'Request';
$container['request'] = $container->share(function ($c) {
return $c['request.class']::createFromGlobals();
});
$container['foo.class'] = 'FooClass';
$container['foo'] = function ($c) {
return new $c['foo.class']($c['request']); // voer het eerder aangemaakte Request object in
};
$container['bar.class'] = 'BarClass';
$container['bar'] = function ($c) {
return new $c['bar.class']($c['request']); // we maken hem niet nogmaals aan, maar gebruiken de eerder aangemaakte Request
};
?>
Toevoeging op 04/01/2013 16:48:19:
P.s. Is het dan wel handig om de constructor in de request class private te maken, zodat je altijd "verplicht" bent om de createfromglobals functie te gebruiken?
Quote:
Is het dan wel handig om de constructor in de request class private te maken, zodat je altijd "verplicht" bent om de createfromglobals functie te gebruiken?
Nee, want ik wil helemaal niet altijd createFromGlobals gebruiken.
(Wanneer zou je NIET createfromglobals willen gebruiken? Is toch makkelijker dan alles handmatig meegeven?)
Ozzie PHP op 04/01/2013 18:04:18:
Maar wat als ik dat nu wel wil :)))
(Wanneer zou je NIET createfromglobals willen gebruiken? Is toch makkelijker dan alles handmatig meegeven?)
(Wanneer zou je NIET createfromglobals willen gebruiken? Is toch makkelijker dan alles handmatig meegeven?)
Bijvoorbeeld bij het testen. Als je een GET, POST, PUT, DELETE request wil testen, is het handig dat je een setRequestMethod functie hebt