[PHP] Global function meegeven als var aan class object

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
Ik gebruik een eigen geschreven klasse om vanuit PHP data uit een MSSQL-databse te trekken en hier vervolgens tabellen van te bakken.

PHP: Voorbeeld aanroepen class DataSet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$userlist = new DataSet(array(
    "select"        => array(
        "ID"            => "ID",
        "Achternaam"    => "Surname",
        "Postcode"      => "Zipcode",
    ),
    "from"          => "dbo.Users",
    "where"         => "Group = 1",
    "order by"      => "Surname ASC",
    "pagination"    => true,
    "debug"         => false,
    "icon"          => true,
));
echo $userlist->outputTable();


Vervolgens komt daar een fancy HTML-table uitgerold; mijn class pakt in dit geval ID, Surname en Username uit de tabel Users en propt dit in een array. Vervolgens wordt de array geoutput en komen als column headers ID, Achternaam en Gebruikersnaam boven de tabel te staan. Soms wil ik echter een bewerking op de data doen en die geef ik dan in de query al mee.

PHP: Voorbeeld stringconcat SQL
1
2
3
4
5
6
7
8
9
$userlist = new DataSet(array(
    "select"        => array(
        "ID"                => "ID",
        "Volledige Naam"    => "(Surname + ', ' + Firstname) AS Fullname",
        "Postcode"          => "Zipcode",
    ),
...
));
echo $userlist->outputTable();


In dit laatste voorbeeld voeg ik dus Surname + Firstname samen als Fullname, so far so good. Nu loop ik echter tegen cases aan waarbij wat uitgebreidere bewerking op de outputdata wil doen en ik wil dat graag 'on the fly' door PHP laten doen. Maar hoe doe ik dit? Ik denk aan zoiets:

PHP: Edit de data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// functie maken om inputdata om te katten naar juiste outputdata
function searchCity($postcode){
    // Plaatsnaam ophalen op basis van postcode
    return $city;
}

$userlist = new DataSet(array(
    "select"        => array(
        "ID"                => "ID",
        "Volledige Naam"    => "(Surname + ', ' + Firstname) AS Fullname",
        "Plaatsnaam"        => "Zipcode",
    ),
...
));
// Aan class meegeven dat ik uit mijn data-array $row[n]['Plaatsnaam']
// (Plaatsnaam is dus gevuld met de postcode)
// in de functie searchCity wil stoppen en de output hiervan 
// weer in $row[n]['Plaatsnaam'] wil stoppen...
$userlist->editData("Plaatsnaam","searchCity");
echo $userlist->outputTable();


Nu is de grote vraag, hoe vang ik dit aan? Ik heb het getest door een simpele global function te schrijven en deze direct aan te roepen in de class, dat lukt maar ik zit nog met het probleem hoe ik de 'functionName' variabel kan meegeven om vervolgens in de class zelf de juiste functie uit te voeren. Ik ben het spoor even helemaal bijster want ik weet niet goed ik dit slim kan aanpakken en of ik dit überhaupt slim aanpak zo. :/ Kan iemand mij in de juiste richting sturen?

[ Voor 3% gewijzigd door Harrie_ op 24-10-2017 17:09 ]

Hoeder van het Noord-Meierijse dialect

Beste antwoord (via Harrie_ op 25-10-2017 10:36)


  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
Je kan in PHP helaas niet zo fraai een variabele functie meegeven als in Javascript. Ken je call_user_func ? Hiermee kan je deels (wellicht) wat je wil. Wat evt wel zou kunnen is een Class meegeven waar de functies inzitten, en dan via een string doorgeven welke functie je wilt uitvoeren op een veld, pseudo code:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class Operations {
   function operation1 ($record) {
      return doDomethingWithRecord;
   }
   function operation2 ($record) {
      return doDomethingWithRecord;
   }
}
$operator = new Operations;

