in dubio... extra class of niet?
In de extra server class (benaderbaar vanuit het request object) staat bijv. deze functie:
Code (php)
Stel dat ik de document root wil opvragen dan gaat dat ongeveer zo:
$document_root = $request->getServer()->getDocumentRoot();
(Het gaat er niet om of de bovenstaande opzet klopt, dus aub daar even niet op reageren.)
In de server class staan nog meer van dit soort functies om gegevens op te halen uit de $_SERVER array.
Wat ik ook zou kunnen doen is die hele exta server class weggooien, en rechtstreeks de data uit de $_SERVER parameter bag ophalen. Je krijgt dan dus zoiets:
$document_root = $request->getDataServer()->get('DOCUMENT_ROOT');
Zoals je ziet moet ik nu zelf de juiste key (in dit geval DOCUMENT_ROOT) invoeren. Nu is dat bij DOCUMENT_ROOT niet zo heel moeilijk, maar als ik bijv. wil weten welke talen de browser ondersteunt dan is de key "HTTP_ACCEPT_LANGUAGE". Dat kan ik niet onthouden, en zal ik dus moeten opzoeken, terwijl ik nu gewoon zoiets kan doen: $languages = $request->getServer()->getLanguages();
Om een lang verhaal kort te maken... ik maak het mezelf dus een stuk makkelijker met die extra class, maar is dat eigenlijk wel de juiste manier? Of zeggen jullie dat ik het zo moet doen: $languages = $request->getDataServer()->get('HTTP_ACCEPT_LANGUAGE');
Gewijzigd op 02/04/2013 23:19:07 door Ozzie PHP
Extra class? Je bedoelt extra method neem ik aan? Je zou kunnen kijken welke data je het meeste van $_SERVER gebruikt en daar een method van maken zoals bv 'REQUEST_METHOD', 'DOCUMENT_ROOT' etc. En voor de anderen die je zelden gebruikt kun je de get function gebruiken. Of begrijp ik je vraag nu verkeerd?
Het gaat echt om een aparte class met daarin een aantal methods inderdaad. En zoals jij zelf al aangeeft heb ik van de meest gebruikte een method gemaakt, zodat ik dus niet dit hoef te doen:
$reqest_method = $request->getDataServer()->get('REQUEST_METHOD');
maar dit...
$reqest_method = $request->getDataServer()->getRequestMethod();
Voor mij wordt het programmeren op deze manier wat makkelijker. Maar de vraag is dus of dit een goed idee is. Van de ene kant maak ik het mezelf makkelijker, want ik hoef niet na te denken hoe de key heet die ik wil ophalen, maar van de andere kant... het betekent ook een aantal extra methods. En nu vraag ik me dus af of het gebruikelijk is om het op deze manier te doen?
-- Offtopic --
Ik zie het wel vaker dat voor $_SERVER, $_SESSION aparte (parameterbags) classes worden gemaakt alleen kan iemand mij hier het nut van vertellen en hoe je dit moet te gebruiken? Want bv ik heb een 'formulieren' class, deze kijkt in een method of het formulier al verstuurd is door $_SERVER['REQUEST_METHOD'] te doen. Stel ik zou dit via de 'server' (parameterbag) class willen doen moet ik deze class eerst weer via de __construct toevoegen aan de formulieren class. Dit lijkt mij beetje onhandig dus wat is de achterliggende gedachte van zon 'server' (parameterbag) class?
Hertog Jan op 02/04/2013 23:48:34:
Ja maar OOP is ook bedoelt om het de programmeur makkelijker te maken, dus waarom dan niet die extra methods?
Nou ja, dat vroeg ik me dus af hè... is het wel "goed" OOP om te doen? En wellicht vertraagt het de boel ietsje die extra methods (alhoewel ik dat niet heb gebenchmarkt).
Hertog Jan op 02/04/2013 23:48:34:
-- Offtopic --
Ik zie het wel vaker dat voor $_SERVER, $_SESSION aparte (parameterbags) classes worden gemaakt alleen kan iemand mij hier het nut van vertellen en hoe je dit moet te gebruiken? Want bv ik heb een 'formulieren' class, deze kijkt in een method of het formulier al verstuurd is door $_SERVER['REQUEST_METHOD'] te doen. Stel ik zou dit via de 'server' (parameterbag) class willen doen moet ik deze class eerst weer via de __construct toevoegen aan de formulieren class. Dit lijkt mij beetje onhandig dus wat is de achterliggende gedachte van zon 'server' (parameterbag) class?
Ik zie het wel vaker dat voor $_SERVER, $_SESSION aparte (parameterbags) classes worden gemaakt alleen kan iemand mij hier het nut van vertellen en hoe je dit moet te gebruiken? Want bv ik heb een 'formulieren' class, deze kijkt in een method of het formulier al verstuurd is door $_SERVER['REQUEST_METHOD'] te doen. Stel ik zou dit via de 'server' (parameterbag) class willen doen moet ik deze class eerst weer via de __construct toevoegen aan de formulieren class. Dit lijkt mij beetje onhandig dus wat is de achterliggende gedachte van zon 'server' (parameterbag) class?
Ik heb een eigen parameter bag gemaakt. Ik heb een request class, en dan heb ik een parameter bag waarin ik bijvoorbeeld alle POST data stop... en bijv. ook eentje waarin ik de SERVER data stop. Als ik dan een POST waarde nodig heb, dan doe ik bijv. zoiets:
$foo = $request->getDataPost()->get('foo');
Dat request object is een service die aanwezig is in de service container. Het is de bedoeling dat ik straks de service container beschikbaar stel aan m'n controllers. Vanuit de controller kun je dan weer zoiets doen:
Code (php)
Is dit dan niet makkelijker?
Daarnaast denk ik dat je opbouw niet helemaal klopt. Jij controleert in isSubmitted() of je formulier is gepost, maar dat lijkt me de verkeerde plek. Jouw router moet op basis van de aangeroepen URL een bepaalde actie in een controller triggeren. Deze actie moet bepalen of de URL is aangeroepen via een POST request. Zo ja, dan pas wordt het formulier afgehandeld. Dat zou de juiste weg moeten zijn lijkt mij.
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
// Zo kan het ook:
if (Server::hasPost()) {
// Er is post: formulier verwerken...
}
?>
// Zo kan het ook:
if (Server::hasPost()) {
// Er is post: formulier verwerken...
}
?>
PHP kent (nog) geen read-only properties, maar juist voor omgevingsvariabelen zoals die in $_SERVER zijn dergelijke "voldongen feiten" voor een applicatie wel relevant. Als je het zo bekijkt, wordt een serverobject vooral een doorgeefluik waar je iets uit kunt halen maar niets in stopt:
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
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
<?php
class Server
{
/**
* @param void
* @return string|null
*/
public static function getRequestMethod()
{
if (isset($_SERVER['REQUEST_METHOD'])) {
if (is_string($_SERVER['REQUEST_METHOD'])) {
$request_method = trim($_SERVER['REQUEST_METHOD']);
$request_method = strtoupper($request_method);
if (!empty($request_method)) {
return $request_method;
} else {
return null;
}
} else {
return null;
}
} else {
return null;
}
}
/**
* @param void
* @return bool
*/
public static function hasPost()
{
if (self::getRequestMethod() !== 'POST') {
return false;
}
if (empty($_POST)) {
return false;
} else {
return true;
}
}
}
?>
class Server
{
/**
* @param void
* @return string|null
*/
public static function getRequestMethod()
{
if (isset($_SERVER['REQUEST_METHOD'])) {
if (is_string($_SERVER['REQUEST_METHOD'])) {
$request_method = trim($_SERVER['REQUEST_METHOD']);
$request_method = strtoupper($request_method);
if (!empty($request_method)) {
return $request_method;
} else {
return null;
}
} else {
return null;
}
} else {
return null;
}
}
/**
* @param void
* @return bool
*/
public static function hasPost()
{
if (self::getRequestMethod() !== 'POST') {
return false;
}
if (empty($_POST)) {
return false;
} else {
return true;
}
}
}
?>
Ozzie PHP op 02/04/2013 23:32:56:
Voor mij wordt het programmeren op deze manier wat makkelijker. Maar de vraag is dus of dit een goed idee is. Van de ene kant maak ik het mezelf makkelijker, want ik hoef niet na te denken hoe de key heet die ik wil ophalen, maar van de andere kant... het betekent ook een aantal extra methods. En nu vraag ik me dus af of het gebruikelijk is om het op deze manier te doen?
Ga terug naar de basis van OOP. Wat is de reden om alles op te splitsen in verschillende classes? Is die reden hier van toepassing, dan is het nuttig om het te doen, zoniet, dan niet.
P.S.
Dit:
Code (php)
is hetzelfde als dit:
Code (php)
Maar het laatste is iets korter ;-)
Ozzie PHP op 03/04/2013 00:19:52:
Uiteindelijk is het natuurlijk je eigen keuze, maar in jouw laatste voorbeeld roep je zomaar rechtstreeks de $_SERVER array aan. Dat is niet zo heel mooi.
Daarnaast denk ik dat je opbouw niet helemaal klopt. Jij controleert in isSubmitted() of je formulier is gepost, maar dat lijkt me de verkeerde plek. Jouw router moet op basis van de aangeroepen URL een bepaalde actie in een controller triggeren. Deze actie moet bepalen of de URL is aangeroepen via een POST request. Zo ja, dan pas wordt het formulier afgehandeld. Dat zou de juiste weg moeten zijn lijkt mij.
Daarnaast denk ik dat je opbouw niet helemaal klopt. Jij controleert in isSubmitted() of je formulier is gepost, maar dat lijkt me de verkeerde plek. Jouw router moet op basis van de aangeroepen URL een bepaalde actie in een controller triggeren. Deze actie moet bepalen of de URL is aangeroepen via een POST request. Zo ja, dan pas wordt het formulier afgehandeld. Dat zou de juiste weg moeten zijn lijkt mij.
Ja dit was een voorbeeld. In de isSubmited word het formulier zeg maar afgehandeld, worden de elementen (velden) gevalideerd, worden de errors gezet en dat soort handelingen. Dit soort handelingen laat je toch niet door een andere class doen?
bv:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
En dan vervolgens zo:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$form = new Form();
if ($form->isSubmitted()) {
// Dit word pas uitgevoerd als het formulier is verzonden en alle velden zijn gevalideerd.
}
?>
$form = new Form();
if ($form->isSubmitted()) {
// Dit word pas uitgevoerd als het formulier is verzonden en alle velden zijn gevalideerd.
}
?>
Of kan dit beter/anders?
Gewijzigd op 03/04/2013 11:10:57 door Joakim Broden
In dit geval lijkt me dat de juiste oplossing. Maar stel je heb een gecompliceerd formulier wat je niet maakt met een form builder, een wizard of een formulier in een dialog(al kan je wel je form builder uitbreiden), dan is de klasse van ozzie wel weer bruikbaar.
Als ik de extra methods niet inlaadt dan duurt de verwerkingstijd tot het moment dat ik de requesst heb aangemaakt ongeveer 0,00350 secondes. Als ik de extra methods wel inlaadt dan duurt het ongeveer 0,00410 seconden. Het wordt er dus wel ietsje trager van. Maar wat is nu het meest gebruikelijk? Wat doen jullie?
Vis je de juiste waarde zelf op uit de $_SERVER array, of maak je daarvoor een functie (met een makkelijke naam) die de juiste waarde ophaalt? Wat is gebruikelijk?
Ward van der Put op 03/04/2013 08:33:15:
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
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
<?php
class Server
{
/**
* @param void
* @return string|null
*/
public static function getRequestMethod()
{
if (isset($_SERVER['REQUEST_METHOD'])) {
if (is_string($_SERVER['REQUEST_METHOD'])) {
$request_method = trim($_SERVER['REQUEST_METHOD']);
$request_method = strtoupper($request_method);
if (!empty($request_method)) {
return $request_method;
} else {
return null;
}
} else {
return null;
}
} else {
return null;
}
}
}
?>
class Server
{
/**
* @param void
* @return string|null
*/
public static function getRequestMethod()
{
if (isset($_SERVER['REQUEST_METHOD'])) {
if (is_string($_SERVER['REQUEST_METHOD'])) {
$request_method = trim($_SERVER['REQUEST_METHOD']);
$request_method = strtoupper($request_method);
if (!empty($request_method)) {
return $request_method;
} else {
return null;
}
} else {
return null;
}
} else {
return null;
}
}
}
?>
Waarom bouw je zoveel controles in? Iedere server geeft een request method af, waarom dan controleren of ie geset is, of het een string is, omzetten naar hoofdletters... is dat niet wat overdreven?
Code (php)
Gewijzigd op 03/04/2013 14:48:06 door Ozzie PHP
@Wouter, ik geef bijvoorbeeld in de constructor de configuration van het formulier op. Hier kun je bijvoorbeeld aangeven of het via POST of via GET gaat en aan de hand van dat word er gekeken of het formulier verstuurd is. En het valideren word bv ook weer gedaan via een aparte validatie class die ik ook mee geef in de de constructor. Maar is een 'request' class echt een toegevoegde waarde?
Nog een voorbeeld, ik heb een 'url' class. Deze stript de URL in de adresbalk op in delen. Dit doet hij bijvoorbeeld aan de hand van de 'HTTP_HOST' en 'SCRIPT_NAME'. Nu gaat dat nog zo:
Code (php)
1
2
3
4
5
2
3
4
5
<?php
public function setHost() {
$this->sHost = rtrim(strtolower($_SERVER['HTTP_HOST']), '/');
}
?>
public function setHost() {
$this->sHost = rtrim(strtolower($_SERVER['HTTP_HOST']), '/');
}
?>
Maar als ik gebruik ga maken van een 'request' class word het:
Code (php)
1
2
3
4
5
2
3
4
5
<?php
public function setHost() {
$this->sHost = rtrim(strtolower($this->oRequest->get('HTTP_HOST')), '/');
}
?>
public function setHost() {
$this->sHost = rtrim(strtolower($this->oRequest->get('HTTP_HOST')), '/');
}
?>
En moet ik ook eerst weer de 'request' class aan de constructor van mij 'url' class toevoegen, oftewel extra methods, extra controlles etc. Dus kan iemand mij misschien het nut vertellen van zon 'request' class zodat ik het licht begin te zien? :)
Gewijzigd op 03/04/2013 15:36:11 door Joakim Broden
Nog meer mensen die het wel (of juist niet) zouden doen? Jullie meningen zijn van harte welkom.
Code (php)
Dat heeft wel nadelen:
• Je bouwt iets dat er al is. Zonde van de tijd en zonde van de moeite om zoiets steeds te parsen en uit te voeren.
• Je introduceert een nieuw PHP-dialect. Dat kun je doen voor de duidelijkheid of voor het gemak, maar "beauty is in the eye of the beholder". Zo kan isReeelGetal() een mooie aanvulling zijn op is_double(), is_float() en is_real(): de een zal de schoonheid van een PHP/Math-NL geweldig vinden, dan ander ziet het als een hel.
• Je maakt implementaties afhankelijk van getRequestMethod() waar ze gewoon $_SERVER['REQUEST_METHOD'] hadden kunnen gebruiken. Dat is een lastige maar belangrijke: script is niet langer direct afhankelijk van de scripttaal zelf, maar van een specifieke interpretatie daarvan. (Dat is de achilleshiel van frameworks die door de makers van frameworks wordt genegeerd: de afhankelijkheid van het framework.)
• Je bouwt schijnzekerheid en onzekerheid in. Wie de API leest, denkt ten onrechte dat getRequestMethod() iets speciaals doet. Die methode is er niet voor niets, toch? Wie dieper in de code duikt, ziet dat getRequestMethod() eigenlijk niets doet en laat de methode misschien links liggen omdat $_SERVER['REQUEST_METHOD'] de oude en vertrouwde oplossing is.
Hertog Jan op 03/04/2013 15:19:31:
Maar als ik gebruik ga maken van een 'request' class word het:
En moet ik ook eerst weer de 'request' class aan de constructor van mij 'url' class toevoegen, oftewel extra methods, extra controlles etc. Dus kan iemand mij misschien het nut vertellen van zon 'request' class zodat ik het licht begin te zien? :)
Code (php)
1
2
3
4
5
2
3
4
5
<?php
public function setHost() {
$this->sHost = rtrim(strtolower($_SERVER['HTTP_HOST']), '/');
}
?>
public function setHost() {
$this->sHost = rtrim(strtolower($_SERVER['HTTP_HOST']), '/');
}
?>
Maar als ik gebruik ga maken van een 'request' class word het:
Code (php)
1
2
3
4
5
2
3
4
5
<?php
public function setHost() {
$this->sHost = rtrim(strtolower($this->oRequest->get('HTTP_HOST')), '/');
}
?>
public function setHost() {
$this->sHost = rtrim(strtolower($this->oRequest->get('HTTP_HOST')), '/');
}
?>
En moet ik ook eerst weer de 'request' class aan de constructor van mij 'url' class toevoegen, oftewel extra methods, extra controlles etc. Dus kan iemand mij misschien het nut vertellen van zon 'request' class zodat ik het licht begin te zien? :)
Die request class zou dan onderdeel worden van je service container en die geef je als service/argument mee aan de class waar je 'm nodig hebt. Je gaat die host dus niet setten, maar je doet zoiets:
$this->request->getServer()->getHost();
Het gaat er vooral om dat je niet zomaar "out of the blue" ergens informatie vandaan haalt. De server informatie hoort bij het request object, en haal je dus netjes uit je request object en niet uit een globale array.
Maar het is maar net hoe netjes/gestructureerd je wil werken. Je kan ook overal waar je POST data nodig hebt, zeggen:
$foo = $_POST['foo'];
Maar het is mooier als je de POST data echt uit je applicatie haalt en in dit geval uit het request object:
$foo = $request->getPostData()->get('foo');
In het eerste geval grijp je zomaar spontaan iets "uit de lucht" terwijl je in het laatste geval gestructureerd je applicatie aanspreekt: geef mij het request, geef me de POST data en geef me van de POST data de waarde die hoort bij de key 'foo'.
Hoop dat dit een beetje verhelderend werkt.