$userlist = new DataSet(array(
    "select"        => array(
        "ID"                => "ID",
        "Volledige Naam"    => array( "(Surname + ', ' + Firstname) AS Fullname", "operation2"),
        "Plaatsnaam"        => "Zipcode",
    )
    ,$operator );

Koop of verkoop je webshop: ecquisition.com

Alle reacties


Acties:
  • Beste antwoord
  • +1 Henk 'm!

  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
Je kan in PHP helaas niet zo fraai een variabele functie meegeven als in Javascript. Ken je call_user_func ? Hiermee kan je deels (wellicht) wat je wil. Wat evt wel zou kunnen is een Class meegeven waar de functies inzitten, en dan via een string doorgeven welke functie je wilt uitvoeren op een veld, pseudo code:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class Operations {
   function operation1 ($record) {
      return doDomethingWithRecord;
   }
   function operation2 ($record) {
      return doDomethingWithRecord;
   }
}
$operator = new Operations;

$userlist = new DataSet(array(
    "select"        => array(
        "ID"                => "ID",
        "Volledige Naam"    => array( "(Surname + ', ' + Firstname) AS Fullname", "operation2"),
        "Plaatsnaam"        => "Zipcode",
    )
    ,$operator );

Koop of verkoop je webshop: ecquisition.com


Acties:
  • +2 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

mocean schreef op woensdag 25 oktober 2017 @ 07:44:
Je kan in PHP helaas niet zo fraai een variabele functie meegeven als in Javascript.
Jawel hoor, je kan gewoon een lambdafunctie meegeven als parameter:
PHP:
1
2
3
4
5
6
7
function test(callable $functie) {
  return $functie('aap');
}

var_dump(test(function($param) {
  return strlen($param);
}));

Dit zou gewoon int(3) moeten afdrukken.

Maar of dat in deze situatie een goed idee is, is een tweede. Die bewerking hoort achteraf te worden toegepast op de complete dataset, gewoon een normaal procedureel verloop lijkt me veel logischer.

'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.


Acties:
  • 0 Henk 'm!

  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
NMe schreef op woensdag 25 oktober 2017 @ 09:49:
[...]
Jawel hoor, je kan gewoon een lambdafunctie meegeven als parameter:
[...]
Oh nice, realiseerde ik me niet (stoffige PHP <5.4 ervaring).

Koop of verkoop je webshop: ecquisition.com


Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
@mocean @NMe bedankt voor de reacties. Ik heb dit topic niet als vraag gemarkeerd dus ik kan ook niet het 'beste antwoord' markeren fixed, maar jullie krijgen allebei van mij een plusje :>

call_user_func was uiteindelijk wel de oplossing. Kende deze functie al wel maar ik gebruik 'm nooit dus ik had het ook niet meer zo paraat op het netvlies. Ik geef nu aan mijn DataSet object een extra array 'functions' mee, en dit werkt perfect.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function fooBar($input){
    return str_replace($input,0,2); // random test
}

$userlist = new DataSet(array(
    "select"        => array(
        "ID"                => "ID",
        "Volledige Naam"    => "(Surname + ', ' + Firstname) AS Fullname",
        "Plaatsnaam"        => "Zipcode",
    ),
    "from"          => "dbo.Users",
    "where"         => "Group = 1",
    "order by"      => "Surname ASC",
    "pagination"    => true,
    "debug"         => false,
    "icon"          => true,
    "functions"     => array(
                            "Volledige Naam" => "fooBar",
                            "Plaatsnaam" => "fooBar",
                            ),
));

echo $userlist->outputTable();


Als ik alle data heb opgehaald en in een array heb zitten dan doe ik een laatste check of er een column in mijn data-array matcht met de function-array => in dat geval trek ik de data door de functie heen. Works like a charm!

Hoeder van het Noord-Meierijse dialect


Acties:
  • +1 Henk 'm!

  • orf
  • Registratie: Augustus 2005
  • Laatst online: 23:39

orf

Misschien een beetje offtopic...

Ik zie een framework of een Class als dit altijd als een API. Je moet makkelijk kunnen praten met de code en het moet eigenlijk zichzelf wijzen.

Naar mijn idee is deze enorme array als argument daarin lastig. Je IDE kan dit niet voor je type-hinten en je moet de parameters en array diepte uit je hoofd kennen, copy-pasten of in je IDE naar de functie defenitie springen om te kijken wat verwacht wordt.

Dat zou je anders op kunnen lossen door met objecten te werken in plaats van een array, of met chaining/fluent methods. Je kan misschien wat inspiratie opdoen bij Doctrine of Eloquent.

Acties:
  • +1 Henk 'm!

  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
orf schreef op woensdag 25 oktober 2017 @ 10:33:
Misschien een beetje offtopic...

Ik zie een framework of een Class als dit altijd als een API. Je moet makkelijk kunnen praten met de code en het moet eigenlijk zichzelf wijzen.

Naar mijn idee is deze enorme array als argument daarin lastig. Je IDE kan dit niet voor je type-hinten en je moet de parameters en array diepte uit je hoofd kennen, copy-pasten of in je IDE naar de functie defenitie springen om te kijken wat verwacht wordt.

Dat zou je anders op kunnen lossen door met objecten te werken in plaats van een array, of met chaining/fluent methods. Je kan misschien wat inspiratie opdoen bij Doctrine of Eloquent.
Ben het wel met je eens, daarnaast lijken de functies sterk op 'presentatie' wat elders moet gebeuren dat in de data-provider API.

Koop of verkoop je webshop: ecquisition.com


Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
@orf Ik heb lang lopen stoeien hoe ik dit efficiënt moet oplossen. Doel van dit hele gebeuren is om onze DBadmins zelf een query 'om te laten zetten' in een systeem bij de klant met daarbij zo min mogelijk 'programmeren', vandaar dat ik ook bewust heb gekozen voor een stukje herkenbaarheid van de array-keys zoals select, from en where.

@mocean Ik begrijp niet helemaal wat je bedoelt?

[ Voor 10% gewijzigd door Harrie_ op 25-10-2017 11:08 ]

Hoeder van het Noord-Meierijse dialect


Acties:
  • +1 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 16:12
Harrie_ schreef op woensdag 25 oktober 2017 @ 11:04:

@mocean Ik begrijp niet helemaal wat je bedoelt?
Je hebt nu een API die een class teruggeeft die ook weer je presentatielaag regelt, want de functie "outputTable" geeft een geformatteerde HTML-tabel terug. Dat is in ieder geval wat ik aanneem dat hij bedoelt.

[ Voor 38% gewijzigd door Merethil op 25-10-2017 11:11 ]


Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
@Merethil klopt. De class DataSet geeft nu in wezen terug wat de naam al zegt: een dataset. Wanneer ik vanuit dit object de functie outputTable() aanroep wordt er een HTML-table van gebakken. Het is inderdaad netter om van die outputTable() een aparte (extended?) class te maken...

Hoeder van het Noord-Meierijse dialect


Acties:
  • +1 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 16:12
Harrie_ schreef op woensdag 25 oktober 2017 @ 11:14:
@Merethil klopt. De class DataSet geeft nu in wezen terug wat de naam al zegt: een dataset. Wanneer ik vanuit dit object de functie outputTable() aanroep wordt er een HTML-table van gebakken. Het is inderdaad netter om van die outputTable() een aparte (extended?) class te maken...
Zelf zou ik een templating language gebruiken voor dat soort zaken, HTML genereren met het handje uit een functie is naar mijn mening niet de manier om het lekker onderhoudbaar te houden...

Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
Merethil schreef op woensdag 25 oktober 2017 @ 11:17:
Zelf zou ik een templating language gebruiken voor dat soort zaken, HTML genereren met het handje uit een functie is naar mijn mening niet de manier om het lekker onderhoudbaar te houden...
Je hebt een punt maar ergens moet je ook de grens trekken. Het geheel is onderdeel van een framework waarin layout (HTML, CSS) en PHP toplevel strict gescheiden zijn. Helemaal low-level in een endpage komt er dan een standaard table met een css-class uit. De opmaak van die table wordt dus vervolgens helemaal bepaald door een CSS-sheet. Voglens mij prima onderhoudbaar, ervanuitgaande dat in HTML6 de <table>,<th>,<tr>,<td>,<a>-elementen niet komen te vervallen...

Hoeder van het Noord-Meierijse dialect


Acties:
  • +1 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Harrie_ schreef op woensdag 25 oktober 2017 @ 11:31:
[...]


Je hebt een punt maar ergens moet je ook de grens trekken. Het geheel is onderdeel van een framework waarin layout (HTML, CSS) en PHP toplevel strict gescheiden zijn. Helemaal low-level in een endpage komt er dan een standaard table met een css-class uit. De opmaak van die table wordt dus vervolgens helemaal bepaald door een CSS-sheet. Voglens mij prima onderhoudbaar, ervanuitgaande dat in HTML6 de <table>,<th>,<tr>,<td>,<a>-elementen niet komen te vervallen...
Zo gescheiden is het niet als je er een query in opbouwt en een stuk HTML mee uitpoept. Je hebt daar model, view én controller in één class gepropt.

'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.


Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
NMe schreef op woensdag 25 oktober 2017 @ 11:35:
[...]

Zo gescheiden is het niet als je er een query in opbouwt en een stuk HTML mee uitpoept. Je hebt daar model, view én controller in één class gepropt.
Hoe zou ik dat dan beter aan kunnen pakken? Ik wil graag alles gescheiden houden maar ik loop hier een beetje op vast.

Ik heb nu een webapplicatie waarbij alles door index.php wordt afgehandeld. index.php required een aantal standaardpagina's t.b.v. autorisatie/sessions/etc en een aantal specifieke pagina's op basis van de request. Op het moment dat alle data compleet is wordt de layout opgebouwd op basis van HTML-bestanden die met default parameters gevuld zijn zoals {{username}} en {{pagetitle}}, etc. Vanzelfsprekend overschrijf ik die parameters met de juiste data/content. Als dat allemaal rond is wordt de specifieke pagina gerequired waar de user naar op zoek is, dus specifiek alles wat in m'n 'content-div' terecht komt. Bij deze laatste stap loop ik er tegenaan dat ik PHP en HTML niet meer strict gescheiden kan houden...

[ Voor 3% gewijzigd door Harrie_ op 25-10-2017 11:54 ]

Hoeder van het Noord-Meierijse dialect


Acties:
  • +1 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Harrie_ schreef op woensdag 25 oktober 2017 @ 11:52:
[...]

Hoe zou ik dat dan beter aan kunnen pakken? Ik wil graag alles gescheiden houden maar ik loop hier een beetje op vast.
Normaal gesproken heb je in een framework je data layer. Denk daarbij aan entities: als je een tabel voor auto's in je database hebt dan heb je een entity (class) Car. Je ORM (bijvoorbeeld Doctrine of Eloquent) heeft vervolgens spul als querybuilders aan boord waarmee je zo'n entiteit (of meerdere) kan ophalen en "hydraten." De normale structuur in wat grotere projecten voor Symfony is bijvoorbeeld dat je entities hebt met voor elke entity waarvoor dat zinnig is een eigen repository en eventueel een aantal managerclasses die de logica bevatten om de verschillende repositories aan elkaar te knopen. Vervolgens gebruik je in je controller alleen die managers of repositories (separation of concerns, je controller hoeft niets van je database te weten) en je controller roept weer je view (een template) aan.

Praktisch voorbeeld uit een project van mij van een paar maanden geleden, een website waarop FIFA-toernooien gespeeld kunnen worden. Ik heb daar dus onder andere tabellen genaamd Tournament, Round, Match en User. Dat betekent dat ik ook entity classes met dezelfde namen heb. Verder heb ik daarbinnen repositories: TournamentRepository, MatchRepository en UserRepository. Daarin staan alle queries (via querybuilders) voor die specifieke entities. Voor Round heb ik bijvoorbeeld geen eigen repository nodig omdat ik geen custom query nodig had voor die entity. Vervolgens heb ik wat betreft deze entiteiten slechts twee managers: de TournamentManager en de UserManager. Die twee managers combineren onder andere de informatie uit de repositories en hebben wat helperfuncties. In mijn controller kan ik vervolgens dingen roepen als $tournamentManager->getUpcomingMatches($tournament, $user) en dan krijg ik gewoon een array van Match-objecten terug. Die array kan ik vervolgens gebruiken in mijn template.

'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.


Acties:
  • 0 Henk 'm!

  • orf
  • Registratie: Augustus 2005
  • Laatst online: 23:39

orf

Ik vind de scheiding van MVC niet het belangrijkste hier. Een datatable is zo dynamisch dat een view automatisch heel dynamisch wordt. Je zou een json-array of object hieruit kunnen laten komen en dat in de frontend gebruiken om een datatable om te zetten. Waarschijnlijk kun je dan zelfs aansluiten op een bestaande datatable-visualisatie.

De scheiding tussen model en controller is natuurlijk wel goed te maken.

Ik zou de query en de formatting los trekken. Het opbouwen van de query kan dan fluent bijvoorbeeld zo:

PHP:
1
2
3
4
5
$quryBuilder->select('u')
    ->from('User u')
    ->where('u.id = :identifier')
    ->orderBy('u.name', 'ASC')
    ->setParameter('identifier', 100);


Dan heb je typeHinting, autocompletion op je method namen, de mogelijkheid om meerdere keren een where toe te voegen, etc.

De output hiervan kan prima een database resultset zijn, die je weer in een object stopt om de presentatie te bouwen (json / html table). Ergens daar tussen kun je mutaties doen op je dataset.

Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
@NMe @orf Bedankt voor de pointers. d:)b

Het verhaal van NMe snijdt hout en kan ik goed relateren aan alles wat we hier hebben draaien in .NET, we maken daarbij o.a. gebruik van EntityFW. Ik vind het echter moelijk om die principes binnen PHP goed toe te passen, zeker zonder gebruik te maken van een bestaand framework en alles zelf from scratch te ontwikkelen. Misschien een minder handige keuze maar ik heb er wel veel plezier aan en heb het idee dat ik (conceptuele) problemen leer doorgronden die ik in een framework niet was tegengekomen (omdat het dan al voor je is opgelost).

Hoe dan ook, ik ga eerst het advies van orf volgen en de query, datamutatie en output helemaal uit elkaar trekken naar aparte classes.

Hoeder van het Noord-Meierijse dialect


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Harrie_ schreef op woensdag 25 oktober 2017 @ 12:33:
@NMe @orf Bedankt voor de pointers. d:)b

Het verhaal van NMe snijdt hout en kan ik goed relateren aan alles wat we hier hebben draaien in .NET, we maken daarbij o.a. gebruik van EntityFW. Ik vind het echter moelijk om die principes binnen PHP goed toe te passen, zeker zonder gebruik te maken van een bestaand framework en alles zelf from scratch te ontwikkelen. Misschien een minder handige keuze maar ik heb er wel veel plezier aan en heb het idee dat ik (conceptuele) problemen leer doorgronden die ik in een framework niet was tegengekomen (omdat het dan al voor je is opgelost).
Als je moeite hebt met dat soort dingen in PHP voostellen dan is het misschien geen slecht idee om een klein projectje in Symfony (en dus Doctrine) op te zetten zodat je kan zien hoe andere frameworks dit aanpakken. Laravel (en Eloquent) is ook een optie maar ik ben persoonlijk stukken minder gecharmeerd van dat framework en al zijn statics.

'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.


Acties:
  • +1 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Topicstarter
@NMe, thanks en gezien ik toch geen leven heb :') zal ik aankomend weekend eens e.e.a. inrichten en me gaan verdiepen in Symfony.

Hoeder van het Noord-Meierijse dialect


Acties:
  • 0 Henk 'm!

  • Mud
  • Registratie: Februari 2007
  • Laatst online: 07-10 15:47

Mud

Pagina: 